爬虫框架Scrapy(5)DownLoader Middleware 的用法

news/2024/7/19 9:56:20 标签: python, 爬虫

文章目录

    • 四. DownLoader Middleware 的用法
        • 1. 使用说明
        • 2. 核心方法
        • 3. 项目实战

四. DownLoader Middleware 的用法

Downloader Middleware 即下载中间件,它是处于 Scrapy 的 Request 和 Response 之间的处理模块。Scheduler 从队列中拿出一个 Request 发送给 Downloader 执行下载,这个过程会经过 Downloader Middleware 的处理。另外,当 Downloader 将 Request 下载完成得到 Response 返回给 Spider 时,会再次经过 Downloader Middleware 处理。 也就是说,Downloader Middleware 在整个架构中起作用的位置是以下两个:

  • 在 Scheduler 调度出队列的 Request 发送给 Downloader 下载之前,也就是我们可以在 Request 执行下载之前对其进行修改。
  • 在下载后生成的 Response 发送给 Spider 之前,也就是我们可以在生成 Resposne 被 Spider 解析之前对其进行修改。

Downloader Middleware 的功能十分强大,修改 User-Agent、处理重定向、设置代理、失败重试、设置 Cookies 等功能都需要借助它来实现。下面我们来了解一下 Downloader Middleware 的详细用法。

1. 使用说明

需要说明的是,Scrapy 其实已经提供了许多 Downloader Middleware,比如负责失败重试、自动重定向等功能的 Middleware,它们被 DOWNLOADER_MIDDLEWARES_BASE 变量所定义。 DOWNLOADER_MIDDLEWARES_BASE 变量的内容如下所示:

python">{
    'scrapy.downloadermiddlewares.robotstxt.RobotsTxtMiddleware': 100,
    'scrapy.downloadermiddlewares.httpauth.HttpAuthMiddleware': 300,
    'scrapy.downloadermiddlewares.downloadtimeout.DownloadTimeoutMiddleware': 350,
    'scrapy.downloadermiddlewares.defaultheaders.DefaultHeadersMiddleware': 400,
    'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware': 500,
    'scrapy.downloadermiddlewares.retry.RetryMiddleware': 550,
    'scrapy.downloadermiddlewares.ajaxcrawl.AjaxCrawlMiddleware': 560,
    'scrapy.downloadermiddlewares.redirect.MetaRefreshMiddleware': 580,
    'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware': 590,
    'scrapy.downloadermiddlewares.redirect.RedirectMiddleware': 600,
    'scrapy.downloadermiddlewares.cookies.CookiesMiddleware': 700,
    'scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware': 750,
    'scrapy.downloadermiddlewares.stats.DownloaderStats': 850,
    'scrapy.downloadermiddlewares.httpcache.HttpCacheMiddleware': 900,
}

这是一个字典格式,字典的键名是 Scrapy 内置的 Downloader Middleware 的名称,键值代表了调用的优先级,优先级是一个数字,数字越小代表越靠近 Scrapy 引擎,数字越大代表越靠近 Downloader。每个 Downloader Middleware 都可以定义 process_request ()request_response () 方法来分别处理请求和响应,对于 process_request () 方法来说,优先级数字越小越先被调用,对于 process_response () 方法来说,优先级数字越大越先被调用。如果自己定义的 Downloader Middleware 要添加到项目里,DOWNLOADER_MIDDLEWARES_BASE 变量不能直接修改。Scrapy 提供了另外一个设置变量 DOWNLOADER_MIDDLEWARES,我们直接修改这个变量就可以添加自己定义的 Downloader Middleware,以及禁用 DOWNLOADER_MIDDLEWARES_BASE 里面定义的 Downloader Middleware。下面我们具体来看看 Downloader Middleware 的使用方法。

2. 核心方法

Scrapy 内置的 Downloader Middleware 为 Scrapy 提供了基础的功能,但在项目实战中我们往往需要单独定义 Downloader Middleware。不用担心,这个过程非常简单,我们只需要实现某几个方法即可。 每个 Downloader Middleware 都定义了一个或多个方法的类,核心的方法有如下三个:

  • process_request(request, spider)
  • process_response(request, response, spider)
  • process_exception(request, exception, spider)

我们只需要实现至少一个方法,就可以定义一个 Downloader Middleware。这三种方法的详析用法可以参考 Python3网络爬虫开发实战教程]。

3. 项目实战

新建一个项目,命令如下所示:

(pyspider) pyvip@VIP:~/project/Python_Spider/Spider_Project/Simple_Case$ scrapy startproject downloader
New Scrapy project 'downloader', using template directory '/home/pyvip/.virtualenvs/pyspider/lib/python3.6/site-packages/scrapy/templates/project', created in:
    /home/pyvip/project/Python_Spider/Spider_Project/Simple_Case/downloader

You can start your first spider with:
    cd downloader
    scrapy genspider example example.com

新建了一个 Scrapy 项目,名为 downloader。进入项目,新建一个 Spider,命令如下所示:

