相比旧版的教务系统,唯一好处是不用输入二维码方便爬虫登录。但登录时用到RSA加密密码发送请求。
首先它点击登录后,提交一个表单,Form Data一共有4个数据
提交的数据 | 解释 |
---|---|
csrftoken | 为了防止跨站域请求伪造 。在登录页源码里有,每次刷新都会变更 |
yhm | 输入的用户名 |
mm | 输入的密码,被加密过。我们主要关注这一个加密过程 |
查看它返回的数据
这条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请求登录
头部文件:
import requests
import time
from lxml import etree
from hex2b64 import HB64
import RSAJS
重中之重的RSA加密过程:
def Get_RSA_Password(self):
# 生成RSA加密密码
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):
# 登录信息门户,成功返回session对象
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)
# 当提交的表单是正确的,url会跳转到主页,所以此处根据url有没有跳转来判断是否登录成功
if login_html.url.find("login_slogin.html") == -1: # -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"]))
登录成功后已经可以为所欲为了,获取课程表只是一个简单操作,就没怎么优化代码了。
完整代码:
# -*- coding=utf-8 -*-
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 = user
self.Password = password
nowTime = lambda:str(round(time.time()*1000))
self.now_time = nowTime()
self.login_url = login_url
self.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):
# 获取到csrftoken
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):
# 生成RSA加密密码
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):
# 登录信息门户,成功返回session对象
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)
# 当提交的表单是正确的,url会跳转到主页,所以此处根据url有没有跳转来判断是否登录成功
if login_html.url.find("login_slogin.html") == -1: # -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__":
# 登录主页url
login_url = "http://学校主页/jwglxt/xtgl/login_slogin.html?language=zh_CN&_t="
# 请求PublicKey的URL
login_KeyUrl = "http://学校主页/jwglxt/xtgl/login_getPublicKey.html?time="
# 登录后的课表URL
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)
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