[python网络爬虫]表单和登陆爬虫

来源:互联网 发布:手机淘宝怎么解除验证 编辑:程序博客网 时间:2024/06/15 19:41
http://www.ituring.com.cn/article/200288?utm_source=tuicool&utm_medium=referral

当你想编写更为复杂的网页爬虫的时候,你面临的第一个问题也许会是:“如何获取登陆页面后的信息?”,因为网络已经飞快地向互动、社交媒体、用户生成内容方向发展。表格和登陆就成为这些类型网站几乎不可或缺的主要组成。幸运的是,表单和登陆还是相对比较容易处理的。

截至当前,在我们之前的爬虫示例中,绝大部分与服务器的交互都是采用了HTTP GET方式去获取信息的。而在本章,我们所关注的是如何通过POST方式来向服务器提交信息用于存储和分析。

表单给用户提供了一种服务器可以理解并使用的,提交POST请求的简单方法。就像网址链接可以帮助用户格式化GET请求,HTML表单可以帮用户格式化POST请求。当然通过一小段代码,我们就可以轻松的通过爬虫来创建并提交表单。

Python Requests类库

尽管可以通过Python核心类库来操作网页表单,但有些时候更友好的代码可以让生活更美好。当你开始使用urllib类库的GET请求做更多事情的时候,放眼Python核心库之外也许更有帮助。

Requests类库在处理复杂HTTP请求、Cookies,请求头等方面更为高效,此处便是Requests类库的创建者Kenneth Reitz对Python核心工具的评价:

Python标准urlib2模块提供了你所需要的绝大多数HTTP功能,但是其API却很垃圾。它的创建是用于不同时间以及不同网页的,即使执行一个简单的任务也需要大量的工作(甚至重写方法等)。

事情并不应该如此,至少在Python中不应如此。

和其他Python类库一样,Requests类库可以通过Python第三方类库管理器如pip来安装,或者直接下载源代码进行安装。

提交一个简单表单

绝大多数网页表单由部分HTML标签、提交按钮以及一个Action页(具体执行表单任务的网址)所组成。HTML标签一般含有文本标签不过有时候也包含文件上传或其他非文本内容标签。

大多数热门网站在robots.txt文件中屏蔽了针对登录表单的访问(详见附录C),因此为了更安全的玩耍,我在pythonscraping.com上创建了一系列不同类型的表单和登录页面。你可以运行你的爬虫来访问他们。其中最为简单的表单地址为:http://bit.ly/1AGKPRU

完整表单代码如下:

<form method="post" action="processing.php">First name: <input type="text" name="firstname"><br>Last name: <input type="text" name="lastname"><br><input type="submit" value="Submit"></form>

在此处需要注意的是:第一,两个input标签的名称为firstnamelastname。这个非常重要,这些标签的名称决定了要POST到服务器的表格变量的名称。如果你要模拟提交表格,并提交自定义内容,那么你需要确定你的变量名称与标签名称匹配。

