pyton简单网络爬虫,aspx网站中form使用到了__VIEWSTATE、__EVENTVALIDATION、cookie来验证的提交

一、需求

最近在学习Python,刚好有一个需求,需要从一个本地密码管理系统获取本地账号的密码 。之前的流程是 登录web-----输入计算机名-----管理员账号、密码---提交------页面返回密码,复制密码,发送邮件给请求用户。每次都要登录页面,这个很郁闷,于是记录下整个过程也有助于自己学习


二、页面分析

先来看下整个流程:输入选项,查询就会返回

技术分享

让我们先看看页面是什么,竟然有两个隐藏参数,每次提交的时候竟然每次都会变,这是一个坑,后面会提到

技术分享

不管了,我用的是Chrome ,直接F12,看网络选项,单击查询。页面看到了返回密码,

技术分享

后端是什么呢?post了这么些东东。

技术分享


三、思路实现

知道了大体流程,现在要做的就是用python模拟浏览器的动作,模拟登录,构造post参数,返回结果中提取计算机名,密码,有效期这个三个参数。


四、坑的描述,解决

__VIEWSTATE和__EVENTVALIDATION是干什么的,其实我也懂,百度了下。


__VIEWSTATE
ViewState是ASP.NET中用来保存WEB控件回传时状态值一种机制。在WEB窗体(FORM)的设置为runat="server",这个窗体(FORM)会被附加一个隐藏的属性_VIEWSTATE。_VIEWSTATE中存放了所有控件在ViewState中的状态值。 
ViewState是类Control中的一个域,其他所有控件通过继承Control来获得了ViewState功能。它的类型是system.Web.UI.StateBag,一个名称/值的对象集合。 
当请求某个页面时,ASP.NET把所有控件的状态序列化成一个字符串,然后做为窗体的隐藏属性送到客户端。当客户端把页面回传时,ASP.NET分析回传的窗体属性,并赋给控件对应的值

__EVENTVALIDATION
__EVENTVALIDATION只是用来验证事件是否从合法的页面发送,只是一个数字签名,所以一般很短。
“id”属性为“__EVENTVALIDATION”的隐藏字段是ASP.NET 2.0的新增的安全措施。该功能可以阻止由潜在的恶意用户从浏览器端发送的未经授权的请求.
为了确保每个回发和回调事件来自于所期望的用户界面元素,ASP.NET运行库将在事件中添加额外的验证层。服务器端通过检验表单提交请求的内容,将其与“id”属性为“__EVENTVALIDATION”隐藏字段中的信息进行匹配。根据匹配结果来验证未在浏览器端添加额外的输入字段(有可能为用户在浏览器端恶意添加的字段),并且该值是在服务器已知的列表中选择的。ASP.NET运行库将在生成期间创建事件验证字段,而这是最不可能获取该信息的时刻。像视图状态一样,事件验证字段包含散列值以防止发生浏览器端篡改。
说明:“id”属性为“__EVENTVALIDATION”隐藏字段一般在表单的最下方,如果表单在浏览器端尚未解析完毕时,用户提交数据有可能导致验证失败。

于是关键的关键是获取这两个值。不断尝试了下,发现可以这样实现,运用正则,在爬取之前先open一次url获取值,然后在第二次爬取的时候把这个值传进post参数里面

#!/usr/bin/python
#coding:utf-8
import urllib  
import urllib2
import re

def get_hiddenvalue(url):
    request=urllib2.Request(url)
    reponse=urllib2.urlopen(request)
    resu=reponse.read()
    VIEWSTATE =re.findall(r‘<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="(.*?)" />‘, resu,re.I)
    EVENTVALIDATION =re.findall(r‘input type="hidden" name="__EVENTVALIDATION" id="__EVENTVALIDATION" value="(.*?)" />‘, resu,re.I)
    return VIEWSTATE[0],EVENTVALIDATION[0]
    
    
    
    
    
url=‘"http://servicedesk.******.com/lapq/"‘ #你自己的url 
test=get_hiddenvalue(url)                   #可以自己设置打印测试返回的值

