使用python爬取方正教务系统的成绩 出成绩后发短信 发邮件(二)

刚才我们已经通过爬虫登录到了教务系统。那么下一步就是去爬取成绩,然后解析,并且执行自己对应的操作了。

那我们第一步,就是打开成绩地址。我们首先看看页面。

我们看到了是这个地址。那我们复制到浏览器,看看需要传递什么参数。

我们需要的就是这个成绩页面,下面是获取成绩的请求。我们打开看看。

参数如下,有一个__VIEWSTATE,这个东西,好像很熟悉,因为登录用过,但是仔细看看,好像不是之前的值,那么我们回想,这个登陆时候好像是登陆页面源码里面一个随机值,用来验证,那我们这个页面是不是也是教务系统那个页面里面的一个随机值呢?我们来看看。

我们打开源码看了看,发现好像还是登录页面那个随机值,那说明有问题,那我们肯定漏了什么东西,我们再去想想。 我们再看教务系统,我们是直接复制那个页面,然后去获取成绩,但是缺少了一个随机值,说明有个存储随机值的页面我们漏了。我们再看那个获取成绩地址。

http://jwxt.i.cqut.edu.cn/(zjvt0pbh4icfjs451vcybs45)/xscjcx_dq.aspx?xh=11503080431&xm=%C0%EE%C7%EC%CD%FA&gnmkdm=N121607

我们直接打开地址看看。

长这个样子。但是我们没有点击学年学期那个查询按钮。那我们看看这个页面源码。有没有那个随机值。

发现了!说明这个是存储随机值的页面。但是好像跟我们获取指定学期成绩是一个页面啊,那我们访问这个页面不也需要这个随机值吗?那我们怎么通过爬虫获取这个页面去获取随机值?这不是矛盾的吗? 那我们看看这个页面访问需要什么参数。

这个好像是默认页面,不需要传递那个随机值。然后在查询不同学期的时候才需要传递那个随机值。那么我们就有思路了。 首先去通过定值,访问这个页面,然后获取到这个页面的随机值。保存下来,去获取某一学期的成绩。 我们看上方图,有一个xm,他的值是(unable to decode value),跟以前一样,点击一下右上角,view URL encoded,

全部是定值。再看看查询某一学期的请求参数。

转义后,除了那个__VIEWSTATE需要我们获取,其他的全部是定值。

那我们来捋一下思路。如何用python获取成绩。

1.首先获取http://jwxt.i.cqut.edu.cn/(随机值)/xscjcx\_dq.aspx?xh=11503080431&xm=%C0%EE%C7%EC%CD%FA&gnmkdm=N121607这个地址

2.我们传参xh,xm,gnmkdm,去访问

3.我们去获取__VIEWSTATE这个值

4.再去访问http://jwxt.i.cqut.edu.cn/(随机值)/xscjcx\_dq.aspx?xh=11503080431&xm=%C0%EE%C7%EC%CD%FA&gnmkdm=N121607这个地址

5.我们传参__VIEWSTATE,和一些定值

6.获取到成绩进行解析

