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

本文介绍了如何使用Scrapy框架处理需要登录的网站。通过发送POST请求模拟登录,Scrapy会自动处理Cookies以便后续请求。如果登录失败,爬虫会停止并显示错误页面。文章还提到,对于包含额外验证如nonce的复杂登录流程,Scrapy提供了内建功能来分步处理,包括获取表单数据和填充登录信息。

经常在爬有些网站的时候需要登录,大多数网站需要你提供一个用户名和密码,在这种情况下,需要先向网站发送一个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()方法的文档是很值得的。它有很多特性比如fromnameformnumber可以在页面上不止一个表单时帮助你选择你想要的那个表单。

from_response()方法包含了表单所有的包括隐藏的域,我们需要做的仅仅是用formdata参数填充userpass域并返回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的重定向.

Scrapy是一个强大的Python爬虫框架,用于高效地抓取网站数据。如果你需要模拟登录某个网站Scrapy可以配合第三方库如Requests或Selenium来完成这个过程。以下是基本步骤: 1. 安装依赖:首先,你需要安装`scrapy`、`requests`(默认支持HTTP请求)和`selenium`(如果目标网站有JavaScript验证)。 ```bash pip install scrapy requests selenium (如果需要) ``` 2. 创建Scrapy项目:使用`scrapy startproject your_project_name`命令创建一个新的Scrapy项目。 3. 导入必要的模块:在`settings.py`文件中添加对Selenium的支持,并设置一个中间件处理登录,例如: ```python DOWNLOADER_MIDDLEWARES = { 'your_project.middlewares.SeleniumMiddleware': 543, } ``` 4. 编写中间件(Middlewares):创建`middlewares/SeleniumMiddleware.py`文件,这里通常会使用`webdriver_manager`来管理浏览器驱动,然后初始化Selenium实例: ```python from scrapy import signals from selenium import webdriver from webdriver_manager.chrome import ChromeDriverManager class SeleniumMiddleware: def __init__(self): self.driver = webdriver.Chrome(ChromeDriverManager().install()) @classmethod def from_crawler(cls, crawler): middleware = cls() crawler.signals.connect(middleware.spider_opened, signal=signals.spider_opened) return middleware def spider_opened(self, spider): # 开启浏览器并导航到登录页面 self.driver.get(spider.login_url) def process_request(self, request, spider): if spider.is_login_required and 'login_form_data' in request.meta: # 提交表单数据,模拟登录 form_data = request.meta['login_form_data'] self.driver.find_element_by_name(form_data['username_field']).send_keys(form_data['username']) self.driver.find_element_by_name(form_data['password_field']).send_keys(form_data['password']) login_button = self.driver.find_element_by_css_selector(form_data['submit_button']) login_button.click() # 如果需要保持登录状态,可以在每个后续请求前检查cookie等信息 # ... return request ``` 5. 使用中间件:在Scrapy项目的spiders目录下,编写一个spider,将登录需求作为元数据传递给中间件: ```python class LoginSpider(scrapy.Spider): name = "login_spider" allowed_domains = ["example.com"] start_urls = ['http://example.com/login'] def is_login_required(self): return True def parse(self, response): # 登录成功后的解析逻辑 ... ``` 6. 设置登录数据和启动爬虫:在运行spider之前,指定登录表单的数据(用户名、密码、提交按钮等),然后通过`scrapy crawl`命令启动。 ```bash scrapy crawl login_spider -a login_form_data={"username_field": "username", "password_field": "password", "submit_button": ".btn-login"} ``` 注意:并非所有网站都支持直接模拟登录,某些网站可能需要验证码、OAuth授权等方式。此外,频繁的模拟登录可能会触发反爬机制或违反服务条款,因此在实际操作时需谨慎。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值