Python教务系统爬虫

1.前期准备

1.1缘由

某天发现正方教务系统突然升级了,以我们学校江南大学为例:
这里写图片描述

原先有一个BUG访问http://202.195.144.163/jndx/**default3**.aspx 可以直接跳过验证码,出现的就是仅仅是用户名和密码一个简洁的框子,现在已经被修复了

所以就必须解决验证码的问题了!

基本思路有几个:

  • 将验证码下载到本地,手工输入验证码
  • 采用验证码的ocr识别算法进行自动破解验证码(经测试识别率太低)
  • 通过网络上的验证码识别接口(收费)

所以最后采用的还是手工输入了。

看了一下超级课程表的解决方案,也是一样的,手工输入验证码
这里写图片描述

1.2需要的工具

  • chrome浏览器 F12可以很方便的观察网页交互
  • fiddler 网络抓包工具
  • 使用python开发需要装几个包:1.re 正则表达式 2.requests 强大的网络包 3.lxml xpath的依赖

2.开始爬虫

2.1登陆教务系统

2.1.1基本思路

开启一个session,完成下面的爬虫工作。确保每次的cookie保持一致。先抓取教务系统首页,然后再一次单独抓取验证码,模拟正常在浏览时看不清验证码刷新一次。将获取的验证码并下载到本地,然后填写验证码,一起将登陆数据post过去,实现登陆。

###2.1.2登陆分析

  1. 通过审核元素观察到验证码的地址是:http://202.195.144.163/jndx/CheckCode.aspx?
    这里写图片描述
  1. 网页登陆查看post数据内容

这里写图片描述

参数说明:

  • __VIEWSTATE:dDwtMTMxNjk0NzYxNTs7Pv+4BrjArC82wBF5MVEk+YUeOI7j

这是.Net框架特有的一个东西,会变化可以从html的源代码中找到这个值
这里写图片描述

  • TextBox1:1030614418

学号参数

  • TextBox2:342626199509064718

密码参数

  • TextBox3:icdc

验证码

  • RadioButtonList1:(unable to decode value)

这个在rawdata里面是%D1%A7%C9%FA 这个是url编码以后的,反url编码转出来的是 学生
这里写图片描述

  • Button1:
  • lbLanguage:

这两个参数均为空值

2.1.3代码实现

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
# author: HuYong
#-*-coding:utf-8-*-
import os
import re
from lxml import etree
import requests
import sys
#设置编码
reload(sys)
sys.setdefaultencoding( "utf-8" )
#初始参数
studentnumber = "1030614418"
password = "342626199509064718"
#访问教务系统
s = requests.session()
url = "http://202.195.144.163/jndx/default2.aspx"
response = s.get(url)
# 使用正则表达式获取 __VIEWSTATE
# __VIEWSTATE = re.findall("name=\"__VIEWSTATE\" value=\"(.*?)\"",response.content)[0]
# 使用xpath获取__VIEWSTATE
selector = etree.HTML(response.content)
__VIEWSTATE = selector.xpath('//*[@id="form1"]/input/@value')[0]
#获取验证码并下载到本地
imgUrl = "http://202.195.144.163/jndx/CheckCode.aspx?"
imgresponse = s.get(imgUrl, stream=True)
print s.cookies
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 = raw_input("验证码是:")
#构建post数据
RadioButtonList1 = u"学生".encode('gb2312','replace')
data = {
"RadioButtonList1":RadioButtonList1,
"__VIEWSTATE":__VIEWSTATE,
"TextBox1":studentnumber,
"TextBox2":password,
"TextBox3":code,
"Button1":"",
"lbLanguage":""
}
headers = {
"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.post(url,data=data,headers=headers)
print "成功进入教务系统!"

这里写图片描述

这里写图片描述

2.2获取教务信息

  • 登陆教务系统后就可以爬取教务系统上的所有信息了。

这里写图片描述

这是登陆后的首页,可从这里提取姓名和学号信息。通过xpath从html中提取即可。

1
2
3
4
5
6
7
8
9
10
11
12
def getInfor(response,xpath):
content = response.content.decode('gb2312') #网页源码是gb2312要先解码
selector = etree.HTML(content)
infor = selector.xpath(xpath)[0]
return infor
#获取学生基本信息
text = getInfor(response,'//*[@id="xhxm"]/text()')
text = text.replace(" ","")
studentnumber = text[:10]
studentname = text[10:].replace("同学","")
print "姓名:"+studentname
print "学号:"+studentnumber
  • 下面演示一下爬取课表信息:
  1. 先抓包分析:

这里写图片描述

点击课表访问的页面是

http://202.195.144.163/jndx/xskbcx.aspx?xh=1030614418&xm=%BA%FA%D3%C2&gnmkdm=N121603

有几个参数xh为学号,xm为姓名,进行了url编码

注意:headers里面有这样一个参数,一个要有,不然会失败
Referer:http://202.195.144.163/jndx/xs_main.aspx?xh=1030614418

2.编码实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
urlStudentname = urllib.quote_plus(str(studentname.encode('gb2312')))
#获取课表
kburl = "http://202.195.144.163/jndx/xskbcx.aspx?xh="+studentnumber+"&xm="+urlStudentname+"&gnmkdm=N121603"

#必须要有Referer这个参数
headers =
{
"Referer":"http://202.195.144.163/jndx/xs_main.aspx?xh=1030614418",
"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(kburl,headers=headers)
html = response.content.decode("gb2312")
print html

这里写图片描述

已经爬取了课表的html源码,下面正则表达式即可提取具体课表信息。

这里写图片描述

3.接下来要做的

  • 能否实现验证码的自动破解

这里写图片描述

观察验证码,需要先去除噪点,然后再分割,再ocr识别

  • 针对于html的表格,能不能写一个方法,自动解析html的table成json数据类型。