我们学校教务处的地址是:http://jwc.ecjtu.jx.cn/ ,往常每次我们获取成绩都需要先进入教务处,然后点击成绩查询,输入公共的账号密码进入,最后输入相关信息获取成绩表格,这里登陆不需要验证码省了我一番功夫,这样我们先进入成绩查询系统登陆界面,先看看怎么模拟登陆这个过程,在Chrome浏览器下按F12打开开发者面板:
这里我们学校的教务处查询系统的密码是公共的jwc也就是拼音缩写,我们输入用户名和密码点击登陆,这时候注意POST请求:
发现了什么,好像Chrome并没有把Post提交的表单信息保留下来直接跳转到了另一个界面然后展示另一个界面的数据,这里就需要我们自己动手操作一下,注意开发者面板左上角的小红点表示这时候正在抓取数据,如果点击一下就会变成灰色,就可以变相地保存下当时抓取到的包,我在点击登陆后新界面未刷新出来之前点击了这个小红点,如愿以偿的得到了Post的表单数据:
这样就获取了浏览器在登陆时候向服务器传递的表单数据,看一下这个表单都有些什么:
这里看到我们需要传递三个参数,分别是:user、pass、Submit,可以很容易的理解这几个单词的字面意思,这样有了思路,我们就可以写出这次代码的第一步:模拟登陆教务处
直接上代码:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import requests
url = 'http://jwc.ecjtu.jx.cn/mis_o/login.php'
datas = {'user': 'jwc',
'pass': 'jwc',
'Submit': '%CC%E1%BD%BB'
}
headers = {'Referer': 'http://jwc.ecjtu.jx.cn/mis_o/login.htm',
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 '
'(KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
'Accept-Language': 'zh-CN,zh;q=0.8',
}
sessions = requests.session()
response = sessions.post(url, headers=headers, data=datas)
print(response.status_code)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
代码输出:
200
- 1
说明我们模拟登陆成功了,这里用到了Requests模块,还不会使用的可以查看中文文档 ,它给自己的定义是:HTTP for Humans,因为简单易用易上手,我们只需要传入Url地址,构造请求头,传入post方法需要的数据,就可以模拟浏览器登陆了,这里因为有进一步获取成绩的操作所以使用了session来保持连接,这里单看最后的返回码的话我们是成功了的,具体如何还要看下一步操作,接下来:
这里为了简便代码我们设定输入学号查询所有成绩,减少其他判断,同样对Post数据进行抓包:
同样查看Post的数据:
因为这里就分析输入学号的情况所以其他都为空,这样我们就可以写出查询成绩的代码:
score_healders = {'Connection': 'keep-alive',
'User - Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) '
'AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36',
'Content - Type': 'application / x - www - form - urlencoded',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
'Content - Length': '69',
'Host': 'jwc.ecjtu.jx.cn',
'Referer': 'http: // jwc.ecjtu.jx.cn / mis_o / main.php',
'Upgrade - Insecure - Requests': '1',
'Accept - Language': 'zh - CN, zh;q = 0.8'
}
score_url = 'http://jwc.ecjtu.jx.cn/mis_o/query.php?start=' + str(
pagenum) + '&job=see&=&Name=&Course=&ClassID=&Term=&StuID=' + num
score_data = {'Name': '',
'StuID': num,
'Course': '',
'Term': '',
'ClassID': '',
'Submit': '%B2%E9%D1%AF'
}
score_response = sessions.post(score_url, data=score_data, headers=score_healders)
content = score_response.content
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
这里解释一下上面的代码,上面的score_url
并不是浏览器上显示的地址,我们要获取真正的地址,在Chrome下右键–查看网页源代码,找到这么一行:
a href=query.php?start=1&job=see&=&Name=&Course=&ClassID=&Term=&StuID=xxxxxxx
- 1
这个才是真正的地址,点击这个地址转入的才是真正的界面,因为这里成绩数据较多,所以这里采用了分页显示,这个start=1
说明是第一页,这个参数是可变的需要我们传入,还有StuID
后面的是我们输入的学号,这样我们就可以拼接出Url地址:
score_url = 'http://jwc.ecjtu.jx.cn/mis_o/query.php?start=' + str(pagenum) + '&job=see&=&Name=&Course=&ClassID=&Term=&StuID=' + num
- 1
同样使用Post方法传递数据并获取响应的内容:
score_response = sessions.post(score_url, data=score_data,headers=score_healders)
content = score_response.content
- 1
- 2
这里采用Beautiful Soup 4.2.0来解析返回的响应内容,因为我们要获取的是成绩,这里到教务处成绩查询界面,查看获取到的成绩在网页中是以表格的形式存在:
观察表格的网页源代码:
<table align=center border=1>
<tr><td bgcolor=009999>学期</td>
<td bgcolor=009999>学号</td>
<td bgcolor=009999>姓名</td>
<td bgcolor=009999>课程</td>
<td bgcolor=009999>课程要求</td>
<td bgcolor=009999>学分</td>
<td bgcolor=009999>成绩</td>
<td bgcolor=009999>重考一</td>
<td bgcolor=009999>重考二</td></tr>
...
...
</tr></table>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
这里拿出第一行举例,虽然我不太懂Html但是从这里可以看出来<tr>
代表的是一行,而<td>
应该是代表这一行中的每一列,这样就好办了,取出每一行然后分解出每一列,打印输出就可以得到我们要的结果:
from bs4 import BeautifulSoup
soup = BeautifulSoup(content, 'html.parser')
# 找到每一行
target = soup.findAll('tr')
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
# 判断是否登陆在模拟登陆操作后增加一个判断:
def isLogin(num):
return_code = response.status_code
if return_code == 200:
if re.match(r"^\d{14}$", num):
print('请稍等')
else:
print('请输入正确的学号')
return True
else:
return False
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
最后在__main__
中这么调用:
if __name__ == '__main__':
num = input('请输入你的学号:')
if isLogin(num):
getScore(num, pagenum=0, i=0, j=0)
getScore(num, pagenum=1, i=31, j=0)
getScore(num, pagenum=2, i=62, j=0)