恭喜各位同学!当你看到这篇文章的时候,意味着你已经从刚开始的“一无所知”,变成了现在的“爬虫新手”!在之前的文章中,我们从最基础的知识点讲起,一步一步的学习了怎么使用Python爬取我们想要获取的信息,在这期间,我们也穿插着学习了HTML、Linux、Ajax等技术。
从本章开始,我们将开发我们最后的实践程序——成绩短信通知服务。相对应的,各位同学可以在本课程的Github页面上获取到对应的代码。
注意!因为每个院校的教务系统并不是统一的,本门课程只能选择最广泛使用的某方教务系统,因此可能并不能适配你所在的学校。但是,技术是相同的。相信我,跟着我学习完这两章的课程后,你一定会庆幸你学校的教务系统不会是教程中的系统——事实上,某方的反爬虫技术和代码格式让我在开发的过程中苦不堪言,甚至一度想放弃。庆幸的是,通过不懈的努力,这两篇文章终于能够和之前计划的一样,展现在你们的眼前。废话不多说,让我们直接开始!
首先我们需要分析登录系统所要传递的参数,如下图所示,我们在的登录的时候,需要输入的参数有:用户名、密码、验证码以及选择学生
。
但是,事实的确如此吗?很显然,是错误的!我们在上一章节已经讲过:除了上述我们需要填写的显性内容外,我们还需要传递一个证明自己身份的_VIEWSTATE
。那么,什么是_VIEWSTATE
呢?
_VIEWSTATE
是ASP.NET的一个控件。如果在客户端和服务器段保持往返的状态,在.net中通过加入一个隐藏控件_ViewState来实现的,这些状态的保持不需要程序员来控制,节省了程序员的精力。
那么, _VIEWSTATE
参数究竟在哪里能够发现呢?很简单,就在网页的源代码中!
让我们把它解析出来:
import requests
from bs4 import BeautifulSoup
url = "target_url"
rensponse = requests.get(url)
soup = BeautifulSoup(rensponse.text,'lmxl')
_VIEWSTATE = soup.find('input', attrs={'name': '__VIEWSTATE'})['value']
通过使用上个章节介绍的fiddler4 ,我们可以确定登录系统需要传递以下的参数:
_VIEWSTATE
:.Net框架用来标记用户身份的控件
TextBox1
:学号参数
TextBox2
:密码参数
TextBox3
:验证码
RadioButtonList1
:学生标记
Button1
:空值
lbLanguage
:空值
事实上,某方教务系统存在不通过验证码即可登录的界面,我在调试的过程中,也一直在使用该页面。但是为了让开发具有普遍性,因此本门默认使用了带有验证码的登录网页。
正如我在上面提到的那样,因为验证码是需要人工输入的,因此在开发的过程中,我们首先将网页中的验证码图片下载到本机,然后采用人工输入的方式,保证准确性。
注意:后续将提供基于机器学习的验证码识别模型,减少人工输入步骤
so,登录所需要的参数都明白了,让我们直接开发吧!
import requests
from bs4 import BeautifulSoup
username='你的用户名'
password='你的密码'
url = 'targeturl'
HEA = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/'
'537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36',
}
response = requests.get(url,HEA)
if response.status_code=='OK':
soup = BeautifulSoup(response.text,'lxml')
else:
hash_url = response.headers['Content-Type']
url = 'targeturl'
response = requests.get(url,HEA)
soup = BeautifulSoup(response.text, 'lxml')
viewState = soup.find('input', attrs={'name': '__VIEWSTATE'})['value']
RadioButtonList1 = u"学生".encode('gb2312','replace')
imgUrl = "targeturl"
imgresponse = s.get(imgUrl, stream=True)
image = imgresponse.content
DstDir = os.getcwd()+"\\"
print("保存验证码到:"+DstDir+"code.jpg"+"\n")
try:
with open(DstDir+"code.jpg" ,"wb") as jpg:
jpg.write(image)
except IOError:
print("IO Error\n")
finally:
jpg.close
#手动输入验证码
code =input("验证码是:")
data = {
'__VIEWSTATE':viewState,
'TextBox1':username,
'TextBox2':password'
'RadioButtonList1':RadioButtonList1,
'Button1':''
}
web_data = requests.post(url=url,data=data,headers=HEA)
print(web_data.text)
运行代码,首先输入我们下载到本地的验证码,然后回车,验证是否登录系统:
Bingo!我们成功进入到了教务系统中!
####分析成绩页面
让我们分析一下成绩的URL:
在成绩的URL中,我们需要注意以下几个参数:
xh
:学生用户名
xm
:学生姓名的URL编码
其中xm
是通过对学生姓名进行URL编码后得到的字符串。你可以在这个网址验证编码前的信息。
举个例子,有个男生,名字叫“小强”,我们使用URL编码工具对其进行编码,其对应编码后的字符串为%e5%b0%8f%e5%bc%ba
。
解释完参数的含义,让我们选取2016-2017年度第二学期的成绩,使用fiddler4 获取服务器的数据传输详情:
同样的,我们还是需要分析一下传输的参数:
_VIEWSTATE
:.Net框架用来标记用户身份的控件
_VIEWSTATEGENERATOR
:默认即可
ddlXN
:选择学年
ddlXQ
:选择的学期
Button1
:空置
其中_VIEWSTATE
也是可以从网页中获取到的,ddlXN
和ddlXQ
是我们选择的学年和学期。
因为某方的验证手段,我们必须模拟浏览器header,同时加上Referer
参数,Referer
参数就是我们所在的成绩页面的URL
让我们开始写代码:
chengji_page = 'http://xxxx.xxxx.edu.cn/xscj_gc.aspx?xh=xxxxxxxx&xm=%e5%b0%8f%e5%bc%ba&gnmkdm=N121605'
header = {
'Referer':''http://xxxx.xxxx.edu.cn/xscj_gc.aspx?xh=xxxxxxxx&xm=%e5%b0%8f%e5%bc%ba&gnmkdm=N121605',
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.110 Safari/537.36'
}
response = s.get(chengji_page,headers=header)
__VIEWSTATE= get_view(response)
data1 = {
"__VIEWSTATE":__VIEWSTATE,
"ddlXN":"2016-2017",
"ddlXQ":"2",
"Button1":""
}
chengji = s.post(chengji_page,data=data1)
print(chengji.text)
让我们运行该段代码:
一切显示正常!我们已经获取到了所对应的成绩!接下来,我们需要解析网页,并且将成绩存入数据库中,同时拼接好之前的接口。虽然步骤很多,但是都是我们之前学到的内容,因此,让我们下章将成绩短息通知服务正式完成吧!
登录
和获取成绩
步骤,这两个步骤是我们开发中最重要的过程,因此同学们有不理解或者不明白的地方,一定要在讨论区发表自己的看法!