Python模拟登陆新版教务网获取课表、成绩(RSA加密)
python作为一门编程语言,可以干好多好多事,可以说只要你想得到,没有它做不到的。自学python有一段时间了,现在此记录近段时间的所学成果——爬取学校教务网。
先贴最终效果图:
如果你的教务网也是这样的,那你算看对文章了。如果不是那你也可以学习爬取信息的思路。
1.信息获取第一步,模拟登录。
在此需要使用浏览器抓包工具,查看请求登录需要发送哪些信息。
教务网界面按F12,会弹出如下界面(作者使用的是win10自带的浏览器)
选择网络(360浏览器是network),开始抓包(也可以用wireshark)。准备好之后输入账号密码进行登录,很快network里就会出现很多条请求信息,我们进行的是登录操作,一般使用的方法都是“post”,而名称会包含login,很快找到下图的一条信息。
选择抓到的这条信息,查看正文,如下。
可以见到这里登录需要4个参数(其实是3条,有两条重复),我们可以确定yhm就是我们的用户名(学号)就是刚才输入的,mm肯定是密码,但怎么不是刚才输入的,加密了?不明白,那就查看源代码吧。
同样F12查看源代码
从中可以发现
现在知道密码为什么要重复了,看了半天也不知道密码是怎么加密的,最后在引用的JavaScript里看到原来是RSA的加密方式。
此时也许你会问什么是RSA,我也不知道,百度一番,看了大量的文章,RSA其实就是把密码进行因式分解那样,是一种主流的加密方式,安全性高,原来他还有公钥、私钥这一回事。那公钥、私钥怎么来呢?同样进行抓包,打开网页之前就抓。
exponent、modulus就是我们要找的公钥、私钥了。
然后在网页源码里找到csrftoken,如下
此外,登录一个网站还需要发送一般的参数,也就是请求标头
好了,理清楚的教务网的登录机制,开始动手码代码吧。
首先是获取公钥、私钥
发送此请求还需要时间参数,可以查看源代码获得,获取方式
其次是对输入的账号密码进行加密,此时导入一个RSA加密的包,需要注意编码格式。
此时就可以进行完整的登录操作了。
可以通过请求的返回结果来判断登录是否成功
好了,如果你做到了这一步,你就可以对教务网进行肆无忌惮得操作了。
查课表:
请求url:
解析查询返回的json:
查成绩:
请求URL:
解析json:
此外还可以写一段自动评教、选课的代码,只要你能想到,都可以实现。
另外,如果你有兴趣可以把python代码修改成别的编程语言,例如java、C,你还可以改写成Android的,开发编写手机端的掌上教务网APP,甚至可以模仿超级课程表。
最后贴上源代码:
def __init__(self,year,term):
self.year = year
self.term = term
self.url1 = 'http://i.nbut.edu.cn:8066/jwglxt/kbcx/xskbcx_cxXskbcxIndex.html?gnmkdm=N253508&layout=default&su='+cumt_login.user
self.url2 = 'http://i.nbut.edu.cn:8066/jwglxt/kbcx/xskbcx_cxXskbcxIndex.html?doType=query&gnmkdm=N253508'
self.url3 ='http://i.nbut.edu.cn:8066/jwglxt/kbcx/xskbcx_cxRsd.html?gnmkdm=N253508'
self.url4 ='http://i.nbut.edu.cn:8066/jwglxt/kbcx/xskbcx_cxXsKb.html?gnmkdm=N253508'
def welcome(self):
try:
stu_name = self.req_2['xsxx']['XM']
sch_stu = self.req_2['xsxx']['XH']
institute = self.req_2['xsxx']['XNMC']
classss = self.req_2['xsxx']['XKKG']
# print(self.req_2)
print('')
print(stu_name+'同学,欢迎您!!!')
print('')
print('姓名:{}\t学号:{}\t\t学年:{}\t学期:{}'.format(stu_name,sch_stu,institute,classss))
print('')
for i in self.req_2['kbList']:
print("课程名称:"+i['kcmc'])
print("教师:"+i['xm'])
print("上课地点:"+i['xqmc']+i['cdmc'])
print("时间:"+i['jcs']+'\t'+i['zcd'])
print('')
except:
print('无当前学期,请重试')
def post_gradedata(self):
try:
data = {'_search':'false',
'nd':int(time.time()),
'queryModel.currentPage':'1',
'queryModel.showCount':'15',
'queryModel.sortName':'',
'queryModel.sortOrder':'asc',
'time':'3',
'xnm':self.year,
'xqm':self.term
}
data3 = {'xnm': self.year,
'xqh_id': self.term,
'xqm': self.term
}
data4 = {'xnm': self.year,
'xqm': self.term
}
req_1 = super().sessions.post(self.url1,data = data,headers = cumt_login.header)
req_2 = super().sessions.post(self.url2,data = data , headers = cumt_login.header)
req_3 = super().sessions.post(self.url3,data = data3,headers = cumt_login.header)
req_4 = super().sessions.post(self.url4,data = data4, headers = cumt_login.header)
self.req_2 = req_4.json()
except:
print('获取失败,请重试...')
time.sleep(2)
exit()
def __init__(self,year,term):
self.year = year
self.term = term
self.url1 = 'http://i.nbut.edu.cn:8066/jwglxt/cjcx/cjcx_cxDgXscj.html?gnmkdm=N305005&layout=default&su='+cumt_login.user
self.url2 = 'http://i.nbut.edu.cn:8066/jwglxt/cjcx/cjcx_cxDgXscj.html?doType=query&gnmkdm=N305005'
def welcome(self):
try:
stu_name = self.req_2['items'][0]['xm']
sch_stu = self.req_2['items'][0]['xslb']
institute = self.req_2['items'][0]['jgmc']
classss = self.req_2['items'][0]['bj']
print('')
print('')
print(stu_name+'同学,欢迎您!!!')
print('')
print('姓名:{}\t学历:{}\t\t学院:{}\t班级:{}'.format(stu_name,sch_stu,institute,classss))
print('')
except:
print('无当前学期,请重试')
def post_gradedata(self):
try:
data = {'_search':'false',
'nd':int(time.time()),
'queryModel.currentPage':'1',
'queryModel.showCount':'15',
'queryModel.sortName':'',
'queryModel.sortOrder':'asc',
'time':'0',
'xnm':self.year,
'xqm':self.term
}
req_1 = super().sessions.post(self.url1,data = data,headers = cumt_login.header)
req_2 = super().sessions.post(self.url2,data = data , headers = cumt_login.header)
self.req_2 = req_2.json()
# print(self.req_2)
except:
print('获取失败,请重试...')
time.sleep(2)
exit()
def print_geades(self):
try:
plt = '{0:{4}<15}\t{1:{4}<6}\t{2:{4}<6}\t{3:{4}<4}'
gk = 0
zkm = 0
print('')
print('--------------------------------------------------------------------------------')
print(plt.format('课程','成绩','绩点','教师',chr(12288)))
print('--------------------------------------------------------------------------------')
for i in self.req_2['items']:
print(plt.format(i['kcmc'],i['bfzcj'],i['jd'],i['jsxm'],chr(12288)))
if i['bfzcj'] < 60:
gk +=1
zkm += 1
print('--------------------------------------------------------------------------------')
print('')
print('通过科目数:{}{}'.format(zkm-gk,'门'))
print('挂科科目数:'+str(gk)+'门')
print('')
print('')
except:
print('无当前学期,请重试')
如果你觉得麻烦,也可以在此处下载,作者把需要导入的包也一并上传。
你可以再这里下载代码。
如果你没有下载积分,可以再下发留下邮箱,作者看到会第一时间发送给你。
作者码字不易,如果你觉得好的话,记得点赞。
最后还要感谢Eddie_Ivan大佬,没有他的文章的帮助,作者突破不了关键的难点。