一个新手用python爬武汉理工大学教务系统
学了一点python感觉想写点东西练练手,python想到的第一个事情就是爬虫,复杂的网站不会爬一直想找简单又有趣的网站爬玩玩,最后想到学校的教务系统挺不错的就…抢课的时候(邪恶)。。。。。废话不多说直接开始
首先就是登陆教务系统,打开教务系统,打开开发者模式,用自己的账号密码登陆观察后台提交的数据。
找到login文件点开看,会发现url和提交的表单信息。。。嘿嘿直接copy过来就可以
关键技术,点开其他的会发现后面访问的页面都要携带登陆的cookie,百度了一下方法,有可以直接复制手动登陆后返回的cookie的但是每次登陆都会返回不同的cookie,每次都要手动登陆一下复制cookie过去,还不如手动登陆算程序的优势就没有了。后面找到了一个好的方法创建opener自动携带cookie打开其他页面。美滋滋。。。。。
方法如下:
# 创建cookie对象保存cookie
cookie = cookiejar.CookieJar()
# 创建一个cookie处理器
headler = urllib.request.HTTPCookieProcessor(cookie)
# 用处理器创建opener,之后opener就携带cookie访问啦
opener = urllib.request.build_opener(headler)
果真有如此神奇的方法。。。。。
然后还是习惯性的建立一下header来伪装浏览器发出的请求
header = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.\
84 Safari/537.36'
}
再建立一下登陆要提交的数据表单,直接copy上图过来就欧了。。。。。
data = {
'systemId':'',
'xmlmsg':'',
'userName': userName,
'password': password,
'type': 'xs'
}
post_data = urllib.parse.urlencode(data).encode('utf-8')#要编码
然后直接用这些数据创建请求。。。。。完事
#登陆请求的url直接copy上图里面的
login_url = 'http://sso.jwc.whut.edu.cn/Certification/login.do'
request_data = urllib.request.Request(login_url, headers=header, data=post_data)
response = opener.open(request_data)
返回一个response数据体,之后解析出来找要找的连接
解析模块很多用自带的HTMLParse也行,不过python当然要用强大的第三方模块啦,beautifulsoup广受好评,用起来是真的方便,好评不是刷的,本来想在这里练习一下正则表达式的不过这个模块真的好用的我都忍不住用了练习正则表达式的心都没了。。。。。
直接上代码
html =BeautifulSoup(response, 'html.parser')
用BeautifulSoup里的函数寻找成绩查询,选课等连接
这里以成绩查询为例子
打开相应体找应该是在图示的a标签里,不确认可以点那个链接看看
直接调函数查找取出链接
mark_url = html.find(title="成绩、绩点查询")['href']
然后发现这个url返回的响应体不是要找的成绩单。。。。再点开成绩查询看看。。。找到响应体就是要找的成绩单。。。。。。看一下相应的地址和提交的数据,发现地址后面那堆诡异的字符点一次变一次,应该是某次相响应服务返回过来的诡异验证码,翻翻前面没有成绩那个响应体果然是那里
当然是用代码把它取出来啦
mark_url = html.find(title="成绩、绩点查询")['href']
req = urllib.request.Request(mark_url, headers=header)
resp1 = opener.open(req)
html2 = BeautifulSoup(resp1, 'html.parser')
snkey = html2.find('a', target="navTab",text="成绩查询")['href']
可是怎么也找不到后面那堆点一次变就变得数字,而且那堆数字在哪页都有选课什么得都带那堆一直变化得数字,刷新也在变,想想会不会是代表访问次数的,最后验证都不是,想过和时间变化的,然后算了一下每隔相同的时间数字的变化量一样,所以应该是和时间有关系的,但是怎么也找不到相对应的关系,后来发现好像不用提交那个数据也可以访问,所以就没有再找那堆数的规律。
点成绩那会发现显示不完所有的成绩,所以还要提交一个显示页面数的数据
直接copy到程序
data2 = {
'pageNum': '1',
'numPerPage': '200',
'xh': 'userName',
'snkey': snkey
}
post_data2 = urllib.parse.urlencode(data2).encode('utf-8')
url2 = 'http://202.114.90.180/Score/' + snkey
req2 = urllib.request.Request(url2, headers=header, data=post_data2)
resp2 = opener.open(req2)
响应体就是要找的成绩单,最后还是用BeautifulSoup解析出来分离出每一科成绩打印出来完事。。。。。。。。成绩查询完毕
html3 = BeautifulSoup(resp2, 'html.parser')
for i in range(len(html3.thead.tr.find_all('th'))):
mat = "{:12}"
print(mat.format(html3.thead.tr.find_all('th')[i].string), end='')
print("\n")
for j in range(len(html3.tbody.find_all('tr', target="sid_cj_id"))):
for k in range(len(html3.tbody.find_all('tr', target="sid_cj_id")[j].find_all('td'))):
if html3.tbody.find_all('tr', target="sid_cj_id")[j].find_all('td')[k].string == None:
html3.tbody.find_all('tr', target="sid_cj_id")[j].find_all('td')[k].string =''
mat = "{:12}"
print(mat.format(html3.tbody.find_all('tr', target="sid_cj_id")[j].find_all('td')[k].string), end='')
print("\n")
总结果
选课的话和前面一样找到连接和关键参数就可以了
在选课的时候提交的有一个数据来源是要用到后端js传来的,数据没看到js也就不怎么会了,,,,,,,,,
addid这个数据是JS传过来的,其他的都可以在前面找得到,解析出来用就可以。
感觉学校教务处的网是故意简单设计让新手练手的吧。。。哈哈。。。。
完整代码
密码错误就运行错误,没空写验证正确性了
import urllib.request
import urllib.parse
from bs4 import BeautifulSoup
from http import cookiejar
def login(header):
userName = input('输入学号回车')
password = input('输入密码回车')
data = {
'systemId': '',
'xmlmsg': '',
'userName': userName,
'password': password,
'type': 'xs'
}
post_data = urllib.parse.urlencode(data).encode('utf-8')
login_url = 'http://sso.jwc.whut.edu.cn/Certification/login.do'
request_data = urllib.request.Request(login_url, headers=header, data=post_data)
cookie = cookiejar.CookieJar()
headler = urllib.request.HTTPCookieProcessor(cookie)
opener = urllib.request.build_opener(headler)
response = opener.open(request_data)
html =BeautifulSoup(response, 'html.parser')
return opener, html
def get_mark(opener,html,header):
mark_url = html.find(title="成绩、绩点查询")['href']
req = urllib.request.Request(mark_url, headers=header)
resp1 = opener.open(req)
html2 = BeautifulSoup(resp1, 'html.parser')
snkey = html2.find('a', target="navTab",text="成绩查询")['href']
data2 = {
'pageNum': '1',
'numPerPage': '200',
'xh': '0121604970404',
'snkey': snkey
}
post_data2 = urllib.parse.urlencode(data2).encode('utf-8')
url2 = 'http://202.114.90.180/Score/' + snkey
req2 = urllib.request.Request(url2, headers=header, data=post_data2)
resp2 = opener.open(req2)
html3 = BeautifulSoup(resp2, 'html.parser')
for i in range(len(html3.thead.tr.find_all('th'))):
mat = "{:12}"
print(mat.format(html3.thead.tr.find_all('th')[i].string), end='')
print("\n")
for j in range(len(html3.tbody.find_all('tr', target="sid_cj_id"))):
for k in range(len(html3.tbody.find_all('tr', target="sid_cj_id")[j].find_all('td'))):
if html3.tbody.find_all('tr', target="sid_cj_id")[j].find_all('td')[k].string == None:
html3.tbody.find_all('tr', target="sid_cj_id")[j].find_all('td')[k].string =''
mat = "{:12}"
print(mat.format(html3.tbody.find_all('tr', target="sid_cj_id")[j].find_all('td')[k].string), end='')
print("\n")
def select_course(opener, html, header):
course_url = html.find(title="学生选课及选课结果查询、教师查询选课名单及回复学生、学院回复学生咨询")['href']
req3 = urllib.request.Request(course_url, headers=header)
resp3 = opener.open(req3)
html2 = BeautifulSoup(resp3, 'html.parser')
gxkxk = html2.find(href="gxkxk.do?xnxq=2018-2019-1")['href']
gxkxk_url = 'http://202.114.90.180/Course/' + gxkxk
req4 = urllib.request.Request(gxkxk_url, headers=header)
resp1 = opener.open(req4)
print(resp1.read().decode('utf-8'))
header = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.\
84 Safari/537.36'
}
opener, html = login(header)
get_mark(opener, html, header)
#select_course(opener, html, header)
结束