Henry's Notebook
Many strange things
搜索
菜单
导航
首页
最近更改
随机页面
帮助
Henry's Home
个人资料
个人资料
创建账户
登录
消息
目前您没有通知。请访问您的
讨论页
以查看过去消息。
页面工具
内容页面
讨论
查看源代码
历史
首页
»
页面s
查看“刷课机详解”的源代码
←
刷课机详解
页面上次由
HenryHu
编辑于13年前
因为以下原因,您没有权限编辑本页:
您所请求的操作仅限于该用户组的用户使用:emailconfirmed
您可以查看与复制此页面的源代码。
关于这个[[刷课机]]是如何工作的 == 代码 == <source lang="python"> #!/usr/local/bin/python # vim: set fileencoding=utf8 : # 下面的东西反正是各种引用,有的或许还不需要…… import urllib2 import urllib import cookielib import lxml.html import subprocess import getpass import time import random from lxml import etree # 各种变量声明…… hosturl = "http://zhjwxk.cic.tsinghua.edu.cn"; # 用户名密码,密码还是当场输入比较安全 username = ""; password = getpass.getpass("Password: "); loginfrm = "https://zhjwxk.cic.tsinghua.edu.cn:443/j_acegi_formlogin_xsxk.do"; # 这个是在OCR之前执行的语句…… ocrcmd_pre = "convert captcha.jpg captcha.bmp ; cuneiform captcha.bmp > /dev/null"; #gocr -a 80 -s 100 -C \"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ\""; # 这句用来获取OCR结果…… ocrcmd_res = "cat cuneiform-out.txt"; urllogin = hosturl + "/xsxk_index.jsp"; # 有这几句就有Cookie支持了…… 请求之前会保留Cookie信息 jar = cookielib.CookieJar() handler = urllib2.HTTPCookieProcessor(jar) opener = urllib2.build_opener(handler) urllib2.install_opener(opener) h=urllib2.HTTPHandler(debuglevel=1) opener = urllib2.build_opener(h) # 另一些变量,主要是刷哪个课…… coursemajor = "30240422" courseminor = "0" term = "2010-2011-1" coursetype = "xx" # rx searchtype = "xxSearch" # rxSearch type_id = "p_xxk_id" # p_rx_id savetype = "saveXxKc" # saveRxKc arg2 = "?m=" + searchtype + "&p_xnxq=" + term + "&tokenPriFlag=" + coursetype + "&p_kch=" + coursemajor success = False trytime = 0 # 好,开工 while not success: # 先登录 while True: # 抓登录页面 data = urllib2.urlopen(urllogin).read() # print data; # 抓登录验证码图片的路径 img = lxml.html.fromstring(data).get_element_by_id("captcha"); # 抓验证码图片 captcha = urllib2.urlopen(hosturl + img.get("src")).read(); # 把图片写到文件用来OCR imgfile = open("captcha.jpg", "w"); imgfile.write(captcha); imgfile.close(); # 运行OCR之前要跑的东西 subprocess.Popen(args=ocrcmd_pre, shell=True).wait(); # 跑OCR程序 ocrproc = subprocess.Popen(args=ocrcmd_res, stdout=subprocess.PIPE, shell=True); # 拿结果,根据一般规律换掉一些OCR搞错的 ocrret = ocrproc.stdout.read().replace(" ","").replace("\n","").replace("/","J").replace("1","J").replace("I","J").replace("S","8"); # 构造登录的参数,用户名/密码/验证码等 loginfrm_arg = urllib.urlencode({'j_username': username, 'j_password': password, 'captchaflag': "login1", '_login_image_': ocrret}) loginres = "" try: # 尝试登录! loginres = urllib2.urlopen(loginfrm, loginfrm_arg).read(); except: loginres = "" if loginres.find("<div align=\"center\"") == -1 : # 成功了!否则再试…… break print "Logged in!" # print urllib2.urlopen(hosturl + "/xkBks.vxkBksXkbBs.do?m=rxSearch&p_xnxq=2010-2011-1&tokenPriFlag=rx&p_kch=00430093").read() # 抓登录之后的界面的一部分 mainpage = lxml.html.fromstring(urllib2.urlopen(hosturl + "/xkBks.vxkBksXkbBs.do" + arg2).read()) selurl = hosturl + "/" + mainpage.forms[0].action while True: trytime = trytime + 1 print "Round ", trytime seldict = {} try: # 枚举每个输入部分,看看哪些要处理 for input in mainpage.forms[0].inputs: if input.name != None and input.value != None: if input.name != 'submit1' and input.name != 'bt': print input.name.encode("utf-8"),":", input.value.encode("utf-8") # 有些是要填的 if input.name == 'm': input.value = savetype if (input.name == None): continue # 有些可以空着 if (input.value == None and input.name != 'j_captcha_bks_xk'): seldict[input.name] = '' continue # 一般的input需要原样返回,比如一些hidden的 if (input.type != 'button') & (input.type != 'reset') : seldict[input.name] = input.value # 恩,这个是验证码…… if input.name == 'j_captcha_bks_xk': # 有这个说明页面上要你填验证码了 img = mainpage.get_element_by_id("captcha"); # 抓验证码存下来 captcha = urllib2.urlopen(hosturl + img.get("src")).read(); imgfile = open("captcha.jpg", "w"); imgfile.write(captcha); imgfile.close(); # 老办法识别验证码 subprocess.Popen(args=ocrcmd_pre, shell=True).wait(); ocrproc = subprocess.Popen(args=ocrcmd_res, stdout=subprocess.PIPE, shell=True); ocrret = ocrproc.stdout.read().replace(" ","").replace("\n","").replace("/","J").replace("1","J").replace("I","J").replace("S","8"); # 把验证码填进去 seldict[input.name] = ocrret print "Img Capt: ",ocrret except: break # 要选啥课 seldict[type_id] = term + ";"+ coursemajor + ";" + courseminor + ";" # 构造选课时提交的参数 selparam = urllib.urlencode(seldict) print selparam # 过会,不急 time.sleep(0.5+0.01*random.randint(0, 100)) # 选课! selres = urllib2.urlopen(selurl, selparam).read().decode('gbk') # 把结果存下来,主要是调试用,另可以观察结果页面 selpage = open("selpage" + str(trytime % 2) + ".htm", "w"); selpage.write(selres.encode("utf-8")); selpage.close(); # 搞定了? if selres.encode("utf-8").find("成功") != -1: success = True; break # 悲剧了,重新登陆吧,多半超时了 if selres.encode("utf-8").find("Forbidden") != -1: timeout = True; break; # 别的问题,多半是满了 mainpage = lxml.html.fromstring(selres) alertStart = selres.find('showMsg("') + 9; alertEnd = selres.find('");', alertStart); print "Result: ", selres[alertStart:alertEnd] # print selres.encode("utf-8") # 全部完成! print "FINISHED!" </source> == 主要用到的方法 == 其实还包括用到的成员变量 === 如何抓页面及提交请求 === * urllib2.urlopen(url) 非常好用的方法,用HTTP抓某个页面。这个样子会用HTTP GET抓。 对返回的东西调用read()就会返回整个页面,在一个字符串里,想干嘛都可以。 * urllib2.urlopen(url, param) 这个样子会用HTTP POST提交某个页面,一般点按钮之类都会提交某个form,这个时候用的多半都是HTTP POST方法。 所以比如登录啦、选课啦都是POST方法,而获取登录页面啦、获取选课页面啦都是GET。 * urllib.urlencode(dict) 给他一个dict,就能返回一个可以给上面那个方法用的param。 * 关于Cookie的那四行 反正就是给系统一个存Cookie的地方,并且让系统用它。这样各个请求的Cookie信息会保留,在下一个请求用。 === HTML页面的分析 === * lxml.html.fromstring(string) lxml是个很方便的分析XML/HTML的库,这个方法能够读一个string,返回一个html对象,里面是HTML文档处理之后得到的结构化的结果。然后在这个对象上就能干各种事情了。以下把其返回的叫html。 * html.get_element_by_id(id) 有了上面那个的结构化的结果,就能在里面找某个特定id的对象了。 * html.forms[] 包括了该页所有form的数组,一般你要找的form就在其中…… 以下把其成员称为form * form.inputs 某form的所有输入,一般我们只关心这个…… 以下把其成员称为input * input.value, input.name 某输入项的值与名字。你可以拿去用,在提交的时候还要交回去。一般提交的时候,参数里都有 名字=值 这样的好多对。 * string.decode(encoding), string.encode(encoding) 反正是用来转编码的,陌生的字符串最好decode一下,要find东西的时候最好encode一下 === 子进程相关 === * subprocess.Popen(args=cmd, shell=True) 开一个进程跑某物,要不要shell有时候不一样。以下把其返回的叫proc * proc.wait() 等某进程结束,这样才好拿它输出的东西。 * proc.stdout() 某进程的输出,用.read()可以全读到一个字符串里。
返回至
刷课机详解
。