其实是半年前做的一段小代码,爬取自己的学校教务处网站大概是每个学习爬虫的同学的入门必备吧(心疼一秒教务处)。其实想起来本科的时候有大神做了南理工GPA的网页,其实也就是个爬虫然后做了数据处理(只是我的猜测啦,不是请不要拍我。。),当时的教务处系统还比较简单,也没有验证码的问题,post一个表单就可以模拟登陆。但是!南理工教务处他改版了,还做的很不错(大概招了个不错的前端),加了验证码大概是这次爬虫比较大的问题了。
1.登陆过程分析
利用chrome的开发者工具,可以清楚地看出南理工研究生院登陆的过程是怎样的。首先,登陆页面长这样:
打开chrome的更多工具中的开发者工具,选择network,把preserve log勾上(这样才能把中间过程保存下来),好了,输入你的用户名密码以及验证码,点击登陆。看一下出现了一个POST方法,这个就是我们提交表单的信息了,点进去拖到最下方可以看到from data,是不是看到了你提交的用户名密码之类的信息,接下来用代码模拟登陆的话把这个data里的信息提交就可以了。
同时,登陆的时候也需要提供请求头,这个在刚刚那个post方法下面也是可以看到的。具体每个域有什么作用这个应该的HTTP协议中用的了。
Host头域指定请求资源的Intenet主机和端口号,必须表示请求url的原始服务器或网关的位置。HTTP/1.1请求必须包含主机头域,否则系统会以400状态码返回。
Accept:告诉WEB服务器自己接受什么介质类型,/ 表示任何类型,type/* 表示该类型下的所有子类型,type/sub-type。
Accept-Charset: 浏览器申明自己接收的字符集。
Authorization:当客户端接收到来自WEB服务器的 WWW-Authenticate 响应时,用该头部来回应自己的身份验证信息给WEB服务器。
User-Agent头域的内容包含发出请求的用户信息。
Referer 头域允许客户端指定请求uri的源资源地址,这可以允许服务器生成回退链表,可用来登陆、优化cache等。如果请求的uri没有自己的uri地址,Referer不能被发送。
2.模拟登陆爬取自己的信息
用cookiejar来保存cookie信息,然后使用urllib2的HTTPCookieProcessor来创建cookie处理器,通过此处理器来构建opener。这也是大部分模拟登陆采用的方法。
这里比较麻烦的是怎样获取验证码的图片。分析网页可以看到验证码图片的url是http://gsmis.njust.edu.cn/Public/ValidateCode.aspx?image=,下面直接给出获取验证码图片的一段代码:
def getUrlRespHtml(url,head) :
resp = getUrlResponse(url,head)
respHtml = resp.read()
return respHtml
def getCheckCode(url,postdic,headerdic):
print "+"*20+"getCheckCode"+"+"*20
# response = urllib2.urlopen(url)
respHtml = getUrlRespHtml(url,headerdic)
img = Image.open(cStringIO.StringIO(respHtml))
img.show()
checkCode = raw_input("code:")
print 'aaa'
postdic["ValidateCode"] = checkCode
return postdic
把自己的用户名密码验证码以及一些其他的信息作为postdata就可以模拟登陆了,问题又来了,新的研究生院网站是aspx的,打开每个子网页的url都是http://gsmis.njust.edu.cn/Gstudent/Default.aspx,怎么才能定位到开题报告的地方呢?这里肯定有比较好的方法的,但是毕竟个人管理系统内容比较简单,于是我想了一个很蠢的办法。。用开发者工具可以看到显示开题报告状态的表格的的url为http://gsmis.njust.edu.cn/Gstudent/Topic/Topic_Manage.aspx?EID=ZfJPCMhdYM0Q2rZHdgSidgWH2ovrUbhP6ygVVycyPf0=,把这个网址输入到地址栏发现的确可以打开。如果我只要这个信息的话,那么用获得的cookies直接打开这个url就可以了。爬取的信息如下图。当然可以进一步用正则表达式或者beautifulsoup对爬取的信息进行分析。
下面给出完整代码:
# -*- coding: utf-8 -*-
"""
Created on Mon Dec 28 21:49:49 2015
@author: DJ
"""
import urllib
import urllib2
import cookielib
from bs4 import BeautifulSoup
from PIL import Image
import cStringIO
#登录地址
LoginUrl = "http://gsmis.njust.edu.cn/UserLogin.aspx?exit=1"
mainpage="http://http://gsmis.njust.edu.cn/Gstudent/Default.aspx"
checkCodeUrl = ''
kaitibaogao='http://gsmis.njust.edu.cn/Gstudent/Topic/Topic_Manage.aspx?EID=ZfJPCMhdYM0Q2rZHdgSidgWH2ovrUbhP6ygVVycyPf0='
#登录主函数
def login():
headerdic={
'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.86 Safari/537.36',
'Host' : 'gsmis.njust.edu.cn',
'Referer' : 'http://gsmis.njust.edu.cn/',
'Accept' : '*/*',
'Connection' : 'Keep-Alive',
}
postdic={
'UserName' : yourusername ,
'PassWord' : yourpassword,
'drpLoginType' : '1',
'__ASYNCPOST' : 'true',
'ScriptManager1' : 'UpdatePanel2|btLogin',
'__EVENTTARGET' : 'btLogin',
'__VIEWSTATE' : '/wEPDwULLTE5OTkyNTM4MzEPZBYCAgMPZBYGAg0PZBYCZg9kFgICAQ8PFgIeCEltYWdlVXJsBSp+L1B1YmxpYy9WYWxpZGF0ZUNvZGUuYXNweD9pbWFnZT02ODA3OTUyOTFkZAIRD2QWAmYPZBYCAgEPEGRkFgFmZAIVD2QWAmYPZBYCAgEPDxYCHgtOYXZpZ2F0ZVVybAUtfi9QdWJsaWMvRW1haWxHZXRQYXNzd2QuYXNweD9FSUQ9VHVyOHZadXVYa3M9ZGQYAQUeX19Db250cm9sc1JlcXVpcmVQb3N0QmFja0tleV9fFgEFDVZhbGlkYXRlSW1hZ2W5HJlvYqz666q9lGAspojpOWb4sA==',
'__EVENTVALIDATION' : '/wEdAAoKNGMKLh/WwBcPaLKBGC94R1LBKX1P1xh290RQyTesRQa+ROBMEf7egV772v+RsRJUvPovksJgUuQnp+WD/+4LQKymBEaZgVw9rfDiAaM1opWKhJheoUmouOqQCzlwTSNWlQTw3DcvmMLY3PAqFoA+uFSTy5ozCEG4XBxL/Ykep0cgC/Irwlr9d8VObb8MnYO0GRqRfbdgDIW2dtIsr6rbUIwej/LsqVAg3gLMpVY6UeARlz0=',
'__EVENTARGUMENT' : '',
'__LASTFOCUS' : ''
}
#cookie 自动处理器
global checkCodeUrl
cookiejar = cookielib.LWPCookieJar()#LWPCookieJar提供可读写操作的cookie文件,存储cookie对象
cookieSupport= urllib2.HTTPCookieProcessor(cookiejar)
opener = urllib2.build_opener(cookieSupport, urllib2.HTTPHandler)
urllib2.install_opener(opener)
#打开登陆页面
img_url="http://gsmis.njust.edu.cn/Public/ValidateCode.aspx?image="
getCheckCode(img_url,postdic,headerdic)
# print postdic
postData=urllib.urlencode(postdic)
sendPostData(LoginUrl, postData, headerdic,opener)
# print opener.open(kaitibaogao).read()
ktbgtxt=opener.open(kaitibaogao).read()
print ktbgtxt
soup=BeautifulSoup(ktbgtxt)
print soup.td
def sendPostData(url, data, header,opener):
print "+"*20+"sendPostData"+"+"*20
# data = urllib.urlencode(data)
request = urllib2.Request(url, data, header)
response = opener.open(request)
url = response.geturl()
text = response.read()
print url
print text
def getUrlResponse(url,head) :
url = str(url)
req = urllib2.Request(url)
for eachhead in head.keys():
req.add_header(eachhead,head[eachhead])
resp = urllib2.urlopen(req)
return resp
def getUrlRespHtml(url,head) :
resp = getUrlResponse(url,head)
respHtml = resp.read()
return respHtml
def getCheckCode(url,postdic,headerdic):
print "+"*20+"getCheckCode"+"+"*20
# response = urllib2.urlopen(url)
respHtml = getUrlRespHtml(url,headerdic)
img = Image.open(cStringIO.StringIO(respHtml))
img.show()
checkCode = raw_input("code:")
print 'aaa'
postdic["ValidateCode"] = checkCode
return postdic
if __name__ == "__main__":
login()