天天看點

大學搶課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()