天天看点

大学抢课python脚本_用彪悍的Python写了一个自动选课的脚本 | 学步园

高手请一笑而过。

物理实验课别人已经做过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 

the_page 

因此,果断的把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()