以下是全部代码,包含上面登录的代码:

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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
#-*-coding:utf-8-*- 
import os
import re from lxml
import etree
import requests
import sys from bs4
import BeautifulSoup
import smtplib from email.mime.text
import MIMEText
import threading
import time from qcloudsms\_py
import SmsSingleSender from qcloudsms\_py.httpclient
import HTTPError
#访问教务系统,前面分析过了,提交数据时要用这个值。先得到\_\_VIEWSTATE的值。
s = requests.session()
url = "http://jwxt.i.cqut.edu.cn"
response = s.get(url)
#获取到有随机值的地址
newUrl = response.url
#获取\_\_VIEWSTATE值
selector = etree.HTML(response.content)
\_\_VIEWSTATE = selector.xpath('//*\[@id="form1"\]/input/@value')\[0\]
#获取验证码
imgUrl = newUrl.replace('Default2.aspx','CheckCode.aspx')
imgresponse = s.get(imgUrl, stream=True)
image = imgresponse.content
#保存验证码
if os.path.exists(r'f://yanzheng.jpg'): os.remove(r'f://yanzheng.jpg') with open(r'f://yanzheng.jpg','wb')as f: f.write(image) f.close()
#打开验证吗
os.startfile(r'f:yanzheng.jpg')
#手动输入验证码
code = input("输入弹出的验证码: ")
#构造参数
data={
'\_\_VIEWSTATE':\_\_VIEWSTATE,
'txtUserName':'学号',
'TextBox2':'密码',
'txtSecretCode':code,
'RadioButtonList1':'%D1%A7%C9%FA',
'Button1':"",
'lbLanguage':'',
'hidPdrs':'',
'hidsc':'',
}
#提交表头,里面的参数是电脑各浏览器的信息。模拟成是浏览器去访问网页。
headers={
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36'
}
#登陆教务系统
response = s.post(newUrl,data=data,headers=headers)
#第一次访问获取成绩页面的参数 d
ata1={ 'xh':'11503080431', 'xm':'%C0%EE%C7%EC%CD%FA', 'gnmkdm':'N121607' }
#提交表头,里面的参数是电脑各浏览器的信息。模拟成是浏览器去访问网页。
#这里添加了一个Referer,这里又是网站一个验证,不添加会无法访问
headers1={ 'Referer':response.url , 'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36' }
#访问地址
response = s.get(newUrl.replace('Default2.aspx','xscjcx\_dq.aspx?xh=11503080431&xm=%C0%EE%C7%EC%CD%FA&gnmkdm=N121607'),data=data1,headers=headers1)
content1 = response.content.decode('gb2312')
#获取\_\_VIEWSTATE值
selector = etree.HTML(content1) \_hhh = selector.xpath('//*\[@id="Form1"\]/input/@value')\[2\]
#第二次访问的参数
data2={ '\_\_EVENTTARGET':'', '\_\_EVENTARGUMENT':'', '\_\_VIEWSTATE':\_hhh, 'ddlxn':'2017-2018', 'ddlxq':'2', 'btnCx':'+%B2%E9++%D1%AF+' }
#通过QQ邮箱发邮件
def sendMail(grade):
#发件地址
\_user = "302657615@qq.com"
#打开qq邮箱,点击设置->账户,找到POP3/IMAP/SMTP/Exchange/CardDAV/CalDAV服务,开启IMAP/SMTP服务,然后根据要求使用手机发送到指定号码,获取授权码,这个授权码填在这里
\_pwd = "授权码"
#收件地址
\_to = "302657615@qq.com"
msg = MIMEText("出分啦!!考了 " + grade) msg\["Subject"\] = "出分啦!!考了 " + grade msg\["From"\] = "wangyezaici"
msg\["To"\] = \_to
s = smtplib.SMTP\_SSL("smtp.qq.com", 465)
s.login(\_user, \_pwd)
s.sendmail(\_user, \_to, msg.as\_string())
s.quit()
#通过腾讯云发短信
def sendSms(a, b):
#自行配置
appid = ;
appkey = "";
phone\_numbers = \[""\];
template\_id = ;
ssender = SmsSingleSender(appid, appkey)
params = \[a, b\]
try:
result = ssender.send\_with\_param(86, phone\_numbers\[0\], template\_id, params)
except HTTPError as e:
print(e) except
Exception as e:
print(e)
print(result)
#定时器 每三分钟查询成绩,如果出成绩给自己发邮件,发短信
def fun\_timer():
#第二次访问
response = s.post(newUrl.replace('Default2.aspx','xscjcx\_dq.aspx?xh=11503080431&xm=%C0%EE%C7%EC%CD%FA&gnmkdm=N121607'),data=data2,headers=headers1)
#获取内容
content2 = response.content.decode('gb2312')
#解析
soup = BeautifulSoup(content2, 'lxml')
#打印当前时间
print(time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time())))
#这里是解析成绩,不同教务系统可能不一样
tables = soup.findAll('table')
tab = tables\[1\]
trs = tab.findAll('tr')
del trs\[0\]
for tr in trs:
tds = tr.findAll('td')
#遍历出现成绩的所有科目 查询是否出现了自己想要查询的科目
if tds\[3\].string.find("编译") != -1:
#打印成绩,发短信,发邮件
print(tds\[3\].string + "考了" + tds\[11\].string)
sendMail(tds\[11\].string)
sendSms(tds\[3\].string, tds\[11\].string)
sys.exit()
global timer
#每三分钟查询一次
timer = threading.Timer(180, fun\_timer)
timer.start()
timer = threading.Timer(1, fun_timer)
timer.start()

这里有两个需要注意的地方,一个是那个模拟请求头headers。我们在登录的时候使用的如下。 [python] headers={ ‘User-Agent’:’Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36’ } [/python] 但是在获取成绩那个页面一直无法访问成功,一直报错并跳出。发现不了问题,然后详细看了一下参数,才发现学校这个还做了验证,还需要传递Referer这个值。还是比较狗的。登陆页面,我们查看登录请求参数的头里也是有这个Referer,但是爬虫里不写却可以登陆成功,获取成绩那里就不行,这里当时花了很多时间。感觉我们学校这个还是很多小手段验证的。 一个就是成绩页面的解析,我们看一下这个系统成绩页面的源码。

每个页面可能结构不一样,这里在解析的时候进行多次尝试即可。思路就是去获取table,然后获取tr,再遍历每个td,重要的值就是两个,一个是课程名,用来判断出成绩的科目,然后还有就是成绩。


# Python

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×