Scrapy, Python: несколько классов предметов в одном конвейере?

У меня есть Spider, который сбрасывает данные, которые нельзя сохранить в одном классе.

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

  • Однако я не знаю, как конвейер с одной функцией parse_item может обрабатывать два разных класса элементов?

  • Или можно использовать разные функции parse_item?

  • Или мне нужно использовать несколько конвейеров?

  • Или возможно ли записать Итератор в поле поля Scrapy?


comments_list=[]
comments=response.xpath(somexpath)
for x in comments.extract():
        comments_list.append(x)
    ScrapyItem['comments'] =comments_list

Ответ 1

По умолчанию каждый элемент проходит через каждый конвейер.

Например, если вы даете ProfileItem и CommentItem, они оба пройдут через все конвейеры. Если у вас есть настройка конвейера для отслеживания типов элементов, то ваш метод process_item может выглядеть так:

def process_item(self, item, spider):
    self.stats.inc_value('typecount/%s' % type(item).__name__)
    return item

При завершении ProfileItem увеличивается 'typecount/ProfileItem'. Когда a CommentItem проходит, 'typecount/CommentItem' увеличивается.

У вас может быть один дескриптор конвейера только одного типа запроса элемента, однако, если обработка этого типа элемента уникальна, проверяя тип элемента перед продолжением:

def process_item(self, item, spider):
    if not isinstance(item, ProfileItem):
        return item
    # Handle your Profile Item here.

Если у вас были два метода process_item выше настройки в разных конвейерах, элемент будет проходить через оба из них, отслеживаться и обрабатываться (или игнорироваться на втором).

Кроме того, у вас может быть одна настройка конвейера для обработки всех связанных элементов:

def process_item(self, item, spider):
    if isinstance(item, ProfileItem):
        return self.handleProfile(item, spider)
    if isinstance(item, CommentItem):
        return self.handleComment(item, spider)

def handleComment(item, spider):
    # Handle Comment here, return item

def handleProfile(item, spider):
    # Handle profile here, return item

Или вы можете сделать его еще более сложным и разработать систему делегирования типов, которая загружает классы и вызывает методы обработчика по умолчанию, аналогично тому, как Scrapy обрабатывает промежуточное программное обеспечение/конвейеры. Это действительно зависит от вас, насколько вам это необходимо, и что вы хотите сделать.

Ответ 2

Определение нескольких элементов - это сложная вещь, когда вы экспортируете свои данные, если они имеют отношение (например, профили 1 - N комментариев), и вам приходится экспортировать их вместе, потому что каждый элемент обрабатывается в разное время по конвейерам. Альтернативный подход для этого сценария заключается в том, чтобы определить поле пользовательской выборочной области, например:

class CommentItem(scrapy.Item):
    profile = ProfileField()

class ProfileField(scrapy.item.Field):
   # your business here

Но учитывая сценарий, в котором вы ДОЛЖНЫ иметь 2 элемента, настоятельно рекомендуется использовать другой конвейер для каждого из этих типов элементов, а также разные экземпляры экспортера, чтобы вы получили эту информацию в разных файлах (если вы используете файлы):

settings.py

ITEM_PIPELINES = {
    'pipelines.CommentsPipeline': 1,
    'pipelines.ProfilePipeline': 1,
}

pipelines.py

class CommentsPipeline(object):
    def process_item(self, item, spider):
        if isinstance(item, CommentItem):
           # Your business here

class ProfilePipeline(object):
    def process_item(self, item, spider):
        if isinstance(item, ProfileItem):
           # Your business here

Ответ 3

Простым способом является наличие в парсере двух подпарасеров, по одному для каждого типа данных. Основной синтаксический анализатор определяет тип ввода и передает строку в соответствующую подпрограмму.

Второй подход состоит в том, чтобы включать парсеры в последовательности: один анализирует профили и игнорирует все остальное; второй анализирует комментарии и игнорирует все остальное (тот же принцип, что и выше).

Это продвижение вперед?