Comment puis-je utiliser différents pipelines pour différentes araignées dans un seul projet Scrapy

J’ai un projet de scrapy qui contient plusieurs araignées. Est-il possible de définir quels pipelines utiliser pour quelle araignée? Tous les pipelines que j’ai définis ne sont pas applicables à chaque araignée.

Merci

Retirez simplement tous les pipelines des parameters principaux et utilisez cette araignée.

Cela définira le pipeline pour l’utilisateur par spider

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

En vous basant sur la solution de Pablo Hoffman , vous pouvez utiliser le décorateur suivant sur la méthode process_item d’un object Pipeline afin qu’il vérifie l’atsortingbut de pipeline de votre araignée pour savoir si elle doit être exécutée ou non. Par exemple:

 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 

Pour que ce décorateur fonctionne correctement, l’araignée doit avoir un atsortingbut de pipeline avec un conteneur des objects Pipeline que vous souhaitez utiliser pour traiter l’élément, par exemple:

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

Et puis dans un fichier 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 

Tous les objects Pipeline doivent toujours être définis dans ITEM_PIPELINES dans les parameters (dans le bon ordre – ce serait bien de changer pour que l’ordre soit également spécifié sur le Spider).

Je peux penser à au moins quatre approches:

  1. Utilisez un projet de grattage différent par ensemble d’araignées et de pipelines (peut-être approprié si vos araignées sont suffisamment différentes pour justifier des projets différents)
  2. Sur la ligne de commande de l’outil Scrapy, modifiez le paramètre de pipeline avec les scrapy settings entre chaque appel de votre araignée
  3. Isolez vos araignées dans leurs propres commandes et sélectionnez les parameters default_settings['ITEM_PIPELINES'] dans votre classe de commandes dans la liste de pipelines souhaitée pour cette commande. Voir la ligne 6 de cet exemple .
  4. Dans les classes de pipeline elles-mêmes, process_item() sorte que process_item() vérifie sur quelle araignée il tourne et ne faites rien s’il doit être ignoré pour cette araignée. Voir l’ exemple en utilisant les ressources par araignée pour vous aider à démarrer. (Cela semble être une solution moche car elle associe étroitement les araignées et les pipelines d’articles. Vous ne devriez probablement pas utiliser celui-ci.)

Vous pouvez utiliser l’atsortingbut name de l’araignée dans votre pipeline

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

Définir tous les pipelines de cette manière peut accomplir ce que vous voulez.

Les autres solutions proposées ici sont bonnes, mais je pense qu’elles pourraient être lentes, car nous n’utilisons pas vraiment le pipeline par spider, mais nous vérifions si un pipeline existe chaque fois qu’un élément est renvoyé (et dans certains cas, cela peut atteindre des millions).

Un bon moyen de désactiver (ou d’activer) complètement une fonctionnalité par araignée consiste à utiliser custom_setting et from_crawler pour toutes les extensions comme ceci:

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 } 

Lorsque vous vérifiez, nous avons spécifié custom_settings qui remplacera les éléments spécifiés dans settings.py , et nous désactivons SOMEPIPELINE_ENABLED pour cette araignée.

Maintenant, lorsque vous lancez cette araignée, recherchez quelque chose comme:

 [scrapy] INFO: Enabled item pipelines: [] 

Maintenant, le raclage a complètement désactivé le pipeline, ne se souciant pas de son existence pour tout le cycle. Vérifiez que cela fonctionne également pour les extensions et les middlewares .

J’utilise deux pipelines, l’un pour le téléchargement d’images (MyImagesPipeline) et l’autre pour l’enregistrement de données dans mongodb (MongoPipeline).

supposons que nous ayons beaucoup d’araignées (spider1, spider2, ………..), dans mon exemple spider1 et spider5 ne peuvent pas utiliser MyImagesPipeline

settings.py

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

Et ci-dessous le code complet du pipeline

 import scrapy import ssortingng 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 = ssortingng.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