[python爬虫]爬取学校教务处以及登录过程验证码的处理

其实是半年前做的一段小代码,爬取自己的学校教务处网站大概是每个学习爬虫的同学的入门必备吧(心疼一秒教务处)。其实想起来本科的时候有大神做了南理工GPA的网页,其实也就是个爬虫然后做了数据处理(只是我的猜测啦,不是请不要拍我。。),当时的教务处系统还比较简单,也没有验证码的问题,post一个表单就可以模拟登陆。但是!南理工教务处他改版了,还做的很不错(大概招了个不错的前端),加了验证码大概是这次爬虫比较大的问题了。

1.登陆过程分析

利用chrome的开发者工具,可以清楚地看出南理工研究生院登陆的过程是怎样的。首先,登陆页面长这样:

[python爬虫]爬取学校教务处以及登录过程验证码的处理_第1张图片

打开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不能被发送。


[python爬虫]爬取学校教务处以及登录过程验证码的处理_第2张图片

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

可以看到用了cStringIO直接把图片保存为内存里的一个临时文件,然后用Image打开,这样代码运行的时候验证码会直接弹出来,填完了关掉就可以了,当然也可以保存到本地,然后到目标地址打开读取,不过我觉得这样比较快。另外要注意一定要先创建cookie,再获取验证码进行提交,不然相当于你填完了验证码又刷新了一下,验证码就变掉了,这样会提示你验证码错误的。

把自己的用户名密码验证码以及一些其他的信息作为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对爬取的信息进行分析。

[python爬虫]爬取学校教务处以及登录过程验证码的处理_第3张图片

下面给出完整代码:

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


你可能感兴趣的:(python)