译者:OSGeo 中国

抓取的主要目标是从非结构化源(通常是网页)中提取结构化数据。scrappyspider可以以python dicts的形式返回提取的数据。虽然方便和熟悉,但python dicts缺乏结构:很容易在字段名中输入错误或返回不一致的数据,特别是在有许多spider的大型项目中。

要定义通用输出数据格式,scrapy提供 Item 类。 Item 对象是用于收集抓取数据的简单容器。他们提供了一个 dictionary-like 具有声明可用字段的方便语法的API。

各种零碎组件使用项目提供的额外信息:导出器查看声明的字段以确定要导出的列,可以使用项目字段元数据自定义序列化。 trackref 跟踪项实例以帮助查找内存泄漏(请参阅 使用调试内存泄漏 trackref 等)。

声明项目

使用简单的类定义语法和 Field 物体。下面是一个例子:

  1. import scrapy
  2. class Product(scrapy.Item):
  3. name = scrapy.Field()
  4. price = scrapy.Field()
  5. stock = scrapy.Field()
  6. tags = scrapy.Field()
  7. last_updated = scrapy.Field(serializer=str)

注解

那些熟悉 Django 会注意到 Scrapy 物品的声明类似于 Django Models 但是,由于不存在不同字段类型的概念,因此片段项要简单得多。

项目字段

Field 对象用于为每个字段指定元数据。例如,用于 last_updated 上面示例中所示的字段。

可以为每个字段指定任何类型的元数据。对接受的值没有限制 Field 物体。出于同样的原因,没有所有可用元数据键的引用列表。中定义的每个键 Field 对象可以由不同的组件使用,只有那些组件知道它。您还可以定义和使用任何其他 Field 为了你自己的需要,也要输入你的项目。的主要目标 Field 对象是提供一种在一个地方定义所有字段元数据的方法。通常,行为依赖于每个字段的组件使用特定的字段键来配置该行为。您必须参考它们的文档来查看每个组件使用的元数据键。

重要的是要注意 Field 用于声明该项的对象不会保留分配为类属性的状态。相反,可以通过 Item.fields 属性。

处理项目

下面是一些使用项执行的常见任务的示例,使用 Product 项目 declared above . 您会注意到API与 dict API .

创建项目

  1. >>> product = Product(name='Desktop PC', price=1000)
  2. >>> print(product)
  3. Product(name='Desktop PC', price=1000)

获取字段值

  1. >>> product['name']
  2. Desktop PC
  3. >>> product.get('name')
  4. Desktop PC
  5. >>> product['price']
  6. 1000
  7. >>> product['last_updated']
  8. Traceback (most recent call last):
  9. ...
  10. KeyError: 'last_updated'
  11. >>> product.get('last_updated', 'not set')
  12. not set
  13. >>> product['lala'] # getting unknown field
  14. Traceback (most recent call last):
  15. ...
  16. KeyError: 'lala'
  17. >>> product.get('lala', 'unknown field')
  18. 'unknown field'
  19. >>> 'name' in product # is name field populated?
  20. True
  21. >>> 'last_updated' in product # is last_updated populated?
  22. False
  23. >>> 'last_updated' in product.fields # is last_updated a declared field?
  24. True
  25. >>> 'lala' in product.fields # is lala a declared field?
  26. False

设置字段值

  1. >>> product['last_updated'] = 'today'
  2. >>> product['last_updated']
  3. today
  4. >>> product['lala'] = 'test' # setting unknown field
  5. Traceback (most recent call last):
  6. ...
  7. KeyError: 'Product does not support field: lala'

访问所有填充的值

要访问所有填充的值,只需使用 dict API ::

  1. >>> product.keys()
  2. ['price', 'name']
  3. >>> product.items()
  4. [('price', 1000), ('name', 'Desktop PC')]

复制项目

要复制项目,必须首先决定是要浅副本还是深副本。

如果您的物品包含 mutable 值如列表或字典,一个浅拷贝将在所有不同的拷贝中保持对相同可变值的引用。

例如,如果您有一个带有标记列表的项目,并且您创建了该项目的浅副本,那么原始项目和副本都具有相同的标记列表。向其中一个项目的列表中添加标记也会将标记添加到另一个项目中。

如果这不是所需的行为,请使用深度复制。

documentation of the copy module 更多信息。

要创建项目的浅副本,可以调用 copy() 在现有项上 (product2 = product.copy() )或从现有项实例化项类 (product2 = Product(product)

要创建深度复制,请调用 deepcopy() 相反 (product2 = product.deepcopy()

其他常见任务

从项目创建听写:

  1. >>> dict(product) # create a dict from all populated values
  2. {'price': 1000, 'name': 'Desktop PC'}

从dicts创建项目:

  1. >>> Product({'name': 'Laptop PC', 'price': 1500})
  2. Product(price=1500, name='Laptop PC')
  3. >>> Product({'name': 'Laptop PC', 'lala': 1500}) # warning: unknown field in dict
  4. Traceback (most recent call last):
  5. ...
  6. KeyError: 'Product does not support field: lala'

扩展项目

您可以通过声明原始项的子类来扩展项(添加更多字段或更改某些字段的元数据)。

例如::

  1. class DiscountedProduct(Product):
  2. discount_percent = scrapy.Field(serializer=str)
  3. discount_expiration_date = scrapy.Field()

您还可以通过使用前面的字段元数据并附加更多值或更改现有值来扩展字段元数据,如:

  1. class SpecificProduct(Product):
  2. name = scrapy.Field(Product.fields['name'], serializer=my_serializer)

添加(或替换)了 serializer 的元数据键 name 字段,保留所有以前存在的元数据值。

项目对象

  1. class scrapy.item.Item([arg])

返回从给定参数中可选初始化的新项。

项目复制标准 dict API 包括其构造函数。项提供的唯一附加属性是:

  1. fields

包含 all declared fields 对于这个项目,不仅仅是那些填充的。键是字段名,值是 Field 中使用的对象 Item declaration .

字段对象

  1. class scrapy.item.Field([arg])

这个 Field 类只是内置的别名 dict class and doesn’t provide any extra functionality or attributes. In other words, Field 对象是普通的旧python dict。单独的类用于支持 item declaration syntax 基于类属性。