Scrapy 下载器中间件官方文档:https://scrapy-chs.readthedocs.io/zh_CN/1.0/topics/downloader-middleware.html
官方 英文 文档:http://doc.scrapy.org/en/latest/topics/downloader-middleware.htmltopics-downloader-middleware
Scrapy 扩展中间件: 针对特定响应状态码,使用代理重新请求:https://www.cnblogs.com/my8100/p/scrapy_middleware_autoproxy.html
https://www.baidu.com/s?wd=中间件状态码不等于200重新请求
下载器中间件是介于Scrapy的request/response处理的钩子框架。 是用于全局修改Scrapy request和response的一个轻量、底层的系统。
用容易理解的话表述就是:更换代理IP,更换Cookies,更换User-Agent,自动重试 等。
1. 如果完全没有中间件,爬虫的流程如下图所示。
2. 使用了中间件以后,爬虫的流程如下图所示。
要激活下载器中间件组件,将其加入到 DOWNLOADER_MIDDLEWARES
设置中。 该设置是一个字典(dict),键为中间件类的路径,值为其中间件的顺序(order)。
这里是一个例子:
- DOWNLOADER_MIDDLEWARES = {
- 'myproject.middlewares.CustomDownloaderMiddleware': 543,
- }
DOWNLOADER_MIDDLEWARES
设置会与 Scrapy 定义的 DOWNLOADER_MIDDLEWARES_BASE
设置合并(但不是覆盖), 而后根据顺序(order)进行排序,最后得到启用中间件的有序列表: 第一个中间件是最靠近引擎的,最后一个中间件是最靠近下载器的。
关于如何分配中间件的顺序请查看 DOWNLOADER_MIDDLEWARES_BASE
设置,而后根据您想要放置中间件的位置选择一个值。 由于每个中间件执行不同的动作,您的中间件可能会依赖于之前(或者之后)执行的中间件,因此顺序是很重要的。
如果您想禁止内置的(在 DOWNLOADER_MIDDLEWARES_BASE
中设置并默认启用的)中间件, 您必须在项目的 DOWNLOADER_MIDDLEWARES
设置中定义该中间件,并将其值赋为 None 。 例如,如果您想要关闭user-agent中间件:
- DOWNLOADER_MIDDLEWARES = {
- 'myproject.middlewares.CustomDownloaderMiddleware': 543,
- 'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware': None,
- }
最后,请注意,有些中间件需要通过特定的设置来启用。更多内容请查看相关中间件文档。
编写下载器中间件十分简单。每个中间件组件是一个定义了以下一个或多个方法的Python类:
class scrapy.downloadermiddlewares.DownloaderMiddleware
当每个 request 通过下载中间件时,该方法被调用。
参数:
返回值:process_request()
必须返回其中之一:
None
。如果其返回 None
,Scrapy将继续处理该request,执行其他的中间件的相应方法,直到合适的下载器处理函数(download handler)被调用, 该request被执行(其response被下载)。Response
对象。如果其返回 Response
对象,Scrapy将不会调用 任何 其他的 process_request()
或 process_exception()
方法,或相应地下载函数; 其将返回该response。 已安装的中间件的 process_response()
方法则会在每个response返回时被调用。Request
对象。如果其返回 Request
对象,Scrapy则停止调用 process_request方法并重新调度返回的request。当新返回的request被执行后, 相应地中间件链将会根据下载的response被调用。IgnoreRequest
。如果其raise一个 IgnoreRequest
异常,则安装的下载中间件的 process_exception()
方法会被调用。如果没有任何一个方法处理该异常, 则request的errback(Request.errback
)方法会被调用。如果没有代码处理抛出的异常, 则该异常被忽略且不记录(不同于其他异常那样)。解释:
参数:
Request
对象) – response所对应的requestResponse
对象) – 被处理的responseSpider
对象) – response所对应的spider返回值:process_request()
必须返回以下之一:
Response
对象。如果其返回一个 Response
(可以与传入的response相同,也可以是全新的对象), 该response会被在链中的其他中间件的 process_response()
方法处理。Request
对象。如果其返回一个 Request
对象,则中间件链停止, 返回的request会被重新调度下载。处理类似于 process_request()
返回request所做的那样。IgnoreRequest
异常。如果其抛出一个 IgnoreRequest
异常,则调用request的errback(Request.errback
)。 如果没有代码处理抛出的异常,则该异常被忽略且不记录(不同于其他异常那样)。解释:
当下载处理器 ( download handler ) 或 process_request()
( 下载中间件 ) 抛出异常 ( 包括 IgnoreRequest
异常) 时, Scrapy 调用 process_exception()
。
参数:
Request
对象) – 产生异常的requestException
对象) – 抛出的异常Spider
对象) – request对应的spider返回值:process_exception()
应该返回以下之一:
None
。如果其返回 None
,Scrapy将会继续处理该异常,接着调用已安装的其他中间件的 process_exception()
方法,直到所有中间件都被调用完毕,则调用默认的异常处理。Response
对象。如果其返回一个 Response
对象,则已安装的中间件链的 process_response()
方法被调用。Scrapy将不会调用任何其他中间件的 process_exception()
方法。Request
对象。如果其返回一个 Request
对象, 则返回的request将会被重新调用下载。这将停止中间件的 process_exception()
方法执行,就如返回一个response的那样。解释:
If present, this classmethod is called to create a middleware instance from a Crawler
. It must return a new instance of the middleware. Crawler object provides access to all Scrapy core components like settings and signals; it is a way for middleware to access them and hook its functionality into Scrapy.
Parameters: | crawler (Crawler object) – crawler that uses this middleware |
---|
scrapy 中的 from_crawler:https://www.jianshu.com/p/e9ec5d7b6204
解释:
在爬虫开发中,更换代理IP是非常常见的情况,有时候每一次访问都需要随机选择一个代理IP来进行。
中间件本身是一个Python的类,只要爬虫每次访问网站之前都先“经过”这个类,它就能给请求换新的代理IP,这样就能实现动态改变代理。
在创建一个Scrapy工程以后,工程文件夹下会有一个 middlewares.py 文件,打开以后其内容如下图所示。
Scrapy 自动生成的这个文件名称为 middlewares.py,名字后面的 s 表示复数,说明这个文件里面可以放很多个中间件。可以看到有一个 SpiderMiddleware (爬虫中间件)中间件 和 DownloaderMiddleware (下载中间件)中间件
在middlewares.py中添加下面一段代码(可以在 下载中间件这个类 里面写,也可以把 爬虫中间件 和 下载中间件 这两个类删了,自己写个 下载中间件的类。推荐 自己单写一个类 作为 下载中间件):
- -*- coding: utf-8 -*-
-
- Define here the models for your spider middleware
- See documentation in:
- https://doc.scrapy.org/en/latest/topics/spider-middleware.html
-
-
- import random
- from scrapy.conf import settings
- from scrapy.utils.project import get_project_settings
-
-
- class ProxyMiddleware(-title class_ inherited__">object):
-
- def process_request(self, request, spider):
- proxy_1 = random.choice(settings['PROXIES']) 方法 1
- proxy_2 = random.choice(get_project_settings()['PROXIES']) 方法 2
- request.meta['proxy'] = proxy_1
打开 setting.py 添加 代理 ,并激活 这个代理中间件:
需要注意的是,代理IP是有类型的,需要先看清楚是 HTTP型 的代理IP还是 HTTPS型 的代理IP。
- DOWNLOADER_MIDDLEWARES = {
- 'test_spider.middlewares.ProxyMiddleware': 543,
- 'test_spider.middlewares.Custom_B_DownloaderMiddleware': 643,
- 'test_spider.middlewares.Custom_B_DownloaderMiddleware': None,
- }
-
- PROXIES = [
- 'https://114.217.243.25:8118',
- 'https://125.37.175.233:8118',
- 'http://1.85.116.218:8118'
- ]
DOWNLOADER_MIDDLEWARES 其实就是一个字典,字典的Key就是用点分隔的中间件路径,后面的数字表示这种中间件的顺序。由于中间件是按顺序运行的,因此如果遇到后一个中间件依赖前一个中间件的情况,中间件的顺序就至关重要。
如何确定后面的数字应该怎么写呢?最简单的办法就是从543开始,逐渐加一,这样一般不会出现什么大问题。如果想把中间件做得更专业一点,那就需要知道Scrapy自带中间件的顺序,如图下图所示 ( DOWNLOADER_MIDDLEWARES
)。
数字越小的中间件越先执行(数字越小,越靠近引擎,数字越大越靠近下载器,所以数字越小的,processrequest()优先处理;数字越大的,process_response()优先处理;若需要关闭某个中间件直接设为None即可),例如Scrapy自带的第1个中间件RobotsTxtMiddleware,它的作用是首先查看settings.py中ROBOTSTXT_OBEY 这一项的配置是True还是False。如果是True,表示要遵守Robots.txt协议,它就会检查将要访问的网址能不能被运行访问,如果不被允许访问,那么直接就取消这一次请求,接下来的和这次请求有关的各种操作全部都不需要继续了。
开发者自定义的中间件,会被按顺序插入到Scrapy自带的中间件中。爬虫会按照从100~900的顺序依次运行所有的中间件。直到所有中间件全部运行完成,或者遇到某一个中间件而取消了这次请求。
Scrapy 其实自带了 UA 中间件(UserAgentMiddleware)、代理中间件(HttpProxyMiddleware)和重试中间件(RetryMiddleware)。所以,从“原则上”说,要自己开发这3个中间件,需要先禁用Scrapy里面自带的这3个中间件。要禁用Scrapy的中间件,需要在settings.py里面将这个中间件的顺序设为None:
- DOWNLOADER_MIDDLEWARES = {
- 'test_spider.middlewares.ProxyMiddleware': 543,
- 'scrapy.contrib.downloadermiddleware.useragent.UserAgentMiddleware': None,
- 'scrapy.contrib.downloadermiddleware.httpproxy.HttpProxyMiddleware': None
- }
-
- PROXIES = [
- 'https://114.217.243.25:8118',
- 'https://125.37.175.233:8118',
- 'http://1.85.116.218:8118'
- ]
为什么说“原则上”应该禁用呢?先查看Scrapy自带的代理中间件的源代码,如下图所示:
从上图可以看出,如果Scrapy发现这个请求已经被设置了代理,那么这个中间件就会什么也不做,直接返回。因此虽然Scrapy自带的这个代理中间件顺序为750,比开发者自定义的代理中间件的顺序543大,但是它并不会覆盖开发者自己定义的代理信息,所以即使不禁用系统自带的这个代理中间件也没有关系。
代理中间件的可用代理列表不一定非要写在settings.py里面,也可以将它们写到数据库或者Redis中。一个可行的自动更换代理的爬虫系统,应该有如下的3个功能。
scrapy 中对接 selenium
- from scrapy.http import HtmlResponse
- from selenium import webdriver
- from selenium.common.exceptions import TimeoutException
- from gp.configs import *
-
-
- class ChromeDownloaderMiddleware(-title class_ inherited__">object):
-
- def __init__(self):
- options = webdriver.ChromeOptions()
- options.add_argument('--headless') 设置无界面
- if CHROME_PATH:
- options.binary_location = CHROME_PATH
- if CHROME_DRIVER_PATH:
- self.driver = webdriver.Chrome(chrome_options=options, executable_path=CHROME_DRIVER_PATH) 初始化Chrome驱动
- else:
- self.driver = webdriver.Chrome(chrome_options=options) 初始化Chrome驱动
-
- def __del__(self):
- self.driver.close()
-
- def process_request(self, request, spider):
- try:
- print('Chrome driver begin...')
- self.driver.get(request.url) 获取网页链接内容
- return HtmlResponse(url=request.url, body=self.driver.page_source, request=request, encoding='utf-8',
- status=200) 返回HTML数据
- except TimeoutException:
- return HtmlResponse(url=request.url, request=request, encoding='utf-8', status=500)
- finally:
- print('Chrome driver end...')
Scrapy学习篇(十一)之设置随机User-Agent:https://www.cnblogs.com/cnkai/p/7401343.html
开发UA中间件和开发代理中间件几乎一样,它也是从 settings.py 配置好的 UA 列表中随机选择一项,加入到请求头中。代码如下:
- class UAMiddleware(-title class_ inherited__">object):
-
- def process_request(self, request, spider):
- ua = random.choice(settings['USER_AGENT_LIST'])
- request.headers['User-Agent'] = ua
比IP更好的是,UA不会存在失效的问题,所以只要收集几十个UA,就可以一直使用。常见的UA如下:
- USER_AGENT_LIST = [
- "Mozilla/5.0 (Linux; U; Android 2.3.6; en-us; Nexus S Build/GRK39F) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1",
- "Avant Browser/1.2.789rel1 (http://www.avantbrowser.com)",
- "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/532.5 (KHTML, like Gecko) Chrome/4.0.249.0 Safari/532.5",
- "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US) AppleWebKit/532.9 (KHTML, like Gecko) Chrome/5.0.310.0 Safari/532.9",
- "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Chrome/7.0.514.0 Safari/534.7",
- "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/534.14 (KHTML, like Gecko) Chrome/9.0.601.0 Safari/534.14",
- "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.14 (KHTML, like Gecko) Chrome/10.0.601.0 Safari/534.14",
- "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.20 (KHTML, like Gecko) Chrome/11.0.672.2 Safari/534.20",
- "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.27 (KHTML, like Gecko) Chrome/12.0.712.0 Safari/534.27",
- "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.24 Safari/535.1",
- "Mozilla/5.0 (Windows NT 6.0) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.874.120 Safari/535.2",
- "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.7 (KHTML, like Gecko) Chrome/16.0.912.36 Safari/535.7",
- "Mozilla/5.0 (Windows; U; Windows NT 6.0 x64; en-US; rv:1.9pre) Gecko/2008072421 Minefield/3.0.2pre",
- "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.10) Gecko/2009042316 Firefox/3.0.10",
- "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-GB; rv:1.9.0.11) Gecko/2009060215 Firefox/3.0.11 (.NET CLR 3.5.30729)",
- "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6 GTB5",
- "Mozilla/5.0 (Windows; U; Windows NT 5.1; tr; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8 ( .NET CLR 3.5.30729; .NET4.0E)",
- "Mozilla/5.0 (Windows NT 6.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1",
- "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:2.0.1) Gecko/20100101 Firefox/4.0.1",
- "Mozilla/5.0 (Windows NT 5.1; rv:5.0) Gecko/20100101 Firefox/5.0",
- "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:6.0a2) Gecko/20110622 Firefox/6.0a2",
- "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:7.0.1) Gecko/20100101 Firefox/7.0.1",
- "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:2.0b4pre) Gecko/20100815 Minefield/4.0b4pre",
- "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0 )",
- "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90)",
- "Mozilla/5.0 (Windows; U; Windows XP) Gecko MultiZilla/1.6.1.0a",
- "Mozilla/2.02E (Win95; U)",
- "Mozilla/3.01Gold (Win95; I)",
- "Mozilla/4.8 [en] (Windows NT 5.1; U)",
- "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.4) Gecko Netscape/7.1 (ax)",
- "HTC_Dream Mozilla/5.0 (Linux; U; Android 1.5; en-ca; Build/CUPCAKE) AppleWebKit/528.5 (KHTML, like Gecko) Version/3.1.2 Mobile Safari/525.20.1",
- "Mozilla/5.0 (hp-tablet; Linux; hpwOS/3.0.2; U; de-DE) AppleWebKit/534.6 (KHTML, like Gecko) wOSBrowser/234.40.1 Safari/534.6 TouchPad/1.0",
- "Mozilla/5.0 (Linux; U; Android 1.5; en-us; sdk Build/CUPCAKE) AppleWebkit/528.5 (KHTML, like Gecko) Version/3.1.2 Mobile Safari/525.20.1",
- "Mozilla/5.0 (Linux; U; Android 2.1; en-us; Nexus One Build/ERD62) AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Mobile Safari/530.17",
- "Mozilla/5.0 (Linux; U; Android 2.2; en-us; Nexus One Build/FRF91) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1",
- "Mozilla/5.0 (Linux; U; Android 1.5; en-us; htc_bahamas Build/CRB17) AppleWebKit/528.5 (KHTML, like Gecko) Version/3.1.2 Mobile Safari/525.20.1",
- "Mozilla/5.0 (Linux; U; Android 2.1-update1; de-de; HTC Desire 1.19.161.5 Build/ERE27) AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Mobile Safari/530.17",
- "Mozilla/5.0 (Linux; U; Android 2.2; en-us; Sprint APA9292KT Build/FRF91) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1",
- "Mozilla/5.0 (Linux; U; Android 1.5; de-ch; HTC Hero Build/CUPCAKE) AppleWebKit/528.5 (KHTML, like Gecko) Version/3.1.2 Mobile Safari/525.20.1",
- "Mozilla/5.0 (Linux; U; Android 2.2; en-us; ADR6300 Build/FRF91) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1",
- "Mozilla/5.0 (Linux; U; Android 2.1; en-us; HTC Legend Build/cupcake) AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Mobile Safari/530.17",
- "Mozilla/5.0 (Linux; U; Android 1.5; de-de; HTC Magic Build/PLAT-RC33) AppleWebKit/528.5 (KHTML, like Gecko) Version/3.1.2 Mobile Safari/525.20.1 FirePHP/0.3",
- "Mozilla/5.0 (Linux; U; Android 1.6; en-us; HTC_TATTOO_A3288 Build/DRC79) AppleWebKit/528.5 (KHTML, like Gecko) Version/3.1.2 Mobile Safari/525.20.1",
- "Mozilla/5.0 (Linux; U; Android 1.0; en-us; dream) AppleWebKit/525.10 (KHTML, like Gecko) Version/3.0.4 Mobile Safari/523.12.2",
- "Mozilla/5.0 (Linux; U; Android 1.5; en-us; T-Mobile G1 Build/CRB43) AppleWebKit/528.5 (KHTML, like Gecko) Version/3.1.2 Mobile Safari 525.20.1",
- "Mozilla/5.0 (Linux; U; Android 1.5; en-gb; T-Mobile_G2_Touch Build/CUPCAKE) AppleWebKit/528.5 (KHTML, like Gecko) Version/3.1.2 Mobile Safari/525.20.1",
- "Mozilla/5.0 (Linux; U; Android 2.0; en-us; Droid Build/ESD20) AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Mobile Safari/530.17",
- "Mozilla/5.0 (Linux; U; Android 2.2; en-us; Droid Build/FRG22D) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1",
- "Mozilla/5.0 (Linux; U; Android 2.0; en-us; Milestone Build/ SHOLS_U2_01.03.1) AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Mobile Safari/530.17",
- "Mozilla/5.0 (Linux; U; Android 2.0.1; de-de; Milestone Build/SHOLS_U2_01.14.0) AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Mobile Safari/530.17",
- "Mozilla/5.0 (Linux; U; Android 3.0; en-us; Xoom Build/HRI39) AppleWebKit/525.10 (KHTML, like Gecko) Version/3.0.4 Mobile Safari/523.12.2",
- "Mozilla/5.0 (Linux; U; Android 0.5; en-us) AppleWebKit/522 (KHTML, like Gecko) Safari/419.3",
- "Mozilla/5.0 (Linux; U; Android 1.1; en-gb; dream) AppleWebKit/525.10 (KHTML, like Gecko) Version/3.0.4 Mobile Safari/523.12.2",
- "Mozilla/5.0 (Linux; U; Android 2.0; en-us; Droid Build/ESD20) AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Mobile Safari/530.17",
- "Mozilla/5.0 (Linux; U; Android 2.1; en-us; Nexus One Build/ERD62) AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Mobile Safari/530.17",
- "Mozilla/5.0 (Linux; U; Android 2.2; en-us; Sprint APA9292KT Build/FRF91) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1",
- "Mozilla/5.0 (Linux; U; Android 2.2; en-us; ADR6300 Build/FRF91) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1",
- "Mozilla/5.0 (Linux; U; Android 2.2; en-ca; GT-P1000M Build/FROYO) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1",
- "Mozilla/5.0 (Linux; U; Android 3.0.1; fr-fr; A500 Build/HRI66) AppleWebKit/534.13 (KHTML, like Gecko) Version/4.0 Safari/534.13",
- "Mozilla/5.0 (Linux; U; Android 3.0; en-us; Xoom Build/HRI39) AppleWebKit/525.10 (KHTML, like Gecko) Version/3.0.4 Mobile Safari/523.12.2",
- "Mozilla/5.0 (Linux; U; Android 1.6; es-es; SonyEricssonX10i Build/R1FA016) AppleWebKit/528.5 (KHTML, like Gecko) Version/3.1.2 Mobile Safari/525.20.1",
- "Mozilla/5.0 (Linux; U; Android 1.6; en-us; SonyEricssonX10i Build/R1AA056) AppleWebKit/528.5 (KHTML, like Gecko) Version/3.1.2 Mobile Safari/525.20.1",
- ]
test_spider.py (使用 的是 scrapy-redis 的 RedisSpider,需要从 redis
网站声明:如果转载,请联系本站管理员。否则一切后果自行承担。
加入交流群
请使用微信扫一扫!