(pyspider) pyvip@VIP:~/project/Python_Spider/Spider_Project/Simple_Case$ cd downloader
(pyspider) pyvip@VIP:~/project/Python_Spider/Spider_Project/Simple_Case/downloader$ cd downloader
(pyspider) pyvip@VIP:~/project/Python_Spider/Spider_Project/Simple_Case/downloader/downloader$ ls
__init__.py  items.py  middlewares.py  pipelines.py  settings.py  spiders
(pyspider) pyvip@VIP:~/project/Python_Spider/Spider_Project/Simple_Case/downloader/downloader$ scrapy genspider httpbin httpbin.org
Created spider 'httpbin' using template 'basic' in module:
  downloader.spiders.httpbin

新建了一个 Spider,名为 httpbin,源代码如下所示:

python">import scrapy
class HttpbinSpider(scrapy.Spider):
    name = 'httpbin'
    allowed_domains = ['httpbin.org']
    start_urls = ['http://httpbin.org/']

    def parse(self, response):
        pass

接下来我们将 parse() 方法添加一行日志输出,将 response 变量的 text 属性输出出来,这样我们便可以看到 Scrapy 发送的 Request 信息了。修改 Spider 内容如下所示:

python">import scrapy

class HttpbinSpider(scrapy.Spider):
    name = 'httpbin'
    allowed_domains = ['httpbin.org']
    start_urls = ['http://httpbin.org/get']

    def parse(self, response):
        self.logger.debug(response.text)

接下来运行此 Spider,执行如下命令:

scrapy crawl httpbin

Scrapy 运行结果包含 Scrapy 发送的 Request 信息,内容如下所示:

python">{"args": {}, 
  "headers": {
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", 
    "Accept-Encoding": "gzip,deflate,br", 
    "Accept-Language": "en", 
    "Connection": "close", 
    "Host": "httpbin.org", 
    "User-Agent": "Scrapy/1.4.0 (+http://scrapy.org)"
  }, 
  "origin": "60.207.237.85", 
  "url": "http://httpbin.org/get"
}

我们观察一下 Headers,Scrapy 发送的 Request 使用的 User-Agent 是 Scrapy/1.4.0 (+http://scrapy.org),这其实是由,这其实是由) Scrapy 内置的 UserAgentMiddleware 设置的,UserAgentMiddleware 的源码如下所示:

python">from scrapy import signals

class UserAgentMiddleware(object):
    def __init__(self, user_agent='Scrapy'):
        self.user_agent = user_agent

    @classmethod
    def from_crawler(cls, crawler):
        o = cls(crawler.settings['USER_AGENT'])
        crawler.signals.connect(o.spider_opened, signal=signals.spider_opened)
        return o

    def spider_opened(self, spider):
        self.user_agent = getattr(spider, 'user_agent', self.user_agent)

    def process_request(self, request, spider):
        if self.user_agent:
            request.headers.setdefault(b'User-Agent', self.user_agent)

在 from_crawler () 方法中,首先尝试获取 settings 里面 USER_AGENT,然后把 USER_AGENT 传递给 init() 方法进行初始化,其参数就是 user_agent。如果没有传递 USER_AGENT 参数就默认设置为 Scrapy 字符串。我们新建的项目没有设置 USER_AGENT,所以这里的 user_agent 变量就是 Scrapy。接下来,在 process_request () 方法中,将 user-agent 变量设置为 headers 变量的一个属性,这样就成功设置了 User-Agent。因此,User-Agent 就是通过此 Downloader Middleware 的 process_request () 方法设置的。

修改请求时的 User-Agent 可以有两种方式:一是修改 settings 里面的 USER_AGENT 变量;二是通过 Downloader Middleware 的 process_request () 方法来修改。 第一种方法非常简单,我们只需要在 setting.py 里面加一行 USER_AGENT 的定义即可:

python">USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Safari/537.36'

一般推荐使用此方法来设置。

但是如果想设置得更灵活,比如设置随机的 User-Agent,那就需要借助 Downloader Middleware 了。所以接下来我们用 Downloader Middleware 实现一个随机 User-Agent 的设置。 在 middlewares.py 里面添加一个 RandomUserAgentMiddleware 的类,如下所示:

python">import random

class RandomUserAgentMiddleware():
    def __init__(self):
        self.user_agents = ['Mozilla/5.0 (Windows; U; MSIE 9.0; Windows NT 9.0; en-US)',
            'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Safari/537.36',
            'Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:15.0) Gecko/20100101 Firefox/15.0.1'
        ]

    def process_request(self, request, spider):
        request.headers['User-Agent'] = random.choice(self.user_agents)

我们首先在类的 init() 方法中定义了三个不同的 User-Agent,并用一个列表来表示。接下来实现了 process_request () 方法,它有一个参数 request,我们直接修改 request 的属性即可。在这里我们直接设置了 request 对象的 headers 属性的 User-Agent,设置内容是随机选择的 User-Agent,这样一个 Downloader Middleware 就写好了。 不过,要使之生效我们还需要再去调用这个 Downloader Middleware。在 settings.py 中,将 DOWNLOADER_MIDDLEWARES 取消注释,并设置成如下内容:

python">DOWNLOADER_MIDDLEWARES = {'scrapydownloadertest.middlewares.RandomUserAgentMiddleware': 543,}

接下来我们重新运行 Spider,就可以看到 User-Agent 被成功修改为列表中所定义的随机的一个 User-Agent 了:

python">{"args": {}, 
  "headers": {
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", 
    "Accept-Encoding": "gzip,deflate,br", 
    "Accept-Language": "en", 
    "Connection": "close", 
    "Host": "httpbin.org", 
    "User-Agent": "Mozilla/5.0 (Windows; U; MSIE 9.0; Windows NT 9.0; en-US)"
  }, 
  "origin": "60.207.237.85", 
  "url": "http://httpbin.org/get"
}

