CC~NU搶課腳本

34.jpg
34.jpg

用前說明:

本文章僅對 Web 開發(fā),Python 開發(fā)進行探討,進行實驗時請遵守學校的規(guī)章制度。
任務自動化本來就是程序員的一大樂趣,無關價值觀。

廢話

很多人有誤區(qū),以為搶課腳本就是像游戲外掛一樣,利用什么教務處系統(tǒng)漏洞去搞到課,而事實上搶課腳本只是模擬瀏覽器和服務器進行交互而已。而它們之間交互的方式是使用 HTTP 協(xié)議,換言之你的程序只要通過 HTTP 協(xié)議與服務器進行交互,就可以模擬瀏覽器能完成的事情。

當然,最樸素的搶課腳本應當數(shù)按鍵精靈。但是按鍵精靈依賴于瀏覽器的渲染速度,而使用 HTTP 協(xié)議交互的腳本可以忽略一切 CSS JS 文件的解析,直接發(fā)請求,資源占用和速度都優(yōu)化了一個量級。

簡而言之,由于 HTTP 是無狀態(tài)協(xié)議,所以每次提交請求,服務器無法判斷你是否是之前的用戶,因此在動態(tài)網(wǎng)頁中常用 Cookies 來鑒別用戶身份,Cookies 是附加在每次 HTTP 請求中用來識別用戶身份的數(shù)據(jù)。

在 Python 中,直接使用 urllib2 默認的 urlopen 是不能處理好 Cookies 的,這里的 urlopen 可以看成是一個能向目標 URL 發(fā)請求的對象。所以我們使用 cookielib 來構造一個能處理 Cookies 的 opener。

cookie = cookielib.CookieJar()
handler = urllib2.HTTPCookieProcessor(cookie)
opener = urllib2.build_opener(handler)

以后,我們使用 opener.open(url) 就可以帶 Cookies 去發(fā) GET 請求了。

環(huán)境要求

  • Python 3
  • selenium
  • chrome
  • chromedriver

登錄

首先用 Chrome 分析一下教務系統(tǒng)的邏輯是怎樣的,打開 Inspect 然后打開教務處網(wǎng)站


屏幕快照 2018-01-09 14.29.59.png
屏幕快照 2018-01-09 14.29.59.png

12.png
12.png

可以看出,前端一點都不簡潔,估計編寫代碼的人技術不是很高,從文件名可以簡單地看出 cas.js 應該是散列函數(shù),應該是處理密碼用的。

然后我們手動登錄一下,看看登錄的請求是怎樣的。


132.png
132.png

屏幕快照 2018-01-09 14.47.21.png
屏幕快照 2018-01-09 14.47.21.png

可以看出發(fā)送了一個 POST 請求,請求地址是 http://xk.ccnu.edu.cn//xtgl/index_initMenu.html。表單內容有 username、password、j_code 和一堆不知道含義的東西。顯然 username 是學號了,password 有經(jīng)驗的可以看出來是的 MD5 散列之后的結果,j_code 是驗證碼結果。

直接對應填上即可。

post_data = {}
post_data['username'] = username
post_data['password'] = pasw_cas
post_data['lt'] = ''
post_data['_eventId'] = 'submit'
post_data['submit'] = '登錄'
post_data = urllib.urlencode(post_data)
opener.open(login_url, post_data)

CAS

既然知道了和 CAS 有關系,可以用 Python 的 cas 模塊進行嘗試。

pasw_cas = cas.new()
pasw_cas.update(password)
pasw_cas = pasw_cas.hexdigest().upper()

一測試發(fā)現(xiàn),提交的就是密碼的 CAS 散列,問題就輕易解決了。當然如果不對,一般來說可以嘗試用戶名+密碼的組合,還有是加上時間戳的組合,最后不行就去逆向 JS 文件吧。

搶課請求

相信到這里很多人已經(jīng)摸到套路了,無非就是抓一個請求,分析,然后偽造這個請求。
這里發(fā)現(xiàn)選課只需要發(fā)一個 POST 請求到 http://xk.ccnu.edu.cn//xtgl/,當然也有帶上 SID,此外還有一個參數(shù),想必就是課程編號了。

和登錄一樣,我們構造一個字典,然后用 urllib 中的 urlencode 功能進行編碼,最后使用 opener.open(res, elect_post_data) 發(fā)送請求即可。

elect_post_data = {};
elect_post_data['sid'] = sid
res = urllib2.Request(elect_url)
opener.open(res, elect_post_data)

如果再套上一個死循環(huán),這個搶課腳本就寫完了。當然,肯定是有很多問題的,我們慢慢來解決

Delay

如果直接死循環(huán)而不加上延時,服務器多半會掛掉。因為客戶端的一個請求對應服務器的一次數(shù)據(jù)庫查詢,多半這樣的壓力學校服務器是受不了的。而且過高的發(fā)包很容易被查水表,一般來說 0.5s 到 0.3s 的延時已經(jīng)足夠超越極大部分單身二十年少年的手速。

瀏覽器偽裝

一般的 Web 都是會對 HTTP 的請求頭進行檢測,以防止一些最簡單的爬蟲,很幸運的是,教務系統(tǒng)并沒有。但是一旦對方的 Web Server 開啟了訪問記錄,很容易把這些 HTTP 請求頭為空的請求篩選出來,然后慢慢查水表之類的,所以為了安全起見,我們需要偽造瀏覽器的請求頭。

UA = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36'
Referer = 'http://xk.ccnu.edu.cn/zftal-ui-v5-1.0.2/assets/js/zftal/jquery.extends.contact-min.js?ver=20171211' + sid
X_Requested_With = 'XMLHttpRequest'
res.add_header('User-Agent', UA)
res.add_header('Referer', Referer)
res.add_header('X_Requested_With', X_Requested_With)

解析響應

上面的代碼我們只處理了發(fā)送請求,而并沒有理會響應,這樣即使搶到了課,程序還是會繼續(xù)運行下去。

我們先分析一下響應是怎樣的,Chrome 中 Inspect 有一個很好用的功能是 Copy as cURL,可以將這次請求提取為 cURL 命令,方便丟到命令行進行分析。


5.png
5.png

可以看出這是一個 JSON 格式的響應,在 Python 處理 JSON 很方便,我們可以用 json 庫中的 response_json = json.loads(response) 將 JSON 字符串轉換為一個字典。這樣你就可以根據(jù)響應來后續(xù)處理,例如是微信通知之類的。

注意

  • 不建議在一臺電腦上開啟多個。
  • 本腳本僅為個人程序開發(fā)之練習,切勿隨意傳播。
  • 改選時間尚未開放,該腳本暫未測試,暫未測試,暫未測試!

致謝:

caoruiy

原文地址:www.iooy.com

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內容