如何在单个Scrapy项目中为不同的蜘蛛使用不同的pipe道

我有一个包含多个蜘蛛的scrapy项目。 有什么办法可以定义哪个pipe道用于哪个蜘蛛? 并非我所定义的所有pipe道都适用于每一个蜘蛛。

谢谢

只要从主要设置中删除所有pipe道,并使用这个内部蜘蛛。

这将为每个蜘蛛用户定义pipe道

class testSpider(InitSpider): name = 'test' custom_settings = { 'ITEM_PIPELINES': { 'app.MyPipeline': 400 } } 

基于Pablo Hoffman的解决scheme ,您可以在Pipeline对象的process_item方法上使用以下装饰器,以便它检查spider的pipeline属性是否应该执行。 例如:

 def check_spider_pipeline(process_item_method): @functools.wraps(process_item_method) def wrapper(self, item, spider): # message template for debugging msg = '%%s %s pipeline step' % (self.__class__.__name__,) # if class is in the spider's pipeline, then use the # process_item method normally. if self.__class__ in spider.pipeline: spider.log(msg % 'executing', level=log.DEBUG) return process_item_method(self, item, spider) # otherwise, just return the untouched item (skip this step in # the pipeline) else: spider.log(msg % 'skipping', level=log.DEBUG) return item return wrapper 

为了使这个装饰器正常工作,蜘蛛必须具有一个pipe道属性和一个你想用来处理该项目的pipe道对象的容器,例如:

 class MySpider(BaseSpider): pipeline = set([ pipelines.Save, pipelines.Validate, ]) def parse(self, response): # insert scrapy goodness here return item 

然后在一个pipelines.py文件中:

 class Save(object): @check_spider_pipeline def process_item(self, item, spider): # do saving here return item class Validate(object): @check_spider_pipeline def process_item(self, item, spider): # do validating here return item 

所有的pipe道对象仍然应该在ITEM_PIPELINES中的设置中定义(按照正确的顺序 – 很好的更改,以便可以在蜘蛛上指定顺序)。

我至less可以想到四种方法:

  1. 每套蜘蛛+pipe道使用不同的scrapy项目(如果您的蜘蛛不同,则可能适用于不同的项目)
  2. 在scrapy工具命令行上,在每次调用蜘蛛之间使用scrapy settings更改pipe道设置
  3. 将您的蜘蛛隔离到自己的scrapy工具命令中 ,并将命令类中的default_settings['ITEM_PIPELINES']定义到该命令所需的pipe道列表。 看到这个例子的第6行 。
  4. 在stream水线类本身,有process_item()检查它正在运行的蜘蛛,如果该蜘蛛应该被忽略,什么都不做。 请参阅使用每蜘蛛资源的示例来帮助您入门。 (这看起来像一个丑陋的解决scheme,因为它将蜘蛛和物品pipe道紧密结合在一起,你可能不应该使用这个。)

您可以在pipe道中使用蜘蛛的name属性

 class CustomPipeline(object) def process_item(self, item, spider) if spider.name == 'spider1': # do something return item return item 

以这种方式定义所有pipe道可以实现你想要的。

这里给出的其他解决scheme是好的,但我认为它们可能会很慢,因为我们并不是真的没有使用每个蜘蛛的pipe道,而是每次返回一个项目时检查是否存在pipe道(在某些情况下,这可能会达到百万)。

为每个蜘蛛完全禁用(或启用)function的好方法是使用custom_settingfrom_crawler来处理所有的扩展:

pipelines.py

 from scrapy.exceptions import NotConfigured class SomePipeline(object): def __init__(self): pass @classmethod def from_crawler(cls, crawler): if not crawler.settings.getbool('SOMEPIPELINE_ENABLED'): # if this isn't specified in settings, the pipeline will be completely disabled raise NotConfigured return cls() def process_item(self, item, spider): # change my item return item 

settings.py

 ITEM_PIPELINES = { 'myproject.pipelines.SomePipeline': 300, } SOMEPIPELINE_ENABLED = True # you could have the pipeline enabled by default 

spider1.py

 class Spider1(Spider): name = 'spider1' start_urls = ["http://example.com"] custom_settings = { 'SOMEPIPELINE_ENABLED': False } 

在你检查的时候,我们已经指定了custom_settings来覆盖settings.py指定的东西,而且我们正在为这个蜘蛛禁用SOMEPIPELINE_ENABLED

现在,当你运行这个蜘蛛,检查像这样的东西:

 [scrapy] INFO: Enabled item pipelines: [] 

现在scrapy已经完全禁用了这个pipe道,整个运行过程中并没有打扰它的存在。 检查这也适用于scrapy extensionsmiddlewares

我使用两个pipe道,一个用于图像下载(MyImagesPipeline),另一个用于保存mongodb(MongoPipeline)中的数据。

假设我们有很多蜘蛛(spider1,spider2,………..),在我的例子中spider1和spider5不能使用MyImagesPipeline

settings.py

 ITEM_PIPELINES = {'scrapycrawler.pipelines.MyImagesPipeline' : 1,'scrapycrawler.pipelines.MongoPipeline' : 2} IMAGES_STORE = '/var/www/scrapycrawler/dowload' 

以及波纹pipe完整的代码

 import scrapy import string import pymongo from scrapy.pipelines.images import ImagesPipeline class MyImagesPipeline(ImagesPipeline): def process_item(self, item, spider): if spider.name not in ['spider1', 'spider5']: return super(ImagesPipeline, self).process_item(item, spider) else: return item def file_path(self, request, response=None, info=None): image_name = string.split(request.url, '/')[-1] dir1 = image_name[0] dir2 = image_name[1] return dir1 + '/' + dir2 + '/' +image_name class MongoPipeline(object): collection_name = 'scrapy_items' collection_url='snapdeal_urls' def __init__(self, mongo_uri, mongo_db): self.mongo_uri = mongo_uri self.mongo_db = mongo_db @classmethod def from_crawler(cls, crawler): return cls( mongo_uri=crawler.settings.get('MONGO_URI'), mongo_db=crawler.settings.get('MONGO_DATABASE', 'scraping') ) def open_spider(self, spider): self.client = pymongo.MongoClient(self.mongo_uri) self.db = self.client[self.mongo_db] def close_spider(self, spider): self.client.close() def process_item(self, item, spider): #self.db[self.collection_name].insert(dict(item)) collection_name=item.get( 'collection_name', self.collection_name ) self.db[collection_name].insert(dict(item)) data = {} data['base_id'] = item['base_id'] self.db[self.collection_url].update({ 'base_id': item['base_id'] }, { '$set': { 'image_download': 1 } }, upsert=False, multi=True) return item