Item

スクレイピングの主な目的は、構造化されていないソース(通常はWebページ)から構造化されたデータを抽出することです。ScrapyのSpiderは、抽出されたデータをPythonのdictとして返すことができます。便利で手軽なのですが、Pythonのdictでは構造化が不十分です。特に、多くのSpiderを持つ大規模なプロジェクトでは、簡単にフィールド名をtypoしたり、矛盾したデータを返してしまいます。

共通の出力データ形式を定義するために、Scrapyは Item クラスを提供します。 Item オブジェクトは、抽出されたデータを収集するためのシンプルなコンテナです。利用可能なフィールドを宣言するための便利な構文を備えた dictライク なAPIを提供します。

さまざまなScrapyコンポーネントがItemが提供する情報を使用します。たとえば、エクスポーターは宣言されたフィールドを参照してエクスポートする列を調べ、シリアライズはItemフィールドのメタデータを利用してカスタマイズできます。 trackref はメモリのリークを見つけるための項目インスタンスを追跡します( Debugging memory leaks with trackref 参照)。

Itemの宣言

Itemはシンプルなクラス定義と Field オブジェクトを使用して宣言されます。次に例を示します。

import scrapy

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

注釈

Django に精通している人は、Itemが Django Models と同じように宣言されていることに気づくでしょう。ただScrapyのItemsは異なるフィールド型の概念がないので、それよりはるかに簡単です。

Itemフィールド

Field オブジェクトは、各フィールドのメタデータを指定するために使用されます。たとえば、上記の例の last_updated フィールドのserializer関数がそれにあたります。

各フィールドには任意の種類のメタデータを指定できます。 Field オブジェクトが受け入れる値に制限はありません。同じ理由から、使用可能なすべてのメタデータキーの参照リストはありません。 Field オブジェクトで定義された各キーは、別のコンポーネントによって使用され、それらのコンポーネントだけがそれを知ることができます。また、自分のニーズに合わせて、プロジェクト内の他の Field キーを定義して使用することもできます。 Field オブジェクトの主な目的は、すべてのフィールドのメタデータを一ヶ所で定義する方法を提供することです。通常、その動作が各フィールドに依存するコンポーネントは、特定のフィールドキーを使用してその動作を構成します。各コンポーネントでどのメタデータキーが使用されているかについては、ドキュメントを参照する必要があります。

項目を宣言するために使用される Field オブジェクトは、クラスの属性として割り当てられたままではないことに注意してください。代わりに、 Item.fields 属性を使用してアクセスできます。

Itemの操作

上記で宣言された Product Itemを使用したタスクの例をいくつか示します。APIは dict API と非常によく似ています。

Itemの作成

>>> 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')]

その他の一般的なタスク

Itemのコピー

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

>>> product3 = product2.copy()
>>> print(product3)
Product(name='Desktop PC', price=1000)

Itemからdictを作成する

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

dictからItemを作成する

>>> 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の拡張

元のItemのサブクラスを宣言することで、フィールドを追加したり、一部のフィールドのメタデータを変更したりなど、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オブジェクト

class scrapy.item.Item([arg])

指定された引数から初期化された新しいItemを返します。

Itemは、コンストラクタを含む標準の dict API を複製します。Itemが独自に提供する唯一の追加属性は次のとおりです。

fields

設定された項目だけでなく、このItemの 宣言されたすべてのフィールド を含む辞書。キーはフィールド名であり、値は Itemの宣言 で使用される Field オブジェクトです。

Fieldオブジェクト

class scrapy.item.Field([arg])

Field クラスは、組み込みの dict クラスへの単なるエイリアスであり、余分な機能や属性を提供しません。言い換えれば、 Field オブジェクトはPythonのdictです。別のクラスを使用して、クラス属性に基づいて Itemの宣言構文 をサポートします。