python网络爬虫——表单交互

将与网页进行交互,根据用户输入返回对应的内容。有些网站需要在登录后才能访问某个网页,在登录之前不允许访问。所以使用用户表单交互传递参数登录。
表单方法
HTML定义了两种向服务器提交数据的方法,分别是GET和POST。使用GET时,会将类似?name1=value1&name2=value2的数据添加到URL中,这串数据被称为“查询字符串”。由于浏览器存在URL长度限制,因此这种方法只适用于少量数据的场景。这种方法应当用于从服务器获取数据,而不是修改数据。在使用POST请求时,数据在请求体中发送,与URL保持分离。敏感数据只应使用POST请求进行发送,以免将数据暴露在URL中。POST数据在请求体中如何表示需要依赖所使用的编码类型。服务器还支持其他HTTP方法。
登录表单
登录这里写链接内容。需要用FirebugLite对这个表单进行分析。
这里写图片描述
包括几个重要组成部分,分别是form标签action、enctype和method属性,以及两个input域。action属性用于设置表单数据提交的地址,encytpe属性用于设置数据提交的编码。
当普通用户通过浏览器打开该网页时,需要输入邮箱和密码,然后单击按钮将数据提交到服务端。如果登录成功,则会跳转到主页;否则会跳转到登录页。
cookie
cookie某些网站为了辨明用户身份、进行session跟踪而储存在用户本地终端上的数据当普通用户加载登录表单时,_formkey的值将会保存在cookie中然后该值会与提交的登录表单数据种的_formkey值进行对比。

# coding:utf-8
import cookielib
import urllib
import urllib2
import lxml.html

# 用户邮箱


LOGTN_EMAIL='[email protected]'

#用户密码
LOGTN_PASSWORD='123456'

# 登录表单地址
LOGIN_URL='http://example.webscraping.com/places/default/user/login?_next=/places/default/index'


def login():

    # 来捕获cookie并在后续连接请求时重新发送,创建cj处理器
    cj=cookielib.CookieJar()
    # 自定义opener,并将opener和CookieJar对象绑定
    # urllib2.build_opener不同于urllib2.urlopen的是
    # 它支持验证、cookie或者其他HTTP高级功能
    opener=urllib2.build_opener(urllib2.HTTPCookieProcessor(cj))
    # 下载登录页面的源代码
    html=opener.open(LOGIN_URL).read()
    data=parse_form(html)
    data['email']=LOGTN_EMAIL
    data['password']=LOGTN_PASSWORD
    # 获取数据的编码格式
    encoded_data=urllib.urlencode(data)
    # 给url发送请求和编码格式
    request=urllib2.Request(LOGIN_URL,encoded_data)
    # 获取响应
    response=opener.open(request)

    print response.geturl()
    return opener


def parse_form(html):
    """从表单中获取输入的数据"""

    tree=lxml.html.fromstring(html)
    data={}
    for e in tree.cssselect('form input'):
        if e.get('name'):
            data[e.get('name')]=e.get('value')

    return data

if __name__=='__main__':
    login()

这里写图片描述

从返回的URL地址可以看出服务器接受了提交的表单,response的URL是主页。
从浏览器加载cookie
先在浏览器中手工登录,然后使用之前的代码得到cookie,从而实现自动登录。以Firefox为例。Firefox在sqlite数据库中存储cookie,在JSON文件中存储session,都可以会获取。
不同的操作系统,Firefox存储session文件的位置不同。

  • Linux:~/.mozilla/firefox/*.default/sessionstore.js
  • OSX:~/Library/Application Support/Firefox/Profiles/*.default/sessionstore.js
  • Window:%APPDATA%/Roaming/Mozilla/Firefox/Profiles/*.default/sessionstore.js
def login_firefox():
    """从Firefox中加载cookie"""

    # 获取session缓存的文件路径
    session_filename=find_ff_sessions()
    #获取一个cookie处理器,包含登录用户的信息
    cj=load_ff_sessions(session_filename)
    opener=urllib2.build_opener(urllib2.HTTPCookieProcessor(cj))

    # 爬取主页信息,如果登录成功则会返回主页信息
    html=opener.open(COUNTRY_URL).read()

    # 检测是否登录成功
    tree=lxml.html.fromstring(html)
    print tree.cssselect('ul#navbar li a')[0].text_content()
    return opener


def load_ff_sessions(session_filename):
    cj=cookielib.CookieJar()
    if os.path.exists(session_filename):
        try:
            json_data=json.loads(open(session_filename,'rb').read())
        except ValueError as e:
            print e
        else:
            for window in json_data.get('windows',[]):
                for cookie in window.get('cookies',[]):
                    pprint.pprint(cookie)
                    c=cookielib.Cookie(0,cookie.get('name',''),
                                       cookie.get('value',''),
                                        None,False,
                                        cookie.get('host',''),
                                       cookie.get('host','').startswith('.'),
                                       cookie.get('host','').startswith('.'),
                                       cookie.get('path',''),False,False,
                                       str(int(time.time())+3600*24*7),
                                       False,None,None,{})
                    cj.set_cookie(c)
    else:
        print 'Session filename does not exist:',session_filename

    return cj

def find_ff_sessions():
    # 不同的操作系统Firefox中的session存储路径
    paths=[
        '~/.mozilla/firefox/*.default/sessionstore-backups',
        '~/Library/Application Support/Firefox/Profiles/*.default',
        '%APPDATA%/Roaming/Mozilla/Firefox/Profiles/*.default'
    ]

    for path in paths:
        filename=os.path.join(path,'*.js')

        # 返回指定路径中所有匹配的文件
        matches=glob.glob(os.path.expanduser(filename))
        if matches:
            return matches[0]

if __name__=='__main__':
    login_firefox()

检测是否登录成功,在登录成功的主页面

这里写图片描述
检测结果:
这里写图片描述
支持内容更新的登录脚本扩展
自动化登录成功运行后,还可以继续扩展该脚本,时其与网站进行交互,更新国家数据。

这里写图片描述
编写一个脚本,每次运行时,都会使该国家的人口数量加1.

 Edit_URL='http://example.webscraping.com/places/default/edit/Afghanistan-1'
    opener=login()
    country_html=opener.open(Edit_URL).read()
    data=parse_form(country_html)
    pprint.pprint(data)

这里写图片描述
更新数据

 data['population']=int(data['population'])+1
    encoded_data=urllib.urlencode(data)
    request=urllib2.Request(Edit_URL,encoded_data)
    response=opener.open(request)

这里写图片描述
可以对任意字段随意进行四ugai和测试。这里适用的表单技术可以应用于抓取时的复杂表单交互当中。
使用Mechanize模块实现自动表单处理
该模块提供了表单交互的高级接口。

import mechanize


    edit_url='http://example.webscraping.com/places/default/edit/Afghanistan-1'
    # 打开浏览器
    br=mechanize.Browser()
    br.open(LOGIN_URL)
    # 选择表单
    br.select_form(nr=0)
    br['email']=LOGTN_EMAIL
    br['password']=LOGTN_PASSWORD
    # 提交
    response=br.submit()
    br.open(edit_url)
    br.select_form(nr=0)
    br['population']=str(int(br['population'])+1)
    br.submit()

不再需要管理cookie,而且访问表单输入框也更加容易处理。
首先创建一个Mechanize浏览器对象,然后定位到登录URL,选择登录表单。直接向浏览器对象传递名称和值,来设置选定表单的输入框内容。然后定位到国家编辑页面,使用表单增加人数。
这里写图片描述

猜你喜欢

转载自blog.csdn.net/mashaokang1314/article/details/82389147