1. 程式人生 > >python爬蟲——模擬登入教務系統爬取成績

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這裡寫圖片描述