高手请一笑而过。
物理实验课别人已经做过3、4个了,自己一个还没做呢。不是咱不想做,而是咱不想起那么早,并且仅有的一次起得早,但是哈工大的服务器竟然超负荷,不停刷新还是不行,不禁感慨这才是真正的“万马争过独木桥“啊!服务器不给力啊……
好了,废话少说。其实,我的想法很简单。写一个三重循环,不停地提交,直到所有的数据都accepted。其中最关键的是提交最后一个页面,因为提交用户名和密码后不需要再访问其他的页面,因此不需要用到cookis。
这个只是Python最简单的应用。核心代码只有两行:
data = urllib.urlencode(each_people) req = urllib2.Request(url , data)
这里用到了Python中Web编程中的比较重要的模块urllib和urllib2。其实你也可以用httplib来代替,两者本质上是一样的,因为urllib内部的一部分就是用httplib来实现的。
现解释一下上面的意思:each_people是一个字典,就相当于C++中的multimap、java中的hashMap,其含义是一个人的选课信息。urllib.urlencode()函数将each_people的格式转换一下,以便将其作为CGI请求的URL字符串的一部分。关于CGI是什么大家可以google一下。举个例子:
>>>import urllib
>>>each_people = {'name' : 'Tom' , 'password' : '12345' , 'class' : 'lab5'}
>>>data = urllib.urlencode(each_people)
>>>print data
结果是:name=Tom&password=12345&class=lab5
第二行看字面意思就知道其实什么意思了。参数url表示你要提交数据的网站。
那么怎么查看其返回结果呢?很简单:
response = urllib2.urlopen(req) the_page = response.read() print the_page
看到有几个人问,就把代码贴出来吧,有注释:
#coding=gb2312 import urllib import urllib2 import re #要提交数据的网站 url = 'http://……' #选课人的信息 info_list = [ {'week' : '9', 'expnumber' : '实验10' , 'weekday' : '2' , 'exp_class' : '3-4' , 'number' : '10000000' , 'password' : '12345678' } , {'week' : '9', 'expnumber' : '实验10' , 'weekday' : '2' , 'exp_class' : '3-4' , 'number' : '20000000' , 'password' : 'abcdefgh' } ] #对应的选课人的名字,可以不要,我加上这个的原因是做一个log,记住选课结果 name_list = [ '张三' , '李四'] #记录对应的是否已经选上,可以用一个 二进制数代替 trace = [ 0 , 0] #主程序,选课 def submit(): while True: whether_over = 1 for i , each_people in enumerate(info_list): if trace[i] == 0 : whether_over = 0 for j in range(20): data = urllib.urlencode(each_people) req = urllib2.Request(url , data) try: response = urllib2.urlopen(req) except urllib2.URLError , e: continue else : the_page = response.read() #下面这个路径可以更改,我用的是我的路径 #这三句是将返回的网页写到文件中,以方便以后检索 my_file = open('/home/superior/Documents/WLlog.txt' , 'w+') ; my_file.write(the_page) ; my_file.close() #将刚才的网页读到内存中 my_file = open('/home/superior/Documents/WLlog.txt' , 'r') ; buffer = my_file.read() my_file.close() #下面用了正则表达式模块中的search()方法 m = re.search('课程预约成功', buffer) #如果找到“课程预约成功”字符串了 if m is not None: result_file = open('/home/superior/Documents/result_log.txt' , 'a+') #将名字记录到result_log.txt中 result_file.write(name_list[i] + ' successful/n') result_file.close() #将此人从列表中划去 trace[i] = 1 break #所有人都选上了 if whether_over == 1: break #定义主函数 def main(): submit() #调用主函数 main()
我认为这个程序效率虽然还不错,但是我认为还可以再提升一下。主要是打开文件,读写文件,关闭文件这几个步骤耗时。但是goole摆弄了好久,没找到更好地办法。有谁找到更好地办法,请吱一声。
另外需要说明的是:
1.为了不失广泛性,info_list这个列表中的信息,是我举例用的。具体使用的话,只需将info_list和url修改一下
2.运行此程序需要预先装上Python,如何安装google一下就知道了
*************************************************************************************************************
今天(Oct 17)帮助15位同学选上了课,心里很高兴,娘的,“胜造七级浮屠”啊!
看了看log,每秒选上5个同学,感觉效率很低啊!于是又想了一下改进的办法。
第一点:
正如前面分析的那样,主要是打开、读取、关闭文件费时。我看了一下the_page和buffer的类型:相同!
print 'buffer' , type( buffer ) print 'the_page' , type( the_page )
结果:
buffer <type 'str'>
the_page <type 'str'>
因此,果断的把my_file这个中间文件给去掉。
第二点:
为每个人循环20遍,这个做法不明智。因为如果当前正在提交的人的信息根本不可能被accepted,比如学号密码打错了,或者选的课程已经满了(这是极有可能发生的),这时再为此人循环20遍,明显的是在浪费时间,而且影响了后面人的提交。难道这就是传说中的“占着茅坑不拉屎”?因此果断的把最后一个循环去掉。
经过上面的两点改进,相信效率一定会有极大的提升。
做了一个final版本,暂且贴上吧。
#coding=gb2312 import urllib import urllib2 import re import os url = 'http://……' info_list = [ {'week' : '9', 'expnumber' : '实验10' , 'weekday' : '2' , 'exp_class' : '3-4' , 'number' : '10000000' , 'password' : '12345678' } , {'week' : '9', 'expnumber' : '实验10' , 'weekday' : '2' , 'exp_class' : '3-4' , 'number' : '20000000' , 'password' : 'abcdefgh' } ] name_list = [ '张三' , '李四' ] trace = [ 0 , 0 ] def submit(): while True: whether_over = 1 for i , each_people in enumerate( info_list ): if trace[ i ] == 0 : whether_over = 0 data = urllib.urlencode( each_people ) req = urllib2.Request( url , data ) try: response = urllib2.urlopen( req ) except urllib2.URLError: continue else : the_page = response.read() m = re.search( '课程预约成功', the_page ) if m is not None: result_file = open( '/home/superior/Documents/result_log.txt' , 'a+' ) result_file.write( name_list[ i ] + ' successful ' + os.popen( 'date' ).read() + '/n' ) result_file.close() trace[ i ] = 1 if whether_over == 1: break if __name__ == '__main__': submit()