我们就通过实现 Downloader Middleware 并利用 process_request () 方法成功设置了随机的 User-Agent。 另外,Downloader Middleware 还有 process_response () 方法。Downloader 对 Request 执行下载之后会得到 Response,随后 Scrapy 引擎会将 Response 发送回 Spider 进行处理。但是在 Response 被发送给 Spider 之前,我们同样可以使用 process_response () 方法对 Response 进行处理。比如这里修改一下 Response 的状态码,在 RandomUserAgentMiddleware 添加如下代码:

python">def process_response(self, request, response, spider):
    response.status = 201
    return response

我们将 response 对象的 status 属性修改为 201,随后将 response 返回,这个被修改后的 Response 就会被发送到 Spider。 我们再在 Spider 里面输出修改后的状态码,在 parse () 方法中添加如下的输出语句:

python">self.logger.debug('Status Code: ' + str(response.status))

重新运行之后,控制台输出了如下内容:

[httpbin] DEBUG: Status Code: 201

可以发现,Response 的状态码成功修改了。 因此要想对 Response 进行处理,就可以借助于 process_response () 方法。 另外还有一个 process_exception () 方法,它是用来处理异常的方法。如果需要异常处理的话,我们可以调用此方法。不过这个方法的使用频率相对低一些,在此不用实例演示。

上述文章内容如有错误,欢迎各位读者在评论区留言!


http://www.niftyadmin.cn/n/1190200.html

相关文章

隐藏Tengine的版本信息

http {.....server_tokens on;server_info on;server_tag bass;reset_timedout_connection on;keepalive_timeout 120;keepalive_requests 100;sendfile on;tcp_nodelay on;tcp_nopush off;..... }当网页不存在时会显示如下图: 修改为: serv…

爬虫框架Scrapy(6)Spider Middleware 的用法

文章目录五. Spider Middleware 的用法1. 使用说明2. 核心方法五. Spider Middleware 的用法 Spider Middleware 是介入到 Scrapy 的 Spider 处理机制的钩子框架。当 Downloader 生成 Response 之后,Response 会被发送给 Spider,在发送给 Spider 之前&a…

android graphic(15)—fence

为何须要fence fence怎样使用 软件实现的opengl 硬件实现的opengl 上层使用canvas画图 上层使用opengl画图 下层合成 updateTexImage doComposeSurfaces DisplayDevice和FramebufferSurface 关于fence。不错的參考文章http://blog.csdn.net/jinzhuojun/article/details/…

爬虫框架Scrapy(7)Itme Pipeline 的用法

文章目录一. Itme Pipeline 的用法1. 实现 Item Pipeline2. 核心方法(1)process_item(item, spider)(2)open_spider(self, spider)(3)close_spider(spider)(4)from_crawler(cls, cra…

Vue.js 基础指令实例讲解(各种数据绑定、表单渲染大总结)——新手入门、高手进阶第一篇...

Vue.js 是一套构建用户界面的渐进式框架。他自身不是一个全能框架——只聚焦于视图层。因此它非常容易学习,非常容易与其它库或已有项目整合。在与相关工具和支持库一起使用时,Vue.js 也能完美地驱动复杂的单页应用。他的语法和 AngularJS特别相像&#…

爬虫框架Scrapy(8)使用 LinkExtractor 提取链接

文章目录使用 LinkExtractor 提取链接1. 提取链接的方法(1)使用Selector(2)使用LinkExtractor2. LinkExtractor 提取链接的规则(1)allow(2)deny(3)allow_doma…

百度编辑器图片在线流量返回url改动

百度编辑器中返回的是我们server中的url,有时并非我们须要的,比方图文编辑中。我想在线浏览上传过的图片 ,那么我返回的应该是腾讯server上面的url。这样才不会被腾讯的过滤器过来掉,全部我们就须要改动在线管理的图片获取路径详细…

爬虫框架Scrapy(9)使用 Exporter 导出数据

文章目录使用 Exporter 导出数据1. 指定数据导出方法(1)命令行参数指定数据导出方式(2)配置文件指定数据导出方式2. 添加数据导出格式使用 Exporter 导出数据 在 Scrapy 中,负责导出数据的组件被称为 Exporter&#x…