刮除数据而无需明确定义要刮取的每个字段

Aco*_*orn 9 python scrapy

我想刮掉一页数据(使用Python Scrapy库),而不必在页面上定义每个字段.相反,我想使用id元素作为字段名称动态生成字段.

起初我认为最好的方法是拥有一个收集所有数据的管道,并在它拥有所有数据后输出.

然后我意识到我需要将数据传递给项目中的管道,但我无法定义项目,因为我不知道它将需要哪些字段!

解决这个问题的最佳方法是什么?

Aco*_*orn 16

更新:

旧方法不适用于项目加载器,并且不必要地使事情变得复杂.这是实现灵活项目的更好方法:

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!"
Run Code Online (Sandbox Code Playgroud)

结果:

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

旧解决方案:

好的,我找到了解决方案.这有点"黑客",但它有效..

Scrapy项将字段名称存储在名为dict的字典中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))
Run Code Online (Sandbox Code Playgroud)

你可以做的是覆盖这个__setitem__功能不那么严格:

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

        self._values[key] = value
Run Code Online (Sandbox Code Playgroud)

你去吧

现在,当您向项目添加数据时,如果项目没有定义该字段,则会添加该项目,然后将照常添加数据.