第二需要注意的是表格实际提交到的执行页面是processing.php(绝对路径为:http://bit.ly/1d7TPVk)。任何POST请求提交到表单都是上述(Action所指向的)地址,而不是包含表单的页面地址。记住:HTML表单的主要目的仅是帮助网站访问者格式化提交到处理页面的请求。除非你在研究如何格式化请求,那么你完全没有必要被包含表单的页面所困扰。

通过Requests类库提交一个表单可以使用4行代码完成,包括import以及print内容函数。

import requestsparams = {'firstname': 'Ryan', 'lastname': 'Mitchell'}r = requests.post("http://pythonscraping.com/pages/files/processing.php", data=params)print(r.text)

表单提交后,脚本会返回页面内容:

Hello there, Ryan Mitchell!

这个脚本可以被应用到许多互联网上的简单表单。例如,登录O‘Reilly媒体通讯的表单,如下所示:

<form action="http://post.oreilly.com/client/o/oreilly/forms/          quicksignup.cgi" id="example_form2" method="POST">    <input name="client_token" type="hidden" value="oreilly" />     <input name="subscribe" type="hidden" value="optin" />     <input name="success_url" type="hidden" value="http://oreilly.com/store/                 newsletter-thankyou.html" />     <input name="error_url" type="hidden" value="http://oreilly.com/store/                 newsletter-signup-error.html" />     <input name="topic_or_dod" type="hidden" value="1" />     <input name="source" type="hidden" value="orm-home-t1-dotd" />    <fieldset>        <input class="email_address long" maxlength="200" name=                     "email_addr" size="25" type="text" value=                     "Enter your email here" />        <button alt="Join" class="skinny" name="submit" onclick=                       "return addClickTracking('orm','ebook','rightrail','dod'                                                );" value="submit">Join</button>    </fieldset></form>

尽管第一次开起来上述代码有点吓人,不过要记住在绝大多数案例中(我们稍后会讲到其他例外),你只需要关注两个事情:

  • 提交数据字段的名称(在这个例子中,字段名称是email_address)

  • 表单的action属性,也就是表单真正提交到的那个页面(在这个例子中,就是http://post.oreilly.com/client/o/oreilly/forms/quicksignup.cgi)

添加需要的信息并运行:

import requestsparams = {'email_addr': 'ryan.e.mitchell@gmail.com'}r = requests.post("http://post.oreilly.com/client/o/oreilly/forms/                   quicksignup.cgi", data=params)print(r.text)

在这个例子中,当你可以真正进入O'Reilly的邮件列表前,网站返回了另一个需要填写的表单。不过同样的原理可以应用到这个新表单上。不过,当你在家自己尝试的时候,我需要你保证正当利用这个技术,而不是通过无效注册给发布者制造垃圾邮件。

单选、多选和其他输入组件

很显然,并不是所有表单都是由文本标签加提交按钮所组成。标准的HTML包含多种表单输入字段:单选按钮、多选按钮、下拉框等等。在HTML5中则扩充了滑动条、邮件、日期等。而且通过自定义Javascript还为输入字段带来了无限可能的扩充,如颜色选择、日历等,只要程序员想去做就没有不能实现的。

不管上述表单字段看起来有多么的复杂,你真正需要关心的只有两个东西:元素的名称和它的数值。元素的名称可以通过查看源代码并找到name属性来轻松辨别。元素数值的获取则稍微有点麻烦,因为它可能在表单提交前瞬间通过Javascript生成。以相当独特的颜色拾取器为例,它的数值就有可能是#F03030这样的数据。

如果你不确定输入字段数值的格式,这里有一些工具你可以用来跟踪浏览器和网站之间的GETPOST请求。最好也是最直观的办法就是查看GET请求,就像之前提到的查看网站URL。如果网站的URL类似下面:

http://domainname.com?thing1=foo&thing2=bar

那你就知道对应的表单应该是如下形式的:

<form method="GET" action="someProcessor.php"><input type="someCrazyInputType" name="thing1" value="foo" /><input type="anotherCrazyInputType" name="thing2" value="bar" /><input type="submit" value="Submit" /></form>

对应的Python参数对象就是:

{'thing1':'foo', 'thing2':'bar'}

如图9-1所示。

如果你被看起来很复杂的POST表单所困扰,同时还想查看浏览器给服务器,发送的到底是什么参数的话。那么最简单的方法就是使用浏览器的监视或开发者工具来查看它们。

谷歌浏览器(Chrome)开发者工具可以通过【查看】->【开发】->【开发者工具】来打开。开发者工具列出了你浏览器与当前网站的所有访问请求,并且可以查看所有请求的访问详情。

提交文件和图片

尽管文件上传在互联网中十分普遍,但是在网络爬虫中却不是十分常用。不过你可以自己编写脚本在你的网站上测试文件上传。不管怎样,知道如何上传文件总是有用的。

这里有一个练习用的文件上传表单:http://pythonscraping.com/pages/files/form2.html,该页面的表单由如下代码组成:

<form action="processing2.php" method="post" enctype="multipart/form-data">    Submit a jpg, png, or gif: <input type="file" name="image"><br>    <input type="submit" value="Upload File"></form>

除了<input>标签的file类型字段,它看起来和之前例子中的文本表单类似。幸运的是,通过Python的requests类库操作表单也是极为类似的:

import requestsfiles = {'uploadFile': open('../files/Python-logo.png', 'rb')}r = requests.post("http://pythonscraping.com/pages/processing2.php",  files=files)print(r.text)

可以看到替换了之前的简单字符串,现在提交到表单字段的数值(通过名称uploadFile)是Python的文件对象,通过open函数返回的。在这个例子中,我提交了一个保存在本地的一个图像文件,路径为:../files/Python-logo.png,相对于当前运行的Python脚本。

是的,就是这么简单!

处理登陆和Cookies

到目前为止,我们讨论的表单都只允许你提交信息到网站,或者查看表单提交后返回页面所包含的信息。这些与登陆表单,可以让你保持登陆状态访问网站有何异同呢?

绝大多数现代网站使用Cookies来辨别登陆者的状态。一旦网站验证通过你的登陆信息,它便会在你的浏览器中储存一个Cookie值,其包含服务器生成的Token、过期时间以及跟踪信息等内容。当你访问网站任意页面的时候,网站则通过Cookie来作为访问者的授权标志。在90年代中期,Cookie尚未大规模使用前,如何安全验证并且跟踪访问者身份对于网站来说是一个大麻烦。

尽管Cookies对于网络开发者来说是一个非常好的解决方案,不过对于网络爬虫却造成了不小的困难。你可以不断尝试提交登陆表格,不过如果你没有处理好登陆表单返回的Cookie信息,那么当你访问下一个页面的时候,你所表现的就好像从来没有登陆过。

我创建了一个简单的登陆表单:http://bit.ly/1KwvSSG(用户名可以任意输入,不过密码必须是"password"

表单的处理地址为:http://bit.ly/1d7U2I1,其中包含了一个“主页”的链接:http://bit.ly/1JcansT

如果你在没有登陆的情况下访问欢迎页面或者个人资料页面,你会得到一个错误信息以及登陆操作指引。在个人信息页面,会检查你浏览器Cookie信息,判断其是否是来自登陆页面设置。

通过Requests类库来跟踪处理Cookies信息非常简单:

import requestsparams = {'username': 'Ryan', 'password': 'password'}r = requests.post("http://pythonscraping.com/pages/cookies/welcome.php", params)print("Cookie is set to:")print(r.cookies.get_dict())print("-----------")print("Going to profile page...")r = requests.get("http://pythonscraping.com/pages/cookies/profile.php",                  cookies=r.cookies)print(r.text)

此处我向欢迎页面发送了登陆参数,就像在登录表单处理时的一样。我在得到返回的Cookies后,将其打印出来验证,并且通过设置cookies参数发送到个人信息页面。

对于简单情况上述方式表现挺好,不过如果你要处理更为复杂的网站,例如在没有提醒的情况下频繁更新Cookies信息,或者你一开始根本就不去考虑Cookies操作。使用Requests类库的session函数在这种例子中表现更好:

import requestssession = requests.Session()params = {'username': 'username', 'password': 'password'}s = session.post("http://pythonscraping.com/pages/cookies/welcome.php", params)print("Cookie is set to:")print(s.cookies.get_dict())print("-----------")print("Going to profile page...")s = session.get("http://pythonscraping.com/pages/cookies/profile.php")print(s.text)

在这个例子中,session对象(通过执行requests.Session()获得)负责跟踪处理session信息,如Cookies、请求头,甚至包括在HTTP上运行的协议如HTTPAdapters。

Requests是一个非常棒的类库,其健全的功能甚至不需要程序员去思考如何编写,第二个类似的类库可能就是Selenium(我们将在第十章详述)。尽管将所有工作交给类库去处理省事省力,但是非常重要的就是搞清楚Cookies是什么以及在编写网络爬虫时如何去正确操作Cookies。它会节省很多痛苦调试的时间,或者帮你弄清楚为何网站有奇怪的表现。



0 0