摘要:关于scrapy中spider middleware的用法。

spider middlerware位于引擎和Spider之间,当Downloader生成Response之后,Response会被发送到Spider,在发送给Spider之前,Response会首先经过Spider Middleware处理,当Spider处理生成Item和Request之后,Item和Request还会经过Spider Middleware的处理。

使用说明

spider中间件1.png

首先把自定义的spider middlerware加入到settings.py文件的SPIDER_MIDDLEWARES设置中,然后该设置会和Scarpy中SPIDER_MIDDLEWARES_BASE定义的Spider Middleware合并。然后根据键值的数字优先级排序,得到一个有序列表,第一个最靠近引擎,最后一个靠近Spider。

spider middleware的方法说明

当Response被Spider Middleware处理时,process_spider_input()方法被调用。

process_spider_input(response,spider)

参数说明:
process_spider_input()方法的参数有如下两个:

  • resonse,是Response 对象,即被处理的Response。
  • spider,是Spider 对象,即该Response对应的Spider。

返回值:
process_spider_input()应该返回None或者抛出一个异常

  • 如果它返回None,Scrapy将会继续处理该Response,调用其他的Spider Middlerware,直到Spider处理该Response。
  • 如果它抛出一个异常,Scrapy将不会调用任何其他的Spider Middleware的process_spider_input方法,而调用Request的errback()方法。errback的输出将被使用process_spider_output()方法来处理。如果Request对象没有errback方法则直接调用process_spider_exception()来处理。

当Spider 处理Response 返回结果时,process spider_ output()方法被调用。

process_spider_output(response,result,spider)

参数说明:
process_spider_output()方法的参数有如下三个:

  • response,是Response对象,即生成该输出的response。
  • result,包含Request或Item对象的可迭代对象,即Spider返回的结果。
  • spider,是Spider对象,即其结果对应的Spider。

返回值:
process_spider_output()必须返回包含Request或者Item对象的可迭代对象。


当Spider 或Spider Middleware 的process_spider _input()方法抛出异常时,process_spider_exception()
方法被调用。

process_spider_exception(response,exception,spider)

参数说明:
process_spider_exception()方法的参数有如下三个:

  • response,是Response对象,即异常被抛出时处理的Response。
  • exception,是Exception对象,即被抛出的异常。
  • spider,是Spider对象,即抛出该异常的Spider。

返回值:
process_spider_exception() 必须要么返回None,要么返回一个包含Response 或 item对象的可迭代对象。
如果process_spider_exception返回None,代表该方法推卸掉责任,并没处理异常,而是直接交给下一个process_spider_exception,全都返回None,则异常最终交给Engine抛出


当使用start_urls变量或者start_request方法时发出请求时被调用,执行的过程类似于process_spider_output(),只不过其没有相关联的response并且必须返回request(不是item)。

process_start_requests(start_requests, spider)

参数说明:
process_start_requests()方法的参数有如下二个:

  • start_requests(包含Request的可迭代对象) - start requests
  • spider,是Spider对象,start request所属的spider

返回值:
必须返回一个包含Request对象的可迭代对象。

关于三个函数的使用

详情请看:scrapy 中间件 - Rannie` - 博客园

如果数值最小spider中间件中的process_spider_input先调用,然后调用数值次小的。如果抛出异常,并且存在errback,则先调用errback,然后调用数值最大的spider中间件中的process_spider_output,然后在调用数值次大的process_spider_output。
如果抛出异常,并且不存在errback,调用数值最大的spider中间件中的process_spider_exception,然后在调用数值次大的process_spider_exception。

因为按照数值大小,从引擎到spider排序,process_spider_input从引擎流向spider,process_spider_output从spider流向引擎。

实验代码如下:

baiduspider.py爬虫文件

import scrapy
class BaiduspiderSpider(scrapy.Spider):
    name = 'baiduspider'
    allowed_domains = ['baidu.com']
    start_urls = ['http://baidu.com/']
    def start_requests(self):
        yield scrapy.Request(url='http://www.baidu.com/',
                         callback=self.parse,
                         errback=self.parse_err,
        )                     
    def parse(self, response):
        pass

    def parse_err(self,res):
        return [1,2,3,4,5]

middlewares2.py中间件文件

from scrapy import signals


class SpiderMiddleware1(object):
        def process_spider_input(self, response, spider):
            print("input1")

        def process_spider_output(self, response, result, spider):
            print('output1',list(result))
            return result

        def process_spider_exception(self, response, exception, spider):
            print('exception1')


class SpiderMiddleware2(object):
        def process_spider_input(self, response, spider):
            print("input2")
            raise TypeError('input2 抛出异常')
        def process_spider_output(self, response, result, spider):
            print('output2',list(result))
            return result
        def process_spider_exception(self, response, exception, spider):
            print('exception2')

       
class SpiderMiddleware3(object):
        def process_spider_input(self, response, spider):
            print("input3")
            return None
        def process_spider_output(self, response, result, spider):
            print('output3',list(result))
            return result
        def process_spider_exception(self, response, exception, spider):
            print('exception3')
            

settings.py文件

SPIDER_MIDDLEWARES = {
    'errback1.middlewares2.SpiderMiddleware1': 543,
    'errback1.middlewares2.SpiderMiddleware2': 544,
    'errback1.middlewares2.SpiderMiddleware3': 545,
}

代码文件:
errback1.rar