今天要說的一個小項目是利用Python來獲取正方教務系統的在校成績,說白了這就是一網絡爬蟲。做之前也有上網搜索了一下資料,這裏就給一個總體的思路吧,就以我學校的作爲例子。不過遺憾的是並沒有添加驗證碼的破解功能,還需要手動輸入。希望能夠幫助到一些朋友。
以下的代碼全部基於Python3。
開始之前:
1、請自行安裝BeautifulSoup 用於網頁解析
2、請自行安裝PrettyTable 用戶格式化輸出
3、請自行安裝PIL 用於打卡圖片。這也是日後想增加OCR識別的一個部分
觀察:
做好了以上的準備工作之後,接下來就要觀察一下我們的教務系統,觀察以下登陸的表單:
可以發現表單被提交至default2.aspx,驗證碼是一個單獨的網頁,爲CheckCode.aspx,表單提交頁應該是一樣的,就是驗證碼,各個學校會有不同。
在利用抓包工具可以發現瀏覽器向客戶端提交了如下圖數據:
總共提交了10個參數(因學校而異,不過應該都差不多)
這有值的5個參數分別對應:_VIEWSTATE,用戶名,密碼,驗證碼,登陸角色(學生)。剩下那些沒有值的在後期構建表單的時候也需要創建
接下來我們進入到查詢全部成績的頁面,頁面也因學校而異
通過抓包工具獲得頁面地址,如下圖方框中的
這時要記下上圖方框中的地址,再一次觀察表單提交的數據:
這一次是6個參數。
其中第一個是_VIEWSTATE,第二個是學年,第三個是學期,緊接着後兩個參數未知,照着寫就好,最後一個參數是【在校學習成績查詢】按鈕URL編碼後的值
不知道大家有沒有注意到在上面兩次查看錶單數據的過程中都出現了一個參數叫_VIEWSTATE?而且兩次都還不一樣,所以我們在模擬的時候要分兩次獲得_VIEWSTATE。
最後我們再看一眼HTTP請求頭
看到那個紅框了嗎,這個Refer參數很重要,要記得添加,否則就會出現302跳轉,然後顯示一行
因爲這個參數在這裏是用來防止盜鏈的,不信的話可以用Chrome的ModHeader插件來試一試
思路:
1、總體:藉助Python的http.cookiejar.CookieJar對象,使用urllib.request.build_opener來構建一個帶有Cookie的opener,然後就使用這個opener來訪問所有的頁面,最後輸出結果就好了。
2、驗證碼的獲取與顯示:因爲我們是要讓用戶輸入驗證碼,所以我們需要把獲取到的圖片以二進制流的方式寫入文件。在利用PIL的open方法將圖片文件讀入,創建圖片對象,最後用show方法調用系統的圖片查看器顯示圖片。代碼片段:
res = opener.open('http://example.com/checkcode.aspx').read()
with open('code.jpg','wb') as file:
file.write(res)
img = Image.open('code.jpg')
img.show()
3、_VIEWSTATE的獲取:這個就要利用正則,把網頁的html讀取下來之後,利用以下正則表達式進行匹配
viewstate = re.search('<input type="hidden" name="__VIEWSTATE" value="(.+?)"',html)
params['__VIEWSTATE'] = viewstate.group(1)
這個params爲我們要提交的表單數據字典
4、關於BeautifulSoup4的解析:我當時是這樣進行分析的,我把網頁讀取出來之後,構造了一個BeautifulSoup對象
soup = BeautifulSoup(response.read().decode('gb2312'),'html.parser')
這裏要注意一下後面的html.parser是解釋器,要加上,然後要根據各自教務系統的編碼進行解碼
接着使用CSS過濾器找到成績表格
html = soup.find('table',class_='datelist')
它會返回一個Tag對象,這個對象是可迭代的,所以我們可以使用for語句來遍歷我們的表格,來獲取每一行的內容,最後在根據需求進行篩選,這個就要因人因學校而異了,因爲每一個學校的表格都不太一樣。
5、PrettyTable輸出:說一點,輸出時要使用str()這個BIF進行轉換,不然有可能會報錯
代碼:
https://github.com/mgsky1/ScoreHelper/blob/master/src/getScore.py
附:
我在源碼中還使用Pickle,用二進制的方式存儲用戶數據,這樣可以避免煩人的多次輸入