python 学习笔记

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 []

上一篇下一篇

猜你喜欢

热点阅读