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

3个月前 (05-08) wang 技术杂谈 0评论 已收录 201℃ 浏览数:157

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

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


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


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


参数如下,有一个__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.获取到成绩进行解析

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

#-*-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)

#第一次访问获取成绩页面的参数
data1={  
    '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。我们在登录的时候使用的如下。

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'
} 

但是在获取成绩那个页面一直无法访问成功,一直报错并跳出。发现不了问题,然后详细看了一下参数,才发现学校这个还做了验证,还需要传递Referer这个值。还是比较狗的。登陆页面,我们查看登录请求参数的头里也是有这个Referer,但是爬虫里不写却可以登陆成功,获取成绩那里就不行,这里当时花了很多时间。感觉我们学校这个还是很多小手段验证的。

一个就是成绩页面的解析,我们看一下这个系统成绩页面的源码。


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

博主

Just do it. Now or never.

相关推荐

嗨、骚年、快来消灭0回复。