爬取的主要目標(biāo)就是從非結(jié)構(gòu)性的數(shù)據(jù)源提取結(jié)構(gòu)性數(shù)據(jù),例如網(wǎng)頁。Scrapy 提供 Item
類來滿足這樣的需求。
Item 對象是種簡單的容器,保存了爬取到得數(shù)據(jù)。其提供了類似于詞典(dictionary-like)的API以及用于聲明可用字段的簡單語法。
Item 使用簡單的 class 定義語法以及 Field
對象來聲明。例如:
import scrapy
class Product(scrapy.Item):
name = scrapy.Field()
price = scrapy.Field()
stock = scrapy.Field()
last_updated = scrapy.Field(serializer=str)
注解
熟悉 Django 的朋友一定會(huì)注意到 Scrapy Item 定義方式與 Django Models 很類似, 不過沒有那么多不同的字段類型(Field type),更為簡單。
Field 對象指明了每個(gè)字段的元數(shù)據(jù)(metadata)。例如下面例子中 last_updated
中指明了該字段的序列化函數(shù)。
您可以為每個(gè)字段指明任何類型的元數(shù)據(jù)。Field 對象對接受的值沒有任何限制。也正是因?yàn)檫@個(gè)原因,文檔也無法提供所有可用的元數(shù)據(jù)的鍵(key)參考列表。Field 對象中保存的每個(gè)鍵可以由多個(gè)組件使用,并且只有這些組件知道這個(gè)鍵的存在。您可以根據(jù)自己的需求,定義使用其他的 Field 鍵。 設(shè)置 Field 對象的主要目的就是在一個(gè)地方定義好所有的元數(shù)據(jù)。一般來說,那些依賴某個(gè)字段的組件肯定使用了特定的鍵(key)。您必須查看組件相關(guān)的文檔,查看其用了哪些元數(shù)據(jù)鍵(metadata key)。
需要注意的是,用來聲明 item 的 Field 對象并沒有被賦值為 class 的屬性。不過您可以通過 Item.fields 屬性進(jìn)行訪問。
以上就是所有您需要知道的如何聲明 item 的內(nèi)容了。
接下來以下邊聲明的 Product item 來演示一些 item 的操作。您會(huì)發(fā)現(xiàn) API 和 dict API 非常相似。
>>> product = Product(name='Desktop PC', price=1000)
>>> print product
Product(name='Desktop PC', price=1000)
>>> 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
>>> 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 來獲取所有的值:
>>> product.keys()
['price', 'name']
>>> product.items()
[('price', 1000), ('name', 'Desktop PC')]
復(fù)制 item:
>>> product2 = Product(product)
>>> print product2
Product(name='Desktop PC', price=1000)
>>> product3 = product2.copy()
>>> print product3
Product(name='Desktop PC', price=1000)
>>> 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'
您可以通過繼承原始的 Item 來擴(kuò)展 item(添加更多的字段或者修改某些字段的元數(shù)據(jù))。
例如:
class DiscountedProduct(Product):
discount_percent = scrapy.Field(serializer=str)
discount_expiration_date = scrapy.Field()
您也可以通過使用原字段的元數(shù)據(jù),添加新的值或修改原來的值來擴(kuò)展字段的元數(shù)據(jù):
class SpecificProduct(Product):
name = scrapy.Field(Product.fields['name'], serializer=my_serializer)
這段代碼在保留所有原來的元數(shù)據(jù)值的情況下添加(或者覆蓋)了 name 字段的 serializer。
class scrapy.item.Item([arg])
返回一個(gè)根據(jù)給定的參數(shù)可選初始化的 item。
Item復(fù)制了標(biāo)準(zhǔn)的 dict API。包括初始化函數(shù)也相同。Item 唯一額外添加的屬性是:
fields
一個(gè)包含了 item 所有聲明的字段的字典,而不僅僅是獲取到的字段。該字典的 key 是字段(field)的名字,值是 Item 聲明中使用到的 Field
對象。
class scrapy.item.Field([arg])
Field 僅僅是內(nèi)置的 dict 類的一個(gè)別名,并沒有提供額外的方法或者屬性。換句話說,F(xiàn)ield 對象完完全全就是 Python 字典(dict)。被用來基于類屬性(class attribute)的方法來支持 item 聲明語法。