web-dev-qa-db-ja.com

CeleryタスクでScrapyスパイダーを実行する

Djangoユーザーが要求するとスクレイピングが発生するサイトがあり、私のコードは新しいプロセスでScrapyスパイダーのスタンドアロンスクリプトを開始します。当然、これはユーザー。

このようなもの:

class StandAloneSpider(Spider):
    #a regular spider

settings.overrides['LOG_ENABLED'] = True
#more settings can be changed...

crawler = CrawlerProcess( settings )
crawler.install()
crawler.configure()

spider = StandAloneSpider()

crawler.crawl( spider )
crawler.start()

Celeryを使用し、ワーカーを使用してクロール要求をキューに入れることにしました。

しかし、トルネードリアクターが再起動できないという問題が発生しています。最初と2番目のスパイダーは正常に実行されますが、後続のスパイダーはReactorNotRestartableエラーをスローします。

誰でも、Celeryフレームワーク内でSpidersを実行する際のヒントを共有できますか?

34
stryderjzw

さて、ここで私がScrapyを自分のDjangoプロジェクトでクロールする対象をキューイングするために使用する方法を紹介します。実際の回避策は、主にここにあるjoehillenのコード http:// snippets .scrapy.org/snippets/13 /

まずtasks.pyファイル

from celery import task

@task()
def crawl_domain(domain_pk):
    from crawl import domain_crawl
    return domain_crawl(domain_pk)

そうして crawl.pyファイル

from multiprocessing import Process
from scrapy.crawler import CrawlerProcess
from scrapy.conf import settings
from spider import DomainSpider
from models import Domain

class DomainCrawlerScript():

    def __init__(self):
        self.crawler = CrawlerProcess(settings)
        self.crawler.install()
        self.crawler.configure()

    def _crawl(self, domain_pk):
        domain = Domain.objects.get(
            pk = domain_pk,
        )
        urls = []
        for page in domain.pages.all():
            urls.append(page.url())
        self.crawler.crawl(DomainSpider(urls))
        self.crawler.start()
        self.crawler.stop()

    def crawl(self, domain_pk):
        p = Process(target=self._crawl, args=[domain_pk])
        p.start()
        p.join()

crawler = DomainCrawlerScript()

def domain_crawl(domain_pk):
    crawler.crawl(domain_pk)

ここでのトリックは、「マルチプロセッシングインポートプロセスから」であり、これがTwistedフレームワークの「ReactorNotRestartable」問題を回避します。したがって、基本的には、Celeryタスクは「domain_crawl」関数を呼び出し、「DomainCrawlerScript」オブジェクトを繰り返し再利用して、Scrapyスパイダーとのインターフェースを確立します。 (私は私の例が少し冗長であることを認識していますが、python [my Django webserver is実際にpython2.4を使用していて、ワーカーサーバーはpython2.7を使用しています])

私の例では、「DomainSpider」は、URLのリストを取得して「start_urls」として設定する、変更されたScrapy Spiderです。

お役に立てれば!

36
byoungb

設定ファイルで CELERYD_MAX_TASKS_PER_CHILD を1に設定して、問題を解決しました。ワーカーデーモンは、スパイダーが実行されるたびに新しいプロセスを開始し、リアクターを処理します。

10
Mondongo