五、完整代码实现

后续会在web实现,输入num,直接将结果邮件返回给用户,

#!/usr/bin/python
#coding:utf-8
import urllib  
import urllib2
import cookielib
import re
import sys
import ConfigParser



#爬取得URL
url="http://servicedesk.sf-express.com/lapq/"


def getfromConfig(agrs):
    #从配置文件得到相关基本信息,配置信息,不再写在脚本中。减少代码维护。
    tagrs = agrs
    try:
        configFile = open(configetc,"r") #打开信息配置文件
    except IOError:
        sys.exit()

    config = ConfigParser.ConfigParser() #创建ConfigParser实例 
    config.readfp(configFile)
    configFile.close()

    try:
        tagrs = config.get("BASEINFO",tagrs)#返回BASEINFO节中,tagrs的键值
    except ConfigParser.NoOptionError:
        sys.exit()
        
    return  tagrs

#获取动态隐藏的参数,为post做准备
def get_hiddenvalue(url):
    request=urllib2.Request(url)
    reponse=urllib2.urlopen(request)
    resu=reponse.read()
    VIEWSTATE =re.findall(r‘<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="(.*?)" />‘, resu,re.I)
    EVENTVALIDATION =re.findall(r‘input type="hidden" name="__EVENTVALIDATION" id="__EVENTVALIDATION" value="(.*?)" />‘, resu,re.I)
    return VIEWSTATE[0],EVENTVALIDATION[0]

#爬取页面,获取密码。
def get_localpw(url,num,username,password):
    #cookie,获取后面将其一起POST出去
    cookie = cookielib.CookieJar()  
    opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookie))

    VIEWSTATE, EVENTVALIDATION=get_hiddenvalue(url)
    #需要POST的数据,
    postdata=urllib.urlencode({  
        ‘__VIEWSTATE‘:VIEWSTATE,
        ‘__EVENTVALIDATION‘:EVENTVALIDATION,
        ‘TextBox_Computer‘:‘hq-pay-%s‘ %num,
        ‘TextBox_LAaccount‘:‘%s‘ %username,
        ‘TextBox_Password‘:‘%s‘ %password,
        ‘button_Submit‘:‘查 询‘
    })
    #自定义一个请求#
    req = urllib2.Request(  
    url = ‘http://servicedesk.sf-express.com/lapq/‘,  
    data = postdata
     )
    #访问该链接#
    result = opener.open(req)
    #打印返回的内容#
    a=result.read() 
    #正则匹配,提取所需数据,我这里只是打印,后续回做为返回值,直接写进文本中。
    computer=re.findall(r‘<input name="TextBox_Computer" type="text" value="(.*?)"‘, a,re.I)
    password= re.findall(r‘<input name="TextBox_LAaccount" type="text" value="(.*?)"‘, a,re.I)
    expired_time=re.findall(r‘ <input name="TextBox_Password" type="datetime" value="(.*?)"‘, a,re.I)
    print u‘计算机名:‘ ,computer[0]
    print u‘密         码:‘,password[0]
    print u‘过期时间:‘,expired_time[0]


if __name__==‘__main__‘:
    configetc = "psw.conf"
    username=getfromConfig(‘username‘)
    password=getfromConfig(‘password‘)    
    
    num=‘******‘
    get_localpw(url,num,username,password)


六、结果,

爬取的结果跟登录页面的一致。对已批量申请的请求可以用for循环,快速的取出密码。

技术分享

技术分享

e什么用的

七、总结

带有隐藏验证机制的,可以先用urllib2 open一次获取其值,再第二次爬取的时候将其做为post的值传进去,从而实现页面的form表单登录。不用去理会第二次open里面的那两个__EVENTVALIDATION、__VIEWSTATE字段







文章来自:http://slliang.blog.51cto.com/6959776/1783837
© 2021 jiaocheng.bubufx.com  联系我们
ICP备案:鲁ICP备09046678号-3