Items

抓取的主要目的是从非结构化源(通常是网页)中提取结构化数据. Scrapy Spider可以将提取的数据作为Python字典返回. Python字典虽然方便且熟悉,但缺乏结构:很容易在字段名称中输入错误或返回不一致的数据,尤其是在具有许多蜘蛛的大型项目中.

为了定义常见的输出数据格式,Scrapy提供了Item类. Item对象是用于收集抓取数据的简单容器. 它们提供了类似于字典的 API,具有方便的语法来声明其可用字段.

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

Declaring Items

使用简单的类定义语法和Field对象声明项目. 这是一个例子:

import scrapy

class Product(scrapy.Item):
    name = scrapy.Field()
    price = scrapy.Field()
    stock = scrapy.Field()
    tags = scrapy.Field()
    last_updated = scrapy.Field(serializer=str)

Note

那些熟悉Django的人会注意到Scrapy Items的声明与Django Models类似,不同之处在于Scrapy Items更简单,因为没有不同字段类型的概念.

Item Fields

Field对象用于为每个字段指定元数据. 例如,上面示例中说明的last_updated字段的序列化函数.

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

重要的是要注意,用于声明项目的Field对象不会保持分配为类属性. 而是可以通过Item.fields属性访问它们.

Working with Items

Here are some examples of common tasks performed with items, using the Product item declared above. You will notice the API is very similar to the dict API.

Creating items

>>> product = Product(name='Desktop PC', price=1000)
>>> print(product)
Product(name='Desktop PC', price=1000)

Getting field values

>>> product['name']
Desktop PC
>>> product.get('name')
Desktop PC

>>> product['price']
1000

>>> product['last_updated']
Traceback (most recent call last):
    ...
KeyError: 'last_updated'

>>> product.get('last_updated', 'not set')
not set

>>> product['lala'] # getting unknown field
Traceback (most recent call last):
    ...
KeyError: 'lala'

>>> product.get('lala', 'unknown field')
'unknown field'

>>> 'name' in product  # is name field populated?
True

>>> 'last_updated' in product  # is last_updated populated?
False

>>> 'last_updated' in product.fields  # is last_updated a declared field?
True

>>> 'lala' in product.fields  # is lala a declared field?
False

Setting field values

>>> product['last_updated'] = 'today'
>>> product['last_updated']
today

>>> product['lala'] = 'test' # setting unknown field
Traceback (most recent call last):
    ...
KeyError: 'Product does not support field: lala'

Accessing all populated values

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

>>> product.keys()
['price', 'name']

>>> product.items()
[('price', 1000), ('name', 'Desktop PC')]

Copying items

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

如果您的项目包含诸如列表或字典之类的可变值,则浅表副本将在所有不同副本中保留对相同可变值的引用.

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

如果这不是理想的行为,请使用深层副本.

有关更多信息,请参见复制模块文档 .

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

要创建深层副本,请改为调用deepcopy()product2 = product.deepcopy() ).

Other common tasks

从项目创建字典:

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

从字典创建项目:

>>> Product({'name': 'Laptop PC', 'price': 1500})
Product(price=1500, name='Laptop PC')

>>> Product({'name': 'Laptop PC', 'lala': 1500}) # warning: unknown field in dict
Traceback (most recent call last):
    ...
KeyError: 'Product does not support field: lala'

Extending Items

You can extend Items (to add more fields or to change some metadata for some fields) by declaring a subclass of your original Item.

例如:

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

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

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

这会为name字段添加(或替换) serializer元数据键,并保留所有先前存在的元数据值.

Item objects

class scrapy.item.Item([arg])

返回一个新的项目,可以选择从给定的参数初始化.

项目复制标准dict API (包括其构造函数),并提供以下其他API成员:

copy()
deepcopy()

返回此项目的深层副本 .

fields

一个字典,其中包含该项目的所有声明的字段 ,而不仅仅是填充的字段 . 键是字段名称,值是Item声明中使用的Field对象.

Field objects

class scrapy.item.Field([arg])

Field类只是内置dict类的别名,不提供任何其他功能或属性. 换句话说, Field对象是普通的Python字典. 一个单独的类用于支持基于类属性的项目声明语法 .