升级版见:http://blog.csdn.net/nghuyong/article/details/52203443
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登陆分析
-
通过审核元素观察到验证码的地址是:http://202.195.144.163/jndx/CheckCode.aspx?
-
网页登陆查看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代码实现
# 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中提取即可。
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
- 下面演示一下爬取课表信息:
- 先抓包分析:
点击课表访问的页面是
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.编码实现:
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数据类型。