小白学 Python 爬虫(36):爬虫框架 Scrapy 入门基础(四) Downloader Middleware

时间:2021-06-11 04:31:21

小白学 Python 爬虫(36):爬虫框架 Scrapy 入门基础(四) Downloader Middleware

人生苦短,我用 Python

前文传送门:

小白学 Python 爬虫(1):开篇

小白学 Python 爬虫(2):前置准备(一)基本类库的安装

小白学 Python 爬虫(3):前置准备(二)Linux基础入门

小白学 Python 爬虫(4):前置准备(三)Docker基础入门

小白学 Python 爬虫(5):前置准备(四)数据库基础

小白学 Python 爬虫(6):前置准备(五)爬虫框架的安装

小白学 Python 爬虫(7):HTTP 基础

小白学 Python 爬虫(8):网页基础

小白学 Python 爬虫(9):爬虫基础

小白学 Python 爬虫(10):Session 和 Cookies

小白学 Python 爬虫(11):urllib 基础使用(一)

小白学 Python 爬虫(12):urllib 基础使用(二)

小白学 Python 爬虫(13):urllib 基础使用(三)

小白学 Python 爬虫(14):urllib 基础使用(四)

小白学 Python 爬虫(15):urllib 基础使用(五)

小白学 Python 爬虫(16):urllib 实战之爬取妹子图

小白学 Python 爬虫(17):Requests 基础使用

小白学 Python 爬虫(18):Requests 进阶操作

小白学 Python 爬虫(19):Xpath 基操

小白学 Python 爬虫(20):Xpath 进阶

小白学 Python 爬虫(21):解析库 Beautiful Soup(上)

小白学 Python 爬虫(22):解析库 Beautiful Soup(下)

小白学 Python 爬虫(23):解析库 pyquery 入门

小白学 Python 爬虫(24):2019 豆瓣电影排行

小白学 Python 爬虫(25):爬取股票信息

小白学 Python 爬虫(26):为啥买不起上海二手房你都买不起

小白学 Python 爬虫(27):自动化测试框架 Selenium 从入门到放弃(上)

小白学 Python 爬虫(28):自动化测试框架 Selenium 从入门到放弃(下)

小白学 Python 爬虫(29):Selenium 获取某大型电商网站商品信息

小白学 Python 爬虫(30):代理基础

小白学 Python 爬虫(31):自己构建一个简单的代理池

小白学 Python 爬虫(32):异步请求库 AIOHTTP 基础入门

小白学 Python 爬虫(33):爬虫框架 Scrapy 入门基础(一)

小白学 Python 爬虫(34):爬虫框架 Scrapy 入门基础(二)

小白学 Python 爬虫(35):爬虫框架 Scrapy 入门基础(三) Selector 选择器

引言

Downloader Middleware 直译过来是下载器中间件,本文后续就叫它下载中间件了。

下载器中间件主要用于 Scrapy 的 Request 和 Response 处理。

Downloader Middleware 的功能非常的强大,可以修改 UA 头、处理重定向、设置代理、设置超时时间、失败重试、设置 Cookies 等功能。

内置下载器中间件

Scrapy 已经为我们提供相当多的内置的下载器中间件,用于各种功能,列表如下:

{
'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,
}

这些列表定义在 DOWNLOADER_MIDDLEWARES_BASE 变量中。

这些列表的数据结构是一个字典格式,后面的值代表了优先级,数字越小代表了越靠近 Scrapy 引擎,数字越大越靠近下载器,数字小的会被优先调用。

自定义下载器中间件

如果要在项目自定义一个下载器中间件,需要我们自己设置 DOWNLOADER_MIDDLEWARES 这个变量,这个变量位于 settings.py ,默认是注释状态,当我们需要的时候直接打开这个注释就可以了,这里不仅可以自定义我们所需要的下载器中间件,还可以禁用 DOWNLOADER_MIDDLEWARES_BASE 中定义的下载器中间件。

每个下载器中间件都是一个Python类,该类定义了以下定义的一个或多个方法。

核心方法共有 4 个,如下:

  • process_request(request, spider)
  • process_response(request, response, spider)
  • process_exception(request, exception, spider)
  • from_crawler(cls, crawler)

而我们至少只需要实现其中的一个方法就可以定义一个下载器中间件。

process_request(request, spider)

参数:

  • request(Request对象)–正在处理的请求
  • spider(Spider对象)–此请求所针对的蜘蛛

对于通过下载中间件的每个请求,都会调用此方法。

process_request() 应该是:return None,返回一个 Response 对象,返回一个Request 对象或引发 IgnoreRequest 异常。

如果返回 None ,则 Scrapy 将继续处理此请求,执行所有其他中间件,直到最终将适当的下载程序处理程序称为执行的请求(并下载了其响应)。

如果它返回一个 Response 对象, Scrapy 不会打扰调用任何其他 process_request() 或 process_exception() 方法,或相应的下载功能; 它将返回该响应。 process_response() 总是在每个响应上调用已安装中间件的方法。

