Scrapy 中间件
什么是中间件
如果有学过 django 的同学,应该对这个名词不陌生了,在 django 中,中间件可以对请求做统一批量的处理
那么在爬虫中,中间件的作用也是做批量处理的,比如把所有请求的请求头添加一个值等等等。
由于爬虫是一个发请求,获取响应的过程,所以在 scrapy 框架中有两个中间件
两种中间件
在 scrapy 框架中所谓的中间件本质上就是一个类,里面有一些方法。
当然你想应用中间件,必须要在 settings 文件中注册一下,优先级仍然是数值小的优先级高,一般放在上面
# 爬虫中间件
SPIDER_MIDDLEWARES = {
'spider1.middlewares.Spider1SpiderMiddleware': 543,
}
# 下载中间件
DOWNLOADER_MIDDLEWARES = {
'spider1.middlewares.Spider1DownloaderMiddleware': 543,
}
爬虫中间件
实际上中间件的方法只有四个就行了,但是框架给我们绑定了一个爬虫打开时的信号
from scrapy import signals
class Spider1SpiderMiddleware:
@classmethod
def from_crawler(cls, crawler):
# This method is used by Scrapy to create your spiders.
s = cls()
# 创建spider(爬虫对象)的时候,注册一个信号
# 信号: 当爬虫的打开的时候 执行 spider_opened 这个方法
crawler.signals.connect(s.spider_opened, signal=signals.spider_opened)
return s
def process_spider_input(self, response, spider):
# 下载完成后,执行,然后交给parse处理
return None
def process_spider_output(self, response, result, spider):
"""
经历过parse函数之后执行
:param response: 上一次请求返回的结果
:param result: yield的对象 包含 [item/Request] 对象的可迭代对象
:param spider: 当前爬虫对象
:return: 返回Request对象 或 Item对象
"""
for i in result:
yield i
def process_spider_exception(self, response, exception, spider):
"""如果执行parse抛出异常的话 会执行这个函数 默认不对异常处理交给下一个中间件处理"""
pass
def process_start_requests(self, start_requests, spider):
"""
爬虫启动时调用
:param start_requests: 包含 Request 对象的可迭代对象
:param spider:
:return: Request 对象
"""
for r in start_requests:
yield r
def spider_opened(self, spider):
# 生成爬虫日志
spider.logger.info('Spider opened: %s' % spider.name)
爬虫开始时有个起始 url,这个时候会经过爬虫中间件的 process_start_requests 方法,然后去下载,接着
我们看到 process_spider_input 和 process_spider_output 这两个方法中参数都有一个response参数可以判断出
这两个方法都是在下载完成后,拿到response之后才会执行的。
当下载完成后再经过爬虫中间件,这个时候会执行 process_spider_input 方法,这个时候的 response 中有
包含这次请求的所有内容,其中请求的 request 对象也被封装成了 response.resquest 。
然后来到 spider 文件中,经历parse方法,这个时候返回值可能是 Request 对象或者 item 对象,然后如果
parse 方法中抛出异常会执行爬虫中间件的 process_spider_exception 方法,一般情况下无异常,继续走爬虫
中间件中的 process_spider_output 方法。这就是爬虫中间件中方法的在什么地方执行的过程。
至于没讲到的那两个方法,是基于信号做出的关于爬虫开启时日志的拓展
下载中间件
class Spider1DownloaderMiddleware:
@classmethod
def from_crawler(cls, crawler):
# 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_request(self, request, spider):
"""
请求需要被下载时,经过所有下载中间件的process_request调用
spider处理完成,返回时调用
:param request:
:param spider:
:return:
None,继续往下执行,去下载
Response对象,停止process_request的执行,开始执行process_response
Request对象,停止中间件的执行,将Request重新放到调度器中
raise IgnoreRequest异常,停止process_request的执行,开始执行process_exception
"""
return None
def process_response(self, request, response, spider):
"""
下载得到响应后,执行
:param request: 请求对象
:param response: 响应对象
:param spider: 爬虫对象
:return:
返回request对象,停止中间件,将Request对象重新放到调度器中
返回response对象,转交给其他中间件process_response
raise IgnoreRequest 异常: 调用Request.errback
"""
return response
def process_exception(self, request, exception, spider):
"""当下载处理器(download handler)或process_request() (下载中间件)抛出异常
:return
None: 继续交给后续中间件处理异常
Response对象: 停止后续process_exception方法
Request对象: 停止中间件,request将会被重新调用下载
"""
pass
def spider_opened(self, spider):
spider.logger.info('Spider opened: %s' % spider.name)
process_request
process_request(self, request, spider)
该方法是下载器中间件类中的一个方法,该方法是每个请求从引擎发送给下载器下载之前都会经过该方法。所以该
方法经常用来处理请求头的替换,IP的更改,Cookie等的替换。
参数:
- request (Request 对象) – 处理的request
- spider (Spider 对象) – 该request对应的spider
返回值:
返回 None:Scrapy 将继续处理该 request,执行其他的中间件的相应方法,直到合适的下载器处理函数
(download handler)被调用,该 request 被执行(其response被下载)。
如果其返回 Response 对象:Scrapy 将不会调用任何其他的 process_request ( ) 或 process_exception ( )
方法,或相应地下载函数; 其将返回response。
如果其返回Request对象,Scrapy 则停止调用 process_request 方法并重新调度返回的request。当新返回的
request被执行后, 相应地中间件链将会根据下载的 response 被调用。
如果其raise一个 IgnoreRequest 异常,则安装的下载中间件的 process_exception ( ) 方法会被调用。如
果没有任何一个方法处理该异常, 则 request 的 errback(Request.errback) 方法会被调用。如果没有代码处
理抛出的异常, 则该异常被忽略且不记录(不同于其他异常那样)
设置 User-Agent
class XxxDownloaderMiddleware(object):
def process_request(self, request, spider):
useragent = ''
# 更新请求头的内容
request.headers.update({"User-Agent": useragent})
return None
设置 Cookie
class XxxDownloaderMiddleware(object):
def process_request(self, request, spider):
request.cookies={
}
return None
设置代理
修改下载中间件,在 process_requests 方法中添加代理,或者重写 DownloaderMiddleware 类并添加process_request 方法,最后在 settings 中启用 DOWNLOADER_MIDDLEWARES
def process_request(self, request, spider):
request.meta['proxy'] = 'http://127.0.0.1:7777'
return None
启动
DOWNLOADER_MIDDLEWARES = {
'mzt.middlewares.MztDownloaderMiddleware': 543,
}
process_response
process_response(self, request, response, spider)
该方法是下载器中间件类中的一个方法,该方法是每个响应从下载器发送给 spider 之前都会经过该方法
request: (Request 对象) response 所对应的request
response: (Response 对象) 被处理的 response
spider: (Spider 对象) response 所对应的 spider
返回值:
如果其返回一个Response (可以与传入的response相同,也可以是全新的对象), 该response会被其他中间件的
process_response() 方法处理。
如果其返回一个Request对象,则返回的request会被重新调度下载。处理类似于 process_request() 返回
request所做的那样。
如果其抛出一个 IgnoreRequest 异常,则调用request的 errback(Request.errback) 。如果没有代码处理
抛出的异常,则该异常被忽略且不记录(不同于其他异常那样)