python爬蟲——模擬登入教務系統爬取成績
主要思路
1.模擬登入到教務處,獲取登入的cookie值,用獲取到的cookie值,訪問成績的網址,分析成績頁面,獲取成績資訊。
2.打包成exe檔案,方便使用 ,我們可以用自己寫的程式快速查詢我們的成績,速度要比正常登入教務處網址查詢快很多,也比超級課程表查詢快很多。
3.舉一反三,我們可以採取同樣的方法獲取教務系統裡面的其他資訊(如學籍卡片,理論課表等),其操作流程基本相同。
首先,我們看一下教務系統的登入介面(本文使用火狐瀏覽器)
按F12進入開發者選項,選擇網路,並輸入使用者名稱和密碼進行登入
我們發現第一條即是我們提交(post)的表單資料,我們點開後,會在右面訊息頭裡找到我們的請求網址http://cdjwc.ccu.edu.cn/jsxsd/xk/LoginToXk
接下來找要提交的資料,找到引數,我們發現表單資料。但資料與我們平時看到的表單資料不一樣。這是經過base64加密的資料。我們可以通過https://base64.supfree.net/,檢視BASE64的加密解密。不難發現,這條表單資料正式用這種方法進行加密的。那麼資料加密了,我們該怎麼辦呢?。由於我們使用的語言是python,這給我們帶來了很大的方便,python中base64庫專門用來base64的加密。
既然我們解決了這個問題,那麼我們就可以模擬登入了。
模擬登陸的程式碼
import requests
import base64
username = input("請輸入賬號:" )
password = input("請輸入密碼:")
jiema = username + password#解碼
encodestr = str(base64.b64encode(jiema.encode('utf-8')), 'utf-8')
print(encodestr)
encoded = encodestr[0:12] + '%%%' + encodestr[12:]#寫成表單資料的格式,將賬號與密碼用%%%分開
print(encoded)
login_url = 'http://cdjwc.ccu.edu.cn/jsxsd/xk/LoginToXk'
headers = {
'User-Agent' :
'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:61.0) Gecko/20100101 Firefox/61.0',
'Connection':
'keep-alive'
}
data = {'encoded': encoded}
html=requests.post(url=login_url,headers=headers,data=data)
print(html.text)
登陸後,我們可以看到首頁的資訊。這說明我們對錶單資料的處理是正確的。接下來,我們要獲取到cookie值。requests.session()
requests模組中的session()方法能夠獲取到cookie值。
session=requests.session()
html=session.post(url=login_url,headers=headers,data=data)
cookies=requests.utils.dict_from_cookiejar(session.cookies)
print(cookies)
這樣我們就可以獲取到cookie值了,獲取到的是一個字典。既然cookie值已經獲取到了,我們暫時放在這。接下來分析成績查詢的頁面。
我們在開發者選項下,找到成績頁面,同樣,我們發現第一條就是我們要抓的資料。
我們找到了請求的網址,接下來找到要提交的資料,同樣在引數中尋找。
既然資料找到了,那麼我們就可以請求這個頁面了,但是怎麼將cookie值傳入呢?我們發現cookie在請求頭headers中,為了方便有效,我們乾脆把下面請求頭的內容全部複製到程式碼中,將cookie換成我們上文中模擬登陸拿到的即可。
Host: cdjwc.ccu.edu.cn
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:61.0) Gecko/20100101 Firefox/61.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Referer: http://cdjwc.ccu.edu.cn/jsxsd/kscj/cjcx_query?Ves632DSdyV=NEW_XSD_XJCJ
Content-Type: application/x-www-form-urlencoded
Content-Length: 26
Cookie: _gscu_752261578=217071781ip13z15; _gscbrs_752261578=1; JSESSIONID=52E0451173A7556EAB6ED1498AB75B69#這裡面換掉
Connection: keep-alive
Upgrade-Insecure-Requests: 1
進行測試,看能否獲取到成績頁面的資訊
import requests
import base64
import re
from bs4 import BeautifulSoup
from urllib import request
from http import cookiejar
username = input("請輸入賬號:")
password = input("請輸入密碼:")
jiema = username + password#解碼
encodestr = str(base64.b64encode(jiema.encode('utf-8')), 'utf-8')
print(encodestr)
encoded = encodestr[0:12] + '%%%' + encodestr[12:]#寫成表單資料的格式,將賬號與密碼用%%%分開
print(encoded)
login_url = 'http://cdjwc.ccu.edu.cn/jsxsd/xk/LoginToXk'
headers = {
'User-Agent':
'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:61.0) Gecko/20100101 Firefox/61.0',
'Connection':
'keep-alive'
}
data = {'encoded': encoded}
session = requests.session()
#html=requests.post(url=login_url,headers=headers,data=data)
html = session.post(url=login_url, headers=headers, data=data)
cookies = requests.utils.dict_from_cookiejar(session.cookies)
#print(cookies)
a = cookies['JSESSIONID']
#print(a)
#print(html.text)
info = re.findall(
'<div id="Top1_divLoginName" class="Nsb_top_menu_nc" style="color: #000000;">(.*?)</div>',
html.text)
if len(info) > 0:
name = info[0]
if name:
print('******************')
print(name)
print('******************')
print("正在查詢,請稍後")
url_grade = 'http://cdjwc.ccu.edu.cn/jsxsd/kscj/cjcx_list'
data2 = {
'kcmc': '',
'kcxz': '',
'kksj': '',
'xsfs': 'all',
}
headers = {
'Accept':
'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Encoding':
'gzip, deflate',
'Accept-Language':
'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2',
'Cache-Control':
'max-age=0',
'Connection':
'keep-alive',
'Content-Length':
'26',
'Cookie':
'JSESSIONID=' + a,
'Content-Type':
'application/x-www-form-urlencoded',
'Host':
'cdjwc.ccu.edu.cn',
'Referer':
'http://cdjwc.ccu.edu.cn/jsxsd/kscj/cjcx_query?Ves632DSdyV=NEW_XSD_XJCJ',
'Upgrade-Insecure-Requests':
'1',
'User-Agent':
'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:59.0) Gecko/20100101 Firefox/59.0}',
}
html2 = requests.post(url_grade, data=data2, headers=headers)
print(html2.text)
通過列印html2.text,我們可以知道,已經能夠順利的獲取到成績頁面資訊了。我們已經完成大多數了,接下來只需在html2中將想要的科目資訊及成績資訊提取出來即可,這裡可以使用正則表示式。我是使用BeautifulSoup,這樣獲取也許會方便一些吧。
我們想要的內容,都在id=”dataList” 的table標籤下。確切的說是除了第一個外的所有tr標籤下,這樣我們稍作處理就能獲取所有的成績資訊了。
完整程式碼
import requests
import base64
import re
from bs4 import BeautifulSoup
from urllib import request
from http import cookiejar
print('\n')
print("不用教務系統也能直接查成績了!!!")
print('\n')
print('****************************')
username=input("請輸入賬號:")
password=input("請輸入密碼:")
jiema=username+password
encodestr =str( base64.b64encode(jiema.encode('utf-8')),'utf-8')
#print(encodestr)
encoded=encodestr[0:12]+'%%%'+encodestr[12:]
#print(encoded)
login_url='http://cdjwc.ccu.edu.cn/jsxsd/xk/LoginToXk'
headers={
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:61.0) Gecko/20100101 Firefox/61.0',
'Connection': 'keep-alive'
}
data={
'encoded':encoded
}
session=requests.session()
#html=requests.post(url=login_url,headers=headers,data=data)
html=session.post(url=login_url,headers=headers,data=data)
cookies=requests.utils.dict_from_cookiejar(session.cookies)
#print(cookies)
a=cookies['JSESSIONID']
#print(a)
#print(html.text)
info=re.findall('<div id="Top1_divLoginName" class="Nsb_top_menu_nc" style="color: #000000;">(.*?)</div>',html.text)#找到登入著的姓名及學號
if len(info)>0:#如果存在,繼續操作,如果不存在,則說明登陸失敗,需重新登陸。
name=info[0]
if name:
print('******************')
print(name)
print('******************')
print("正在查詢,請稍後")
print('******************')
url_grade = 'http://cdjwc.ccu.edu.cn/jsxsd/kscj/cjcx_list'
data2 = {'kcmc': '',
'kcxz': '',
'kksj': '',
'xsfs': 'all',
}
headers = {'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Encoding': 'gzip, deflate',
'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2',
'Cache-Control': 'max-age=0',
'Connection': 'keep-alive',
'Content-Length': '26',
'Cookie':'JSESSIONID='+a,
'Content-Type':'application/x-www-form-urlencoded',
'Host': 'cdjwc.ccu.edu.cn',
'Referer': 'http://cdjwc.ccu.edu.cn/jsxsd/kscj/cjcx_query?Ves632DSdyV=NEW_XSD_XJCJ',
'Upgrade-Insecure-Requests': '1',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:59.0) Gecko/20100101 Firefox/59.0}',}
html2=requests.post(url_grade,data=data2,headers=headers)
#print(html2.text)
soup = BeautifulSoup(html2.text, 'lxml')#建立soup物件
table = soup.select("#dataList")[0]
tr = table.find_all('tr')[1:]
for i in tr:
subject = i.find_all('td', align="left")[1::2][0].text
score = i.find('a').text
print(subject + '--------------' + score)
print('******************')
input("輸入回車鍵退出查詢")
else:
print('賬號或密碼錯誤,請重新輸入!!')
打包成可執行程式:
在cmd中進入程式所在檔案目錄,執行
pyinstaller 檔名.py -F
即可打包。如果打包過程出現編碼錯誤,找到最後一個報錯所在的檔案,將with open(filename)as f: 改成with open(filename,encoding=”UTF-8”)as f:(我的是在C:\ProgramData\Anaconda3\Lib\site-packages\PyInstaller\utils\win32下的winmanifest.py檔案,1075行)即可。重新執行pyinstaller 檔名.py -F