一、中间件介绍
中间件是 Scrapy 里面的一个核心概念。使用中间件可以在爬虫的请求发起之前或者请求返回之后对数据进行定制化修改,从而开发出适应不同情况的爬虫。
“中间件”这个中文名字和前面章节讲到的“中间人”只有一字之差。它们做的事情确实也非常相似。中间件和中间人都能在中途劫持数据,做一些修改再把数据传递出去。不同点在于,中间件是开发者主动加进去的组件,而中间人是被动的,一般是恶意地加进去的环节。中间件主要用来辅助开发,而中间人却多被用来进行数据的窃取、伪造甚至攻击。
在Scrapy中有两种中间件:下载器中间件(Downloader Middleware)和爬虫中间件(Spider Middleware)。
ps:中间件离哪个模块近就称为什么中间件,另外平时主要用下载中间件,因为爬虫中间件使用方法和下载中间件相同,且功能重复,所以通常使用下载中间件。
二、中间件的作用
中间件可以用于修改Scrapy请求和响应的行为,例如更改请求头、处理代理、处理cookies、实现自定义的重试策略、实现自定义的下载延迟逻辑等。
- 修改请求和响应:中间件可以拦截请求和响应,对其进行修改或添加额外信息,如修改请求头、添加代理、处理cookies等。
- 处理异常:中间件可以捕获和处理请求过程中的异常,实现自定义的异常处理逻辑。
- 实现下载延迟:可以在中间件中实现自定义的下载延迟逻辑,控制请求发送的时间间隔。
- 实现自定义的重试策略:通过中间件可以实现自定义的重试逻辑,例如根据特定的条件决定是否重新发送请求。
- 处理HTTP代理:中间件可以实现代理的切换和管理,以便在爬取过程中使用不同的代理IP。
- 日志记录:中间件可以用于记录请求、响应的信息,方便调试和监控爬虫的运行状态。
- 数据处理:可以在中间件中对爬取到的数据进行处理,如数据清洗、格式转换等。
通过编写自定义的中间件,用户可以灵活地扩展和定制Scrapy框架的功能,以满足特定的爬取需求和处理逻辑。 Scrapy提供了一系列的中间件接口,用户可以根据自己的需求实现这些接口来编写自己的中间件。
三、爬虫中间件
1、源码
# 爬虫中间件
class ScrapydemmoSpiderMiddleware:
# Not all methods need to be defined. If a method is not defined,
# scrapy acts as if the spider middleware does not modify the
# passed objects.
@classmethod
def from_crawler(cls, crawler):
# 该方法是Scrapy用于创建爬虫实例的方法。
# This method is used by Scrapy to create your spiders.
s = cls()
crawler.signals.connect(s.spider_opened, signal=signals.spider_opened)
return s
def process_spider_input(self, response, spider):
# 当响应从爬虫中间件进入爬虫时,调用该方法进行处理。
# 应返回None或引发异常。
# Called for each response that goes through the spider
# middleware and into the spider.
# Should return None or raise an exception.
return None
def process_spider_output(self, response, result, spider):
# 当爬虫处理完响应后,调用该方法对处理结果进行处理。
# 必须返回一个可迭代的Request对象或item对象。
# Called with the results returned from the Spider, after
# it has processed the response.
# Must return an iterable of Request, or item objects.
for i in result:
yield i
def process_spider_exception(self, response, exception, spider):
# 当爬虫中抛出异常时,调用该方法进行处理。
# 应返回None或者一个可迭代的Request对象或item对象。
# Called when a spider or process_spider_input() method
# (from other spider middleware) raises an exception.
# Should return either None or an iterable of Request or item objects.
pass
def process_start_requests(self, start_requests, spider):
# 在爬虫启动时,对初始请求进行处理。
# Called with the start requests of the spider, and works
# similarly to the process_spider_output() method, except
# that it doesn’t have a response associated.
# Must return only requests (not items).
for r in start_requests:
yield r
def spider_opened(self, spider):
spider.logger.info("Spider opened: %s" % spider.name)
2、方法介绍
(1)def from_crawler(cls, crawler)
from_crawler
方法是一个类方法,它会在创建爬虫实例时被Scrapy调用,用于初始化爬虫中间件的实例。在该方法中,首先创建了一个中间件实例 s
,然后通过 crawler.signals.connect
方法连接了 spider_opened
信号和对应的处理方法。
(2)def process_spider_input(self, response, spider)
process_spider_input
方法会在响应从爬虫中间件传递到爬虫之前调用。它接收两个参数:response
是响应对象,spider
是当前爬虫实例。这个方法可以用来对响应进行预处理或检查。应该返回 None
或引发异常。
(3)def process_spider_output(self, response, result, spider)
process_spider_output
方法在爬虫处理完响应后会被调用。它接收三个参数:response
是爬虫处理后的响应对象,result
是爬虫的处理结果,spider
是当前爬虫实例。这个方法主要用于对爬虫处理结果进行进一步处理或过滤,并将处理结果返回。必须返回一个可迭代的Request对象或item对象。
(4)def process_spider_exception(self, response, exception, spider)
process_spider_exception
方法在爬虫或 process_spider_input()
方法中抛出异常时会被调用。它接收三个参数:response
是发生异常的响应对象,exception
是抛出的异常对象,spider
是当前爬虫实例。这个方法可以用来对爬虫处理过程中的异常进行处理,可以返回 None
或一个可迭代的Request对象或item对象。
(5)def process_start_requests(self, start_requests, spider)
process_start_requests
方法在爬虫启动时被调用,用于对初始请求进行处理。它接收两个参数:start_requests
是初始请求的列表,spider
是当前爬虫实例。这个方法必须返回一个可迭代的Request对象,而不能返回item对象。
(6)def spider_opened(self, spider)
spider_opened
方法在爬虫打开时被调用。它接收一个参数 spider
,表示当前爬虫实例。在这个方法中,通过日志记录器(logger
)输出 "Spider opened: 爬虫名称" 的信息。
(7)激活SpiderMiddleware
SPIDER_MIDDLEWARES = {
"ScrapyDemmo.middlewares.ScrapydemmoSpiderMiddleware": 543,
}
四、下载中间件
1、源码
# 下载中间件
class ScrapydemmoDownloaderMiddleware:
# 不是所有的方法都需要定义。如果某个方法没有被定义,
# Scrapy会认为这个下载中间件不会修改传递的对象。
@classmethod
def from_crawler(cls, crawler):
# Scrapy使用该方法创建您的爬虫。
s = cls()
# 通过signals连接spider_opened信号和spider_opened方法
crawler.signals.connect(s.spider_opened, signal=signals.spider_opened)
return s
# 拦截处理所有的请求对象
# 参数:request就是拦截到的请求对象,spider爬虫文件中爬虫类实例化的对象
# spider参数的作用可以实现爬虫类和中间类的数据交互
def process_request(self, request, spider):
# 返回None:继续处理本次请求,执行下一个中间件的process_request方法
# 返回一个Response对象:执行当前中间件的process_response方法,重新回到引擎,被调度
# 返回一个Request对象:直接返回给引擎,被调度。进入调度器等待下次被调用
# 抛出IgnoreRequest异常:调用已安装的下载中间件的process_exception方法
return None
# 拦截处理所有的响应对象
# 参数:response就是拦截到的响应对象,request就是被拦截到响应对象对应的唯一的一个请求对象
def process_response(self, request, response, spider):
# - 返回一个Response对象:继续执行,进入引擎,被调度到爬虫进行解析
# - 返回一个Request对象:进入引擎,返回到调度器被重新调用
# - 或者抛出IgnoreRequest异常:抛出异常
return response
# 拦截和处理发生异常的请求对象
# 参数:reqeust就是拦截到的发生异常的请求对象
# 方法存在的意义:将发生异常的请求拦截到,然后对其进行修正
def process_exception(self, request, exception, spider):
# 当下载处理程序或process_request()方法(来自其他下载中间件)引发异常时调用。
# 必须返回以下之一:
# - 返回None:继续处理该异常
# - 返回一个Response对象:停止process_exception()链
# - 返回一个Request对象:停止process_exception()链
pass
# 控制日志数据的(忽略)
def spider_opened(self, spider):
spider.logger.info("Spider opened: %s" % spider.name)
2、方法介绍
(1)process_request(self, request, spider)
【此方法是用的最多的】
- 当每个request通过下载中间件时,该方法被调用。
- 返回None值:没有return也是返回None,该request对象传递给下载器,或通过引擎传递给其他权重低的process_request方法 【如果所有的下载器中间件都返回为None,则请求最终被交给下载器处理】
- 返回Response对象:不再请求,把response返回给引擎 【如果返回为请求,则将请求交给调度器】
- 返回Request对象:把request对象通过引擎交给调度器,此时将不通过其他权重低的process_request方法 【将响应对象交给spider进行解析】
参数
- request(Request 对象)–处理的request
- spider(Spider 对象)–该request对应的spider
(2)process_response(self, request, response, spider)
- 当下载器完成http请求,传递响应给引擎的时候调用
- 返回Resposne:通过引擎交给爬虫处理或交给权重更低的其他下载中间件的process_response方法 【如果返回为请求,则将请求交给调度器】
- 返回Request对象:通过引擎交给调取器继续请求,此时将不通过其他权重低的process_request方法 【将响应对象交给spider进行解析】
- 在settings.py中配置开启中间件,权重值越小越优先执行 【同管道的注册使用】
参数
- request (Request 对象) – response所对应的request
- response (Response 对象) – 被处理的response
- spider (Spider 对象) – response所对应的spider
(3)process_exception(request, exception, spider)
当下载处理器(download handler)或 process_request() (下载中间件)抛出异常(包括IgnoreRequest异常)时,Scrapy调用 process_exception() 。
process_exception() 应该返回以下之一: 返回 None 、 一个 Response 对象、或者一个 Request 对象。
- 如果其返回 None ,Scrapy将会继续处理该异常,接着调用已安装的其他中间件的 process_exception() 方法,直到所有中间件都被调用完毕,则调用默认的异常处理。
- 如果其返回一个 Response 对象,则已安装的中间件链的 process_response() 方法被调用。Scrapy将不会调用任何其他中间件的 process_exception() 方法。
- 如果其返回一个 Request 对象, 则返回的request将会被重新调用下载。这将停止中间件的 process_exception() 方法执行,就如返回一个response的那样。
参数
- request (是 Request 对象) – 产生异常的request
- exception (Exception 对象) – 抛出的异常
- spider (Spider 对象) – request对应的spider
(4)激活Downloader Middleware
DOWNLOADER_MIDDLEWARES = {
"ScrapyDemmo.middlewares.ScrapydemmoDownloaderMiddleware": 543,
}
标签:框架,process,request,中间件,spider,爬虫,scrapy,response
From: https://www.cnblogs.com/xiao01/p/18117502