有没有方法为每个蜘蛛使用单独的scrapy管道?

时间:2013-06-29 14:29:56

标签: python web-scraping scrapy scrapy-spider

我想在不同的域下获取网页,这意味着我必须在命令“scrapy crawl myspider”下使用不同的蜘蛛。但是,由于网页内容不同,我必须使用不同的管道逻辑将数据放入数据库。但对于每个蜘蛛,它们必须遍历settings.py中定义的所有管道。是否有其他优雅的方法为每个蜘蛛使用单独的管道?

3 个答案:

答案 0 :(得分:9)

在引擎启动期间,为项目中的所有蜘蛛全局定义

ITEM_PIPELINES设置。它无法在飞行中为每只蜘蛛进行更改。

以下是一些需要考虑的选项:

  • 更改管道代码。在您的管道的process_item方法中跳过/继续处理蜘蛛返回的项目,例如:

    def process_item(self, item, spider): 
        if spider.name not in ['spider1', 'spider2']: 
            return item  
    
        # process item
    
  • 更改开始抓取的方式。根据作为参数传递的蜘蛛名称执行from a script,在调用ITEM_PIPELINES之前覆盖您的crawler.configure()设置。

另见:

希望有所帮助。

答案 1 :(得分:5)

上述稍微好一点的版本如下。它更好,因为这种方式允许您比上面的管道中的'不在['spider1','spider2']'的编码中更容易选择性地打开不同蜘蛛的管道。

在你的蜘蛛类中,添加:

#start_urls=...
pipelines = ['pipeline1', 'pipeline2'] #allows you to selectively turn on pipelines within spiders
#...

然后在每个管道中,您可以使用getattr方法作为魔法。添加:

class pipeline1():  
    def process_item(self, item, spider):
       if 'pipeline1' not in getattr(spider, 'pipelines'):
          return item
       #...keep going as normal  

答案 2 :(得分:1)

更强大的解决方案;不记得我发现它的位置,但scrapy dev在某处提出了它。使用这种方法可以让你通过不使用包装器在所有蜘蛛上运行一些管道。它也使得你不必复制检查是否使用管道的逻辑。

打包机:

def check_spider_pipeline(process_item_method):
    """
        This wrapper makes it so pipelines can be turned on and off at a spider level.
    """
    @functools.wraps(process_item_method)
    def wrapper(self, item, spider):
        if self.__class__ in spider.pipeline:
            return process_item_method(self, item, spider)
        else:
            return item

    return wrapper

用法:

@check_spider_pipeline
def process_item(self, item, spider):
    ........
    ........
    return item

蜘蛛用法:

pipeline = {some.pipeline, some.other.pipeline .....}