如果返回一个 Request 对象, Scrapy 将停止调用 process_request 方法并重新计划返回的请求。一旦执行了新返回的请求,就会在下载的响应上调用适当的中间件链。

如果引发 IgnoreRequest 异常,则所有的下载器中间件的方法 process_exception() 会依次执行,如果没有一个方法处理该异常,那么 Request 的 errback() 方法就会回调,如果该异常还没处理,那么就会忽略。

process_response(request, response, spider)

参数:

  • request (是一个 Request 对象)–发起响应的请求
  • response (response 对象)–正在处理的响应
  • spider (spider 对象)–此响应预期用于的蜘蛛

process_response() 应该:返回响应对象,返回请求对象或引发 IgnoreRequest 异常。

如果它返回一个 Response (它可以是相同的给定响应,也可以是全新的响应),那么该响应将继续使用链中下一个中间件的 process_response() 进行处理。

如果它返回一个 Request 对象,则中间件链将暂停,并将返回的请求重新安排为将来下载。 这与从 process_request() 返回请求的行为相同。

如果引发 IgnoreRequest 异常,则调用请求的 errback 函数(Request.errback)。 如果没有代码处理引发的异常,则将其忽略并且不记录(与其他异常不同)。

process_exception(request, exception, spider)

参数:

  • request (是一个Request对象)–生成异常的请求
  • exception (Exception对象)–引发的异常
  • spider (spider对象)–此请求所针对的蜘蛛

当下载处理程序或 process_request() (从下载程序中间件中)引发异常(包括 IgnoreRequest 异常)时, Scrapy 会调用 process_exception() 。

process_exception() 应该返回:无,响应对象或请求对象。

如果返回 None ,则 Scrapy 将继续处理此异常,执行已安装中间件的任何其他 process_exception() 方法,直到没有中间件为止,并且默认异常处理开始。

如果返回 Response 对象,则会启动已安装中间件的 process_response() 方法链,并且 Scrapy 不会费心调用中间件的任何其他 process_exception() 方法。

如果它返回一个 Request 对象,则将返回的请求重新安排为将来下载。 这将停止执行中间件的 process_exception() 方法,就像返回响应一样。

from_crawler(cls, crawler)

参数:

  • crawler(搜寻器对象)–使用此中间件的搜寻器

如果存在,则调用该类方法以从 Crawler 创建中间件实例。 它必须返回中间件的新实例。 搜寻器对象提供对所有 Scrapy 核心组件(如设置和信号)的访问; 它是中间件访问它们并将其功能连接到 Scrapy 中的一种方式。

示例

首先,我们还是在前面的 Scrapy 的项目上新建一个 Spider ,具体代码如下:

# -*- coding: utf-8 -*-
import scrapy class HttpbinSpider(scrapy.Spider):
name = 'httpbin'
allowed_domains = ['httpbin.org']
start_urls = ['https://httpbin.org/get'] def parse(self, response):
self.logger.debug(response.text)

使用如下命令运行一下:

scrapy crawl httpbin

结果部分截取如下:

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

可以看到,这里的 UA 头是 Scrapy/1.8.0 (+https://scrapy.org) ,这个其实是由 Scrapy 内置的 UserAgentMiddleware 设置的。

这里我们通过修改一下 UA 头,当然修改 UA 头可以通过 settings 中的 USER_AGENT 进行设置,这里我们要演示下载器中间件嘛,所以就使用下载器中间件设置一下。

首先我们在 middlewares.py 中新增一个 UaDownLoaderMiddleware ,示例代码如下:

class UaDownLoaderMiddleware(object):

    def process_request(self, request, spider):

        request.headers['User-Agent'] = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36'

新增完成后,还需要在配置文件 settings 中开启这个下载器中间件,找到 DOWNLOADER_MIDDLEWARES ,将注释去掉,修改为:

DOWNLOADER_MIDDLEWARES = {
'first_scrapy.middlewares.UaDownLoaderMiddleware': 543,
}

到这里,我们的修改就完成了,可以重新运行这只爬虫:

scrapy crawl httpbin

结果部分截取如下:

{
"args": {},
"headers": {
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Accept-Encoding": "gzip,deflate,br",
"Accept-Language": "en",
"Host": "httpbin.org",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36"
},
"origin": "183.195.68.215, 183.195.68.215",
"url": "https://httpbin.org/get"
}

可以看到,这里响应的 UA 已经变成了我们刚才设置的 UA 头,证明我们的修改是成功的。

本篇就先到这里了,希望各位同学可以自己动手试一下。

示例代码

本系列的所有代码小编都会放在代码管理仓库 Github 和 Gitee 上,方便大家取用。

示例代码-Github

示例代码-Gitee

参考

https://docs.scrapy.org/en/latest/topics/settings.html#std:setting-DOWNLOADER_MIDDLEWARES_BASE

https://docs.scrapy.org/en/latest/topics/downloader-middleware.html