假期在家里歇着,题不想刷,机器学习慕课看着无聊。。想起上学的时候给同学吹逼:“爬虫不用学,Google一下就会了”,于是决定靠着网上的资料把学校教务爬一爬。
第一步是登陆,一直觉得学校教务系统登陆反人类。。之前输错密码还有一些提示,现在干脆整个网页没什么变化,加个感叹号图片就完事了。
通过检测网页上这个感叹号,就可以知道我们是否登陆成功了。
然后我们用chrome浏览器的调试功能看一下登陆的逻辑。。。神奇的发现:
至此,整个登陆的逻辑非常的显然了。。首先访问首页获取验证码和cookies,然后按格式向jwLoginAction.do 直接post学号和密码,就登陆成功了。
实现方面,我使用了python3.7 配合requests库来模拟登陆操作。
验证码:使用requests.get获取验证码图片,再用Image库打开,人眼看一下验证码。
cookies获取: 调用 requests.get 获取 response ,response.cookies即为获取到的cookies。
post登陆:将要发送的信息写成键-值形式,然后调用requests.post(url,data=postData,cookies=cookies) 注意带上cookies登陆。之后检查post结果,如果返回200则为正常(并不是登录成功,只是网络通信正常)
最后检查返回的网页,是否为登陆后的教务系统即可。
勉为其难的贴一下代码。。。太丑了。。(有参考github上的代码)实现了一个获取成绩并取平均数的功能。
import requests import http.cookiejar import io import sys import time import json import getopt import getpass from PIL import Image from io import BytesIO from requests_html import HTML from json import encoder url="https://jwxt.bupt.edu.cn/" cookies = None headers=\ { "User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36", "Referer":"https://jwxt.bupt.edu.cn/", "Connection":"keep-alive", "Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8", "Accept-Encoding":"gzip, deflate", "Accept-Language":"zh-CN,zh;q=0.8", "Upgrade-Insecure-Requests":"1", "Cache-Control":"max-age=0", } def login(): flag=1 cnt=0 while flag==1: cnt=cnt+1 print("第",cnt,"次尝试") print("开始获取验证码") captcha_response=requests.get(url+'validateCodeAction.do?random=',cookies=cookies) if captcha_response.status_code!=requests.codes.ok: print("获取验证码失败,是否重新获取?") req=input("请输入1或2 1:是 2:否 ") if req==0: exit(0) else: continue print("获取验证码成功") captcha_origin=Image.open(BytesIO(captcha_response.content)) captcha_origin.show() yzm=input('请输入验证码: ') zjh=input('请输入学号') mm=input('请输入密码') postData=\ { "type":"sso", "zjh": zjh, "mm": mm, "v_yzm":yzm } login_response=requests.post(url+'jwLoginAction.do',data=postData,cookies=cookies) if login_response.status_code==requests.codes.ok: print("发送请求成功") else: print("由于网络问题发送请求失败,准备重试.....") index=login_response.text print(index) if index.find("alert.gif")!=-1: print("登录失败,可能是账号、密码或验证码错误") else: print("登陆成功") break def to_float(s): try: return float(s) except ValueError: return s def get_grade(): grade_response=requests.get(url+'gradeLnAllAction.do?type=ln&oper='+'fa',cookies=cookies) html=HTML(html=grade_response.text) grade_response=requests.get(url+html.find('iframe', first=True).attrs['src'],cookies=cookies) table=HTML(html=grade_response.text) keys=[] for i in range(1,8): keys.append(table.xpath('table[last()]/tr/td/table[1]/thead/tr/th[' + str(i) + ']')[0].text) result=[] last_course=table.xpath('table[last()]/tr/td/table[1]/tr[last()]')[0] course_index=1 while True: current_course = table.xpath('table[last()]/tr/td/table[1]/tr[' + str(course_index) + ']')[0] values = [] for i in range(1, 8): if i == 5 or i == 7: values.append(to_float(current_course.xpath('tr/td[' + str(i) + ']')[0].text)) else: values.append(current_course.xpath('tr/td[' + str(i) + ']')[0].text) result.append(zip(keys,values)) if current_course.element==last_course.element: break course_index +=1 return result def get_avg(result): ans=0.0 all_points=0.0 for res in result: points=0.0 mark=0.0 flag=1 for (k,v) in res: if k=="成绩" and isinstance(v,float)==1: mark=points*v if k=="学分": points=v if k=="课程属性" and v=="选修": flag=0 if flag==1: ans+=mark all_points+=points return ans/all_points if __name__ == '__main__': response=requests.get(url,headers=headers) cookies=response.cookies login() res=get_grade() print(get_avg(res))