Элемент теряет имя при выходе в Python / Scrapy

#python #scrapy

#python #scrapy

Вопрос:

В Scrapy 2.4.x на Python 3.8.x я передаю элемент с целью сохранения некоторой статистики в БД. У скребка есть еще один элемент, который также получает результат.

Хотя имя элемента присутствует в основном скрипте «StatsItem», оно теряется в другом классе. Я использую имя элемента, чтобы решить, какой метод вызывать:

в scraper.py:

 import scrapy
from crawler.items import StatsItem, OtherItem

class demo(scrapy.Spider):

    def parse_item(self, response):
       stats = StatsItem()
       stats['results'] = 10
       yield stats

       print(type(stats).__name__)
       # Output: StatsItem

       print(stats)
       # Output: {'results': 10}
 

в pipeline.py

 import scrapy
from crawler.items import StatsItem, OtherItem

class mysql_pipeline(object):

    def process_item(self, item, spider):

        print(type(item).__name__)
        # Output: NoneType

        if isinstance(item, StatsItem):
            self.save_stats(item, spider)

        elif isinstance(item, OtherItem):
            # call other method

        return item
 

Выводом print в первом классе является «StatsItem», в то время как в конвейере он является «NoneType», поэтому метод save_stats() никогда не вызывается.

Я довольно новичок в Python, поэтому может быть лучший способ сделать это. Я не знаю ни сообщения об ошибке, ни исключения. Любая помощь приветствуется.

Комментарии:

1. Единственный объект, который имеет тип NoneType None . Таким образом, теряется не только имя — у вас вообще нет значения.

2. Вам не нужно наследовать от (object) (это неявно, вы можете оставить его выключенным). И если вы получаете NoneType в качестве имени типа, это означает, что ваша функция вызывается с item помощью being None . Поскольку вы не включаете вызов, невозможно сказать, почему это так, или это даже удивительно.

3. Это очень странно. У меня есть аналогичный сканер, в котором работает код копирования / вставки. Я не вижу никакой разницы. Также элемент пуст, когда я распечатываю его внутри элемента процесса, однако он не пуст в методе «demo». Я получаю распечатку словаря и имени класса.

4. это действительно работает? он должен выдать вам сообщение об ошибке, потому yield что не может быть введен напрямую class . Это должно быть в каком-то методе — т.е. в методе parse . in. С текущим кодом мы не можем воспроизвести проблему. Вы можете создать минимальный рабочий код с вашей проблемой, который мы могли бы просто скопировать, запустить и увидеть проблему.

5. всегда помещайте полное сообщение об ошибке (начинающееся со слова «Taceback») в вопрос (не комментарий) в виде текста (не скриншота). Есть и другая полезная информация.

Ответ №1:

Вы не можете использовать yield вне функции imo.

Ответ №2:

Я, наконец, смог найти проблему. Конкретный искатель был почти идентичен всем другим, у которых не было этой проблемы, но, за одним исключением, я настраивал конвейер элементов:

 custom_settings.update({
    'ITEM_PIPELINES' : {
         'crawler.pipelines.mysql_pipeline': 301,
     }
})
 

Удалив это, исправлена проблема.

Комментарии:

1. если вы удалите его, он должен запустить поисковый робот без запуска mysql_pipeline

2. В том-то и дело, что конвейер был импортирован дважды. Оказавшись внутри settings.py и один раз через обновление настроек непосредственно в искателе. Это вызвало такое неожиданное поведение.

3. то же pipeline самое в двух местах — это необычная ситуация, которая может затруднить поиск решения 🙂