Django Celery Scrappy ОШИБКА: twisted.internet.error.ReactorNotRestartable - PullRequest
0 голосов

У меня есть следующая модель: Команда «собирать» (collect_positions.py) -> задача Celery (tasks.py) -> ScrappySpider (MySpider) ...

collect_positions.py:

from django.core.management.base import BaseCommand

from tracker.models import Keyword
from tracker.tasks import positions


class Command(BaseCommand):
    help = 'collect_positions'

    def handle(self, *args, **options):

        def chunks(l, n):
            """Yield successive n-sized chunks from l."""
            for i in range(0, len(l), n):
                yield l[i:i + n]

        chunk_size = 1

        keywords = Keyword.objects.filter(product=product).values_list('id', flat=True)

        chunks_list = list(chunks(keywords, chunk_size))
        positions.chunks(chunks_list, 1).apply_async(queue='collect_positions')

        return 0

tasks.py:

from app_name.celery import app
from scrapy.settings import Settings
from scrapy_app import settings as scrapy_settings
from scrapy_app.spiders.my_spider import MySpider
from tracker.models import Keyword
from scrapy.crawler import CrawlerProcess


@app.task
def positions(*args):
    s = Settings()
    s.setmodule(scrapy_settings)

    keywords = Keyword.objects.filter(id__in=list(args))
    process = CrawlerProcess(s)
    process.crawl(MySpider, keywords_chunk=keywords)
    process.start()

    return 1

Я запускаю команду через командную строку, которая создает задачи для разбора. Первая очередь успешно завершена, но другие вернули ошибку:

twisted.internet.error.ReactorNotRestartable

Скажите, пожалуйста, как я могу исправить эту ошибку? Я могу предоставить любые данные, если есть необходимость ...

ОБНОВЛЕНИЕ 1

Спасибо за ответ, @Chiefir! Мне удалось запустить все очереди, но только функция start_requests () запущена, а parse () не запускается.

Основные функции лоскутного паука:

def start_requests(self):
    print('STEP1')

    yield scrapy.Request(
        url='exmaple.com',
        callback=self.parse,
        errback=self.error_callback,
        dont_filter=True
    )

def error_callback(self, failure):
    print(failure)

    # log all errback failures,
    # in case you want to do something special for some errors,
    # you may need the failure's type
    print(repr(failure))

    # if isinstance(failure.value, HttpError):
    if failure.check(HttpError):
        # you can get the response
        response = failure.value.response
        print('HttpError on %s', response.url)

    # elif isinstance(failure.value, DNSLookupError):
    elif failure.check(DNSLookupError):
        # this is the original request
        request = failure.request
        print('DNSLookupError on %s', request.url)

    # elif isinstance(failure.value, TimeoutError):
    elif failure.check(TimeoutError):
        request = failure.request
        print('TimeoutError on %s', request.url)


def parse(self, response):
    print('STEP2', response)

В консоли я получаю:

STEP1

В чем может быть причина?

1 Ответ

0 голосов
/ 02 мая 2018

Это старый вопрос как мир:

Вот что помогло мне выиграть битву с ошибкой ReactorNotRestartable: последний ответ автора вопроса
0) pip install crochet
1) import from crochet import setup
2) setup() - вверху файла
3) удалить 2 строки:
а) d.addBoth(lambda _: reactor.stop())
б) reactor.run()

У меня была такая же проблема с этой ошибкой, и я потратил 4+ часа, чтобы решить эту проблему, прочитайте все вопросы здесь об этом. Наконец нашел тот - и поделись. Вот как я это решил. Единственные значимые строки из Scrapy docs слева - это 2 последние строки в этом моем коде:

#some more imports
from crochet import setup
setup()

def run_spider(spiderName):
    module_name="first_scrapy.spiders.{}".format(spiderName)
    scrapy_var = import_module(module_name)   #do some dynamic import of selected spider   
    spiderObj=scrapy_var.mySpider()           #get mySpider-object from spider module
    crawler = CrawlerRunner(get_project_settings())   #from Scrapy docs
    crawler.crawl(spiderObj)                          #from Scrapy docs

Этот код позволяет мне выбрать, какого паука запускать только с его именем, переданным функции run_spider, а после завершения удаления - выбрать другого паука и запустить его снова.

В вашем случае вам нужно в отдельном файле создать отдельную функцию, которая запускает ваших пауков и запускает ее из вашего task. Обычно я так делаю :)
P.S. И действительно, нет никакого способа перезагрузить TwistedReactor.
ОБНОВЛЕНИЕ 1
Я не знаю, нужно ли вам вызывать метод start_requests(). Для меня это обычно работает только с этим кодом:

class mySpider(scrapy.Spider):
    name = "somname"
    allowed_domains = ["somesite.com"]
    start_urls = ["https://somesite.com"]

    def parse(self, response):
        pass
    def parse_dir_contents(self, response):      #for crawling additional links
        pass
...