# 項目
> 譯者:[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穩定性