Обновление:
Старый метод не работал с загрузчиками предметов и излишне усложнял вещи. Вот лучший способ получить гибкий предмет:
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
И вот, пожалуйста.
Теперь, когда вы добавляете данные в Элемент, если для элемента не определено это поле, оно будет добавлено, а затем данные будут добавлены как обычно.