scrapy进阶开发(四):spiderMiddleware
2018-03-04 本文已影响62人
9c0ddf06559c
SpiderMiddleWare的定义
spiderMiddleware 是一个Scrapy的spider处理机制的钩子框架,你可以插入自定义的功能用来处理engine发往spider的response和spider发往engine的request和item
激活SpiderMiddleware
想要激活SpiderMiddleware,需要在settings里配置SPIDER_MIDDLEWARES,这是一个字典dict,key:value对应的是 类路径:顺序,顺序由大到小,越小的越靠近spider,由大的越靠近engine,也就是说,由spider到engine是升序调用,从engine到spider为降序调用
SPIDER_MIDDLEWARES = {
'myproject.middlewares.CustomSpiderMiddleware': 543,
#如果想禁用一个内置的spider,需要将其顺序设置为None
'scrapy.spidermiddlewares.offsite.OffsiteMiddleware': None,
}
定义自己的spider
class scrapy.spidermiddlewares.SpiderMiddleware:
"""
这个方法在将response发往spider的过程中被调用
这个方法应该返回None或者raise一个异常
* response:正在响应的处理
* spider:该响应的目标spider
"""
def process_spider_input(response, spider):
pass
"""
这个方法将在requset或者item发往engine的过程中被调用
这个方法必须返回一个reponse,dict,item
* response:产生该响应对应的response
* result:(一个request,dict,item)由这个spider返回的结果
* spider:该响应的目标spider
"""
def process_spider_output(response, result, spider):
pass
"""
这个方法将在一个spider或者一个process_spider_input方法抛出异常的时候被调用
这个方法应该返回None或者一个reponse,dict,item
* response :当前的相应
* exception:抛出的异常
* spider:当前的爬虫
"""
process_spider_exception(response, exception, spider):
pass
"""
这个方法用来处理首次发往engine的请求,和process_spider_output唯一不同的地方是,不接受response,并且只能返回一个request
"""
process_start_requests(start_requests, spider):
pass
"""
如果这个方法存在,将用来创建一个middleware实例,并且应该将改实例返回,这个方法接收一个crawler对象,改对象提供了spider的所有核心配置
这提供了一种方法让middleware可以访问其配置并hook住其他的scrapy组件
"""
@classmethod
from_crawler(cls, crawler):
pass
内置的SpiderMiddleware
scrapy内置的SpiderMiddleware 都在scrapy.spiderMiddlewares下面
image.png看一下HttpErrorMiddleware的源码
class HttpErrorMiddleware(object):
@classmethod
def from_crawler(cls, crawler):
"""
这个方法将settings传给构造函数,并返回了创建的实例
"""
return cls(crawler.settings)
def __init__(self, settings):
"""
构造函数
"""
# 获取HTTPERROR_ALLOW_ALL配置,改配置是一个布尔类型,声明是否需要spider自己处理所有的http相应状态码
self.handle_httpstatus_all = settings.getbool('HTTPERROR_ALLOW_ALL')
# 获取HTTPERROR_ALLOWED_CODES配合,该配置是一个list,声明spider需要自己处理的http响应状态码
self.handle_httpstatus_list = settings.getlist('HTTPERROR_ALLOWED_CODES')
def process_spider_input(self, response, spider):
"""
处理发往spider的相应
"""
# 如果是200-300之间的状态码,之间返回由spider处理
if 200 <= response.status < 300: # common case
return
# 获取元信息
meta = response.meta
# 如果在元信息里包含handle_httpstatus_all这个参数,
# 则说明当前请求相应的所有状态码都需要自己处理,直接返回
if 'handle_httpstatus_all' in meta:
return
# 同上,只不过这里变成了list
if 'handle_httpstatus_list' in meta:
allowed_statuses = meta['handle_httpstatus_list']
# 如果配置里声明了需要处理所有的请求,则直接返回
elif self.handle_httpstatus_all:
return
else:
# 如果上面条件全都不满足,则获取当前spider的handle_httpstatus_list属性
allowed_statuses = getattr(spider, 'handle_httpstatus_list', self.handle_httpstatus_list)
# 如果当前的status在运行自己处理的status列表里,则直接返回
if response.status in allowed_statuses:
return
# 如果上面都没有满足,则说明当前status需要由scrapy框架处理,所以抛出一个异常
raise HttpError(response, 'Ignoring non-200 response')
def process_spider_exception(self, response, exception, spider):
"""
处理HttpError的异常
"""
# 只处理HttpError的异常
if isinstance(exception, HttpError):
# 当前异常状态码出现次数加1
spider.crawler.stats.inc_value('httperror/response_ignored_count')
spider.crawler.stats.inc_value(
'httperror/response_ignored_status_count/%s' % response.status
)
打印日志
logger.info(
"Ignoring response %(response)r: HTTP status code is not handled or not allowed",
{'response': response}, extra={'spider': spider},
)
return []