84 votes

Comment exécuter Scrapy à partir d'un script Python ?

Je suis nouveau à Scrapy et je cherche un moyen de l'exécuter à partir d'un script Python. J'ai trouvé 2 sources qui expliquent cela :

http://tryolabs.com/Blog/2011/09/27/calling-scrapy-python-script/

http://snipplr.com/view/67006/using-scrapy-from-a-script/

Je n'arrive pas à savoir où je dois mettre mon code spider et comment l'appeler à partir de la fonction principale. Merci de m'aider. Voici l'exemple de code :

# This snippet can be used to run scrapy spiders independent of scrapyd or the scrapy command line tool and use it from a script. 
# 
# The multiprocessing library is used in order to work around a bug in Twisted, in which you cannot restart an already running reactor or in this case a scrapy instance.
# 
# [Here](http://groups.google.com/group/scrapy-users/browse_thread/thread/f332fc5b749d401a) is the mailing-list discussion for this snippet. 

#!/usr/bin/python
import os
os.environ.setdefault('SCRAPY_SETTINGS_MODULE', 'project.settings') #Must be at the top before other imports

from scrapy import log, signals, project
from scrapy.xlib.pydispatch import dispatcher
from scrapy.conf import settings
from scrapy.crawler import CrawlerProcess
from multiprocessing import Process, Queue

class CrawlerScript():

    def __init__(self):
        self.crawler = CrawlerProcess(settings)
        if not hasattr(project, 'crawler'):
            self.crawler.install()
        self.crawler.configure()
        self.items = []
        dispatcher.connect(self._item_passed, signals.item_passed)

    def _item_passed(self, item):
        self.items.append(item)

    def _crawl(self, queue, spider_name):
        spider = self.crawler.spiders.create(spider_name)
        if spider:
            self.crawler.queue.append_spider(spider)
        self.crawler.start()
        self.crawler.stop()
        queue.put(self.items)

    def crawl(self, spider):
        queue = Queue()
        p = Process(target=self._crawl, args=(queue, spider,))
        p.start()
        p.join()
        return queue.get(True)

# Usage
if __name__ == "__main__":
    log.start()

    """
    This example runs spider1 and then spider2 three times. 
    """
    items = list()
    crawler = CrawlerScript()
    items.append(crawler.crawl('spider1'))
    for i in range(3):
        items.append(crawler.crawl('spider2'))
    print items

# Snippet imported from snippets.scrapy.org (which no longer works)
# author: joehillen
# date  : Oct 24, 2010

Nous vous remercions.

94voto

sddhhanover Points 723

Toutes les autres réponses font référence à la version 0.x de Scrapy. les documents mis à jour Scrapy 1.0 demande :

import scrapy
from scrapy.crawler import CrawlerProcess

class MySpider(scrapy.Spider):
    # Your spider definition
    ...

process = CrawlerProcess({
    'USER_AGENT': 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)'
})

process.crawl(MySpider)
process.start() # the script will block here until the crawling is finished

19voto

Arun Augustine Points 1462

Nous pouvons simplement utiliser

from scrapy.crawler import CrawlerProcess
from project.spiders.test_spider import SpiderName

process = CrawlerProcess()
process.crawl(SpiderName, arg1=val1,arg2=val2)
process.start()

Utilisez ces arguments à l'intérieur de l'araignée __init__ avec la portée globale.

16voto

mrmagooey Points 1170

Bien que je n'aie pas essayé, je pense que la réponse peut être trouvée dans la rubrique documentation scrapy . Pour le citer directement :

from twisted.internet import reactor
from scrapy.crawler import Crawler
from scrapy.settings import Settings
from scrapy import log
from testspiders.spiders.followall import FollowAllSpider

spider = FollowAllSpider(domain='scrapinghub.com')
crawler = Crawler(Settings())
crawler.configure()
crawler.crawl(spider)
crawler.start()
log.start()
reactor.run() # the script will block here

D'après ce que j'ai compris, il s'agit d'un nouveau développement dans la bibliothèque qui rend obsolètes certaines des approches antérieures en ligne (comme celle de la question).

13voto

Medeiros Points 725

Dans scrapy 0.19.x, c'est ce qu'il faut faire :

from twisted.internet import reactor
from scrapy.crawler import Crawler
from scrapy import log, signals
from testspiders.spiders.followall import FollowAllSpider
from scrapy.utils.project import get_project_settings

spider = FollowAllSpider(domain='scrapinghub.com')
settings = get_project_settings()
crawler = Crawler(settings)
crawler.signals.connect(reactor.stop, signal=signals.spider_closed)
crawler.configure()
crawler.crawl(spider)
crawler.start()
log.start()
reactor.run() # the script will block here until the spider_closed signal was sent

Notez ces lignes

settings = get_project_settings()
crawler = Crawler(settings)

Sans cela, votre spider n'utilisera pas vos paramètres et n'enregistrera pas les éléments. Il m'a fallu un certain temps pour comprendre pourquoi l'exemple de la documentation ne sauvegardait pas mes éléments. J'ai envoyé une pull request pour corriger l'exemple de la documentation.

Pour ce faire, il suffit d'appeler la commande directement à partir de votre script.

from scrapy import cmdline
cmdline.execute("scrapy crawl followall".split())  #followall is the spider's name

J'ai copié cette réponse sur ma première réponse ici : https://stackoverflow.com/a/19060485/1402286

11voto

1Z1 Points 71

Lorsque plusieurs crawlers doivent être exécutés dans un seul script python, l'arrêt du réacteur doit être géré avec précaution car le réacteur ne peut être arrêté qu'une seule fois et ne peut pas être redémarré.

Cependant, j'ai constaté, en réalisant mon projet, que l'utilisation de

os.system("scrapy crawl yourspider")

est le plus simple. Cela m'évitera de gérer toutes sortes de signaux, en particulier lorsque j'ai plusieurs araignées.

Si la performance est un problème, vous pouvez utiliser le multiprocessing pour exécuter vos spiders en parallèle, quelque chose comme :

def _crawl(spider_name=None):
    if spider_name:
        os.system('scrapy crawl %s' % spider_name)
    return None

def run_crawler():

    spider_names = ['spider1', 'spider2', 'spider2']

    pool = Pool(processes=len(spider_names))
    pool.map(_crawl, spider_names)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X