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
Простым способом является наличие в парсере двух подпарасеров, по одному для каждого типа данных. Основной синтаксический анализатор определяет тип ввода и передает строку в соответствующую подпрограмму.
Второй подход состоит в том, чтобы включать парсеры в последовательности: один анализирует профили и игнорирует все остальное; второй анализирует комментарии и игнорирует все остальное (тот же принцип, что и выше).
Это продвижение вперед?