# 项目
> 译者:[OSGeo 中国](https://www.osgeo.cn/)
抓取的主要目标是从非结构化源(通常是网页)中提取结构化数据。scrappyspider可以以python dicts的形式返回提取的数据。虽然方便和熟悉,但python dicts缺乏结构:很容易在字段名中输入错误或返回不一致的数据,特别是在有许多spider的大型项目中。
要定义通用输出数据格式,scrapy提供 [`Item`](#scrapy.item.Item "scrapy.item.Item") 类。 [`Item`](#scrapy.item.Item "scrapy.item.Item") 对象是用于收集抓取数据的简单容器。他们提供了一个 [dictionary-like](https://docs.python.org/2/library/stdtypes.html#dict) 具有声明可用字段的方便语法的API。
各种零碎组件使用项目提供的额外信息:导出器查看声明的字段以确定要导出的列,可以使用项目字段元数据自定义序列化。 `trackref` 跟踪项实例以帮助查找内存泄漏(请参阅 [使用调试内存泄漏 trackref](leaks.html#topics-leaks-trackrefs) 等)。
## 声明项目
使用简单的类定义语法和 [`Field`](#scrapy.item.Field "scrapy.item.Field") 物体。下面是一个例子:
```py
import scrapy
class Product(scrapy.Item):
name = scrapy.Field()
price = scrapy.Field()
stock = scrapy.Field()
tags = scrapy.Field()
last_updated = scrapy.Field(serializer=str)
```
注解
那些熟悉 [Django](https://www.djangoproject.com/) 会注意到 Scrapy 物品的声明类似于 [Django Models](https://docs.djangoproject.com/en/dev/topics/db/models/) 但是,由于不存在不同字段类型的概念,因此片段项要简单得多。
## 项目字段
[`Field`](#scrapy.item.Field "scrapy.item.Field") 对象用于为每个字段指定元数据。例如,用于 `last_updated` 上面示例中所示的字段。
可以为每个字段指定任何类型的元数据。对接受的值没有限制 [`Field`](#scrapy.item.Field "scrapy.item.Field") 物体。出于同样的原因,没有所有可用元数据键的引用列表。中定义的每个键 [`Field`](#scrapy.item.Field "scrapy.item.Field") 对象可以由不同的组件使用,只有那些组件知道它。您还可以定义和使用任何其他 [`Field`](#scrapy.item.Field "scrapy.item.Field") 为了你自己的需要,也要输入你的项目。的主要目标 [`Field`](#scrapy.item.Field "scrapy.item.Field") 对象是提供一种在一个地方定义所有字段元数据的方法。通常,行为依赖于每个字段的组件使用特定的字段键来配置该行为。您必须参考它们的文档来查看每个组件使用的元数据键。
重要的是要注意 [`Field`](#scrapy.item.Field "scrapy.item.Field") 用于声明该项的对象不会保留分配为类属性的状态。相反,可以通过 [`Item.fields`](#scrapy.item.Item.fields "scrapy.item.Item.fields") 属性。
## 处理项目
下面是一些使用项执行的常见任务的示例,使用 `Product` 项目 [declared above](#topics-items-declaring) . 您会注意到API与 [dict API](https://docs.python.org/2/library/stdtypes.html#dict) .
### 创建项目
```py
>>> product = Product(name='Desktop PC', price=1000)
>>> print(product)
Product(name='Desktop PC', price=1000)
```
### 获取字段值
```py
>>> 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
```
### 设置字段值
```py
>>> 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'
```
### 访问所有填充的值
要访问所有填充的值,只需使用 [dict API](https://docs.python.org/2/library/stdtypes.html#dict) ::
```py
>>> product.keys()
['price', 'name']
>>> product.items()
[('price', 1000), ('name', 'Desktop PC')]
```
### 复制项目
要复制项目,必须首先决定是要浅副本还是深副本。
如果您的物品包含 [mutable](https://docs.python.org/glossary.html#term-mutable) 值如列表或字典,一个浅拷贝将在所有不同的拷贝中保持对相同可变值的引用。
例如,如果您有一个带有标记列表的项目,并且您创建了该项目的浅副本,那么原始项目和副本都具有相同的标记列表。向其中一个项目的列表中添加标记也会将标记添加到另一个项目中。
如果这不是所需的行为,请使用深度复制。
见 [documentation of the copy module](https://docs.python.org/library/copy.html) 更多信息。
要创建项目的浅副本,可以调用 `copy()` 在现有项上 (`product2 = product.copy()` )或从现有项实例化项类 (`product2 = Product(product)` )
要创建深度复制,请调用 `deepcopy()` 相反 (`product2 = product.deepcopy()` )
### 其他常见任务
从项目创建听写:
```py
>>> dict(product) # create a dict from all populated values
{'price': 1000, 'name': 'Desktop PC'}
```
从dicts创建项目:
```py
>>> 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'
```
## 扩展项目
您可以通过声明原始项的子类来扩展项(添加更多字段或更改某些字段的元数据)。
例如::
```py
class DiscountedProduct(Product):
discount_percent = scrapy.Field(serializer=str)
discount_expiration_date = scrapy.Field()
```
您还可以通过使用前面的字段元数据并附加更多值或更改现有值来扩展字段元数据,如:
```py
class SpecificProduct(Product):
name = scrapy.Field(Product.fields['name'], serializer=my_serializer)
```
添加(或替换)了 `serializer` 的元数据键 `name` 字段,保留所有以前存在的元数据值。
## 项目对象
```py
class scrapy.item.Item([arg])
```
返回从给定参数中可选初始化的新项。
项目复制标准 [dict API](https://docs.python.org/2/library/stdtypes.html#dict) 包括其构造函数。项提供的唯一附加属性是:
```py
fields
```
包含 _all declared fields_ 对于这个项目,不仅仅是那些填充的。键是字段名,值是 [`Field`](#scrapy.item.Field "scrapy.item.Field") 中使用的对象 [Item declaration](#topics-items-declaring) .
## 字段对象
```py
class scrapy.item.Field([arg])
```
这个 [`Field`](#scrapy.item.Field "scrapy.item.Field") 类只是内置的别名 [dict](https://docs.python.org/2/library/stdtypes.html#dict) class and doesn't provide any extra functionality or attributes. In other words, [`Field`](#scrapy.item.Field "scrapy.item.Field") 对象是普通的旧python dict。单独的类用于支持 [item declaration syntax](#topics-items-declaring) 基于类属性。
- 简介
- 第一步
- Scrapy at a glance
- 安装指南
- Scrapy 教程
- 实例
- 基本概念
- 命令行工具
- Spider
- 选择器
- 项目
- 项目加载器
- Scrapy shell
- 项目管道
- Feed 导出
- 请求和响应
- 链接提取器
- 设置
- 例外情况
- 内置服务
- Logging
- 统计数据集合
- 发送电子邮件
- 远程登录控制台
- Web服务
- 解决具体问题
- 常见问题
- 调试spiders
- Spider 合约
- 常用做法
- 通用爬虫
- 使用浏览器的开发人员工具进行抓取
- 调试内存泄漏
- 下载和处理文件和图像
- 部署 Spider
- AutoThrottle 扩展
- Benchmarking
- 作业:暂停和恢复爬行
- 延伸 Scrapy
- 体系结构概述
- 下载器中间件
- Spider 中间件
- 扩展
- 核心API
- 信号
- 条目导出器
- 其余所有
- 发行说明
- 为 Scrapy 贡献
- 版本控制和API稳定性