生活随笔
收集整理的這篇文章主要介紹了
用Python登陆新版正方教务系统获取课程表(及RSA加密密码实现)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
前言
最近做一個微信小程序,需要登錄教務系統。提前用python嘗試一下登錄接口,并獲取到課表打印出來。
我們學校用到新版正方教務系統,長這個樣子。
相比舊版的教務系統,唯一好處是不用輸入二維碼方便爬蟲登錄。但登錄時用到RSA加密密碼發送請求。
正文
分析網頁:
在網頁上填上隨便寫的賬號密碼,點擊登錄。開發者工具記錄如下:
首先它點擊登錄后,提交一個表單,Form Data一共有4個數據
提交的數據解釋
| csrftoken | 為了防止跨站域請求偽造 。在登錄頁源碼里有,每次刷新都會變更 |
| yhm | 輸入的用戶名 |
| mm | 輸入的密碼,被加密過。我們主要關注這一個加密過程 |
csrftoken 如圖所示:
另外,在開發者工具里,我們還需要注意服務器的一條get請求
查看它返回的數據
這條Get請求作用:發送當前時間戳,返回公共密鑰。并且每次modulus的數據不同,有人會問,這個東西干嘛的?
其實,這是在密碼加密時用到的公鑰,如果你也曾看過它的密碼加密代碼,就會了解到。
我們翻一下網站的Javascript,看看密碼加密過程
$
.getJSON(_path
+"/xtgl/login_getPublicKey.html?time="+new Date().getTime(),function(data
){modulus
= data
["modulus"];exponent
= data
["exponent"];});
if($("#mmsfjm").val() == '0'){$("#hidMm").val($("#mm").val());}else{var rsaKey
= new RSAKey();rsaKey
.setPublic(b64tohex(modulus
), b64tohex(exponent
));var enPassword
= hex2b64(rsaKey
.encrypt($("#mm").val()));$("#mm").val(enPassword
);$("#hidMm").val(enPassword
); }
具體加密過程:首先獲取modulus,exponent。將他們從base64轉16進制,再通過RSA算法生成公鑰。
用公鑰將密碼生成私鑰從16進制轉回base64。變成最終加密的密碼。
至此,我們分析完成,在python里面要做的步驟:
1、獲取到csrftoken
2、發送時間戳獲取到PublicKey
3、生成RSA加密的密碼
4、POST請求登錄
python實現過程
登錄中唯一難點是生成rsa加密的密碼,有大神把js的rsa算法寫成python,具體在github里。我已經下載并放在項目文件夾下,直接調用。
頭部文件:
import requests
import time
from lxml
import etree
from hex2b64
import HB64
import RSAJS
重中之重的RSA加密過程:
def Get_RSA_Password(self
):rsaKey
= RSAJS
.RSAKey
()rsaKey
.setPublic
(HB64
().b642hex
(self
.modulus
),HB64
().b642hex
(self
.exponent
))self
.enPassword
= HB64
().hex2b64
(rsaKey
.encrypt
(self
.Password
))
與JavaScript原加密算法對比:
登錄代碼:
def Longin_Home(self
):self
.Get_indexHtml
()self
.Get_csrftoken
()self
.Get_PublicKey
()self
.Get_RSA_Password
()login_data
= [("csrftoken", self
.csrftoken
),("yhm", self
.Username
),("mm", self
.enPassword
),("mm", self
.enPassword
)]login_html
= self
.session
.post
(self
.login_url
+ self
.now_time
,data
=login_data
)if login_html
.url
.find
("login_slogin.html") == -1: print("登錄成功")return self
.session
else:print("用戶名或密碼不正確,登錄失敗")exit
()
獲取課程表代碼
class TimeTable():def __init__(self
,session
,table_url
):data
= {"xnm":2018,"xqm":12}table_info
= session
.post
(table_url
,data
= data
).json
()for each
in table_info
["kbList"]:plt
= r
'{} | {:<8s} | {:<13s} | {:<15s} | {:<22s}'print(plt
.format(each
["xqjmc"], each
["jc"], each
["cdmc"], each
["zcd"], each
["kcmc"]))
登錄成功后已經可以為所欲為了,獲取課程表只是一個簡單操作,就沒怎么優化代碼了。
完整代碼:
import requests
import time
from lxml
import etree
from hex2b64
import HB64
import RSAJS
class Longin():def __init__(self
,user
,password
,login_url
,login_KeyUrl
):self
.Username
= userself
.Password
= passwordnowTime
= lambda:str(round(time
.time
()*1000))self
.now_time
= nowTime
()self
.login_url
= login_urlself
.login_Key
= login_KeyUrl
def Get_indexHtml(self
):self
.session
= requests
.Session
()self
.session
.headers
.update
({"User-Agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36","Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8","Accept-Encoding": "gzip, deflate","Accept-Language": "zh-CN,zh;q=0.9","Cache-Control": "max-age=0","Connection": "keep-alive","Referer": self
.login_url
+ self
.now_time
,"Upgrade-Insecure-Requests": "1"
})self
.response
= self
.session
.get
(self
.login_url
+ self
.now_time
).content
.decode
("utf-8")def Get_csrftoken(self
):lxml
= etree
.HTML
(self
.response
)self
.csrftoken
= lxml
.xpath
("//input[@id='csrftoken']/@value")[0]def Get_PublicKey(self
):key_html
= self
.session
.get
(self
.login_Key
+ self
.now_time
)key_data
= key_html
.json
()self
.modulus
= key_data
["modulus"]self
.exponent
= key_data
["exponent"]def Get_RSA_Password(self
):rsaKey
= RSAJS
.RSAKey
()rsaKey
.setPublic
(HB64
().b642hex
(self
.modulus
),HB64
().b642hex
(self
.exponent
))self
.enPassword
= HB64
().hex2b64
(rsaKey
.encrypt
(self
.Password
))def Longin_Home(self
):self
.Get_indexHtml
()self
.Get_csrftoken
()self
.Get_PublicKey
()self
.Get_RSA_Password
()login_data
= [("csrftoken", self
.csrftoken
),("yhm", self
.Username
),("mm", self
.enPassword
),("mm", self
.enPassword
)]login_html
= self
.session
.post
(self
.login_url
+ self
.now_time
,data
=login_data
)if login_html
.url
.find
("login_slogin.html") == -1: print("登錄成功")return self
.session
else:print("用戶名或密碼不正確,登錄失敗")exit
()class TimeTable():def __init__(self
,session
,table_url
):data
= {"xnm":2018,"xqm":12}table_info
= session
.post
(table_url
,data
= data
).json
()for each
in table_info
["kbList"]:plt
= r
'{} | {:<8s} | {:<13s} | {:<15s} | {:<22s}'print(plt
.format(each
["xqjmc"], each
["jc"], each
["cdmc"], each
["zcd"], each
["kcmc"]))if __name__
== "__main__":login_url
= "http://學校主頁/jwglxt/xtgl/login_slogin.html?language=zh_CN&_t="login_KeyUrl
= "http://學校主頁/jwglxt/xtgl/login_getPublicKey.html?time="table_url
= "http://學校主頁/jwglxt/kbcx/xskbcx_cxXsKb.html?gnmkdm=N2151"zspt
= Longin
("輸入你的賬號","輸入你的密碼",login_url
,login_KeyUrl
)response_cookies
= zspt
.Longin_Home
()table
= TimeTable
(response_cookies
,table_url
)
最后需要注意的地方:
為了代碼更有移植性,方便各位在自己的學校的教務系統登錄,整個代碼幾乎封裝好了。也即是說,只要你的學校也使用新版正方教務系統,那么稍微閱讀代碼(特別是if "__name__"==__main__:這部分),改三個網站地址便可調用。
程序里調用的hex2b64、RSAJS庫和完整代碼我已經打包好了,上傳到csdn里。或者你也可以在評論留下郵箱,看到了就發給你。
CSDN下載鏈接:
https://download.csdn.net/download/koevas/11010479
百度云:
鏈接:https://pan.baidu.com/s/1gkMXCzXdx5NWUUs8bvGM-A
提取碼:it2x
參考資料:
https://github.com/Pusnow/pyjsbn-rsa
https://blog.csdn.net/qq_33278884/article/details/80936714
https://www.v2ex.com/t/433971
總結
以上是生活随笔為你收集整理的用Python登陆新版正方教务系统获取课程表(及RSA加密密码实现)的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。