您的位置:首页 > 运维架构 > 网站架构

使用Scrapy抓取需要登录的网站

2016-04-01 16:51 633 查看
经常在爬有些网站的时候需要登录,大多数网站需要你提供一个用户名和密码,在这种情况下,需要先向网站发送一个POST请求。可以使用Scrapy的
FormRequest
类,这个类和
Request
类很相似,只是多了一个extra参数,用这个参数可以传递表单数据。要使用这个类,先导入:

from scrapy.http import FormRequest


然后把
start_urls
替换成
start_requests()
方法,因为在这种情况下需要的不仅仅是一些URL(
start_requests()
方法的默认行为是从
start_urls
取出URL发出请求)。

start_requests()
方法中创建并返回一个
FormRequest


# Start with a login request
def start_requests(self):
return [
FormRequest(
"http://web:9312/dynamic/login",
formdata={"user": "user", "pass": "pass"}
)]


Scrapy帮助我们处理了Cookies,只要登录之后,它就会在以后的请求中传递给服务器,就像浏览器做的一样。运行一下
scrapy crawl


$ scrapy crawl login
INFO: Scrapy 1.0.3 started (bot: properties)
...
DEBUG: Redirecting (302) to <GET .../gated> from <POST
.../login >
DEBUG: Crawled (200) <GET .../data.php>
DEBUG: Crawled (200) <GET .../property_000001.html> (referer:
.../data.php)
DEBUG: Scraped from <200 .../property_000001.html>
{'address': [u'Plaistow, London'],
'date': [datetime.datetime(2015, 11, 25, 12, 7, 27, 120119)],
'description': [u'features'],
'image_urls': [u'http://web:9312/images/i02.jpg'],
...
INFO: Closing spider (finished)
INFO: Dumping Scrapy stats:
{...
'downloader/request_method_count/GET': 4,
'downloader/request_method_count/POST': 1,
...
'item_scraped_count': 3,


从以上的输出中可以观察到一点:从
dynamic/login
(登录页面)重定向到
dynamic/gated
(登录后自动跳转到的页面)。也就是说,Scrapy从登录后跳转的作为种子URL,而这个跳转行为是与浏览器一致的。

如果输入错了用户名或者密码,会被重定向到一个错误页面,不会有items,且爬取的过程也会终止,比如:

$ scrapy crawl login
INFO: Scrapy 1.0.3 started (bot: properties)
...
DEBUG: Redirecting (302) to <GET .../dynamic/error > from <POST
.../dynamic/login>
DEBUG: Crawled (200) <GET .../dynamic/error>
...
INFO: Spider closed (closespider_itemcount)


上面只是一个简单的登录的例子,有些网站的登录做得更加复杂,但是大多数Scrapy也能很容易地处理。比如有些网站需要你从表单页POST数据到登录页的时候加上一些其他的一些表单变量,这样可以确认cookies是否已经启用,而且可以让暴力破解更加困难。



假设你访问了http://localhost:9312/dynamic/nonce这个URL,用谷歌浏览器的开发者工具可以看到这个表单有一个隐藏的域是nonce。当提交这份表单(到http://localhost:9312/dynamic/nonce-login)时,必须给出正确的用户名密码以及访问登录页面时服务器给出的nonce值。这个值猜是没法猜的,只能分成两个请求来解决登录问题。先要访问表单面然后访问登录页并传递数据。Scrapy有内建的函数帮助我们完成。

创建一个爬虫,在
start_request()
里面先返回一个指向表单页的请求,并把它的
callback
属性设置成
parse_welcome()
。在
parse_welcome()
方法中,使用
FormRequest
对象的
from_response()
方法,创建一个包含了原来表单所有域和值的
FormRequest
对象。
FormRequest.from_response()
方法大概模仿了页面上的第一个表单的单击提交行为,不过表单的每个域都是空的。

注:

花些时间熟悉一下
from_response()
方法的文档是很值得的。它有很多特性比如
fromname
formnumber
可以在页面上不止一个表单时帮助你选择你想要的那个表单。

from_response()
方法包含了表单所有的包括隐藏的域,我们需要做的仅仅是用
formdata
参数填充
user
pass
域并返回
FormRequest
对象即可。相关代码如下:

# Start on the welcome page
def start_requests(self):
return [
Request(
"http://web:9312/dynamic/nonce", callback=self.parse_welcome)
]
# Post welcome page's first form with the given user/pass
def parse_welcome(self, response):
return FormRequest.from_response(
response,
formdata={"user": "user", "pass": "pass"}
)


运行结果如下:

$ scrapy crawl noncelogin
INFO: Scrapy 1.0.3 started (bot: properties)
...
DEBUG: Crawled (200) <GET .../dynamic/nonce>
DEBUG: Redirecting (302) to <GET .../dynamic/gated > from <POST
.../dynamic/nonce-login>
DEBUG: Crawled (200) <GET .../dynamic/gated>
...
INFO: Dumping Scrapy stats:
{...
'downloader/request_method_count/GET': 5,
'downloader/request_method_count/POST': 1,
...
'item_scraped_count': 3,


可以看到,第一个请求是到/dynamic/nonce的GET请求,然后是到/dynamic/nonce-login的POST请求,再然后是登录之后到/dynamic/gated的重定向.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: