Очистка данных без необходимости явно определять каждое поле для очистки - PullRequest
9 голосов
/ 21 февраля 2011

Я хочу очистить страницу данных (используя библиотеку Python Scrapy) без необходимости определять каждое отдельное поле на странице. Вместо этого я хочу динамически генерировать поля, используя id элемента в качестве имени поля.

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

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

Какой для меня лучший способ решить эту проблему?

Ответы [ 4 ]

16 голосов
/ 22 февраля 2011

Обновление:

Старый метод не работал с загрузчиками предметов и излишне усложнял вещи. Вот лучший способ получить гибкий предмет:

from scrapy.item import BaseItem
from scrapy.contrib.loader import ItemLoader

class FlexibleItem(dict, BaseItem):
    pass

if __name__ == '__main__':
    item = FlexibleItem()
    loader = ItemLoader(item)

    loader.add_value('foo', 'bar')
    loader.add_value('baz', 123)
    loader.add_value('baz', 'test')
    loader.add_value(None, {'abc': 'xyz', 'foo': 555})

    print loader.load_item()

    if 'meow' not in item:
        print "it's not a cat!"

Результат:

{'foo': ['bar', 555], 'baz': [123, 'test'], 'abc': ['xyz']}
it's not a cat!

Старое решение:

Хорошо, я нашел решение. Это немного "взломать", но это работает ..

Предмет Scrapy хранит имена полей в диктовке под названием fields. При добавлении данных в элемент он проверяет, существует ли поле, а если нет, выдает ошибку:

def __setitem__(self, key, value):
    if key in self.fields:
        self._values[key] = value
    else:
        raise KeyError("%s does not support field: %s" %\
              (self.__class__.__name__, key))

Что вы можете сделать, так это переопределить эту __setitem__ функцию, чтобы она была менее строгой:

class FlexItem(Item):
    def __setitem__(self, key, value):
        if key not in self.fields:
            self.fields[key] = Field()

        self._values[key] = value

И вот, пожалуйста.

Теперь, когда вы добавляете данные в Элемент, если для элемента не определено это поле, оно будет добавлено, а затем данные будут добавлены как обычно.

4 голосов
/ 23 июня 2014

Это решение работает с экспортерами (scrapy crawl -t json -o output.json):

import scrapy

class FlexibleItem(scrapy.Item):
    def __setitem__(self, key, value):
        if key not in self.fields:
            self.fields[key] = scrapy.Field()
        super(FlexibleItem, self).__setitem__(key, value)

РЕДАКТИРОВАТЬ: обновлен для работы с последней Scrapy

2 голосов
/ 23 мая 2015

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

import scrapy
from collections import defaultdict

class FlexibleItem(scrapy.Item):
    fields = defaultdict(scrapy.Field)

    def __setitem__(self, key, value):
        # all keys are supported
        self._values[key] = value
1 голос
/ 11 августа 2015

Я знаю, что мой ответ опоздал, но для тех, кому все еще нужны динамические элементы, использующие Scrapy (текущая версия 1), я создал репозиторий на Github, включая пример.

Вот, пожалуйста,

https://github.com/WilliamKinaan/ScrapyDynamicItems

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...