アイテム¶
スクレイピングの主な目標は、非構造化ソース(通常はWebページ)から構造化データを抽出することです。 Scrapyスパイダーは、抽出したデータをPythonの辞書として返すことができます。 Pythonの辞書には便利で使い慣れていますが、構造が欠けています。特に、多くのスパイダーがいる大規模なプロジェクトでは、容易にフィールド名をtypoしたり、矛盾したデータを返しちゃったりします。
一般的な出力データ形式を定義するために、Scrapyは Item
クラスを提供します。 Item
オブジェクトは、スクレイピングされたデータを収集するために使用される単純なコンテナです。 これらは、利用可能なフィールドを宣言するための便利な構文を持つ「辞書のようなAPI」(dictionary-like API)を提供します。
さまざまなScrapyコンポーネントは、アイテムによって提供される追加情報を使用します。エクスポーターは、宣言されたフィールドを見てエクスポートする列を見つけます。シリアル化は、アイテムのフィールド・メタ・データを使用してカスタマイズできます。 trackref
はアイテムのインスタンスを追跡して、メモリ・リーク( trackref を使用したメモリ・リークのデバッグ 参照)などを見つけるのに役立ちます。
アイテムの宣言¶
アイテムは、単純なクラス定義構文と 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)
注釈
Django に精通している人は、Scrapyアイテムが Django Models と同様に宣言されていることに気付くでしょう。ただし、異なるフィールド型の概念がないため、Scrapyアイテムははるかに単純です。
アイテムのフィールド¶
Field
オブジェクトは、各フィールドのメタ・データを指定するために使用されます。 たとえば、上記の例で示した last_updated
フィールドのシリアル化関数です。
あなたは各フィールドに任意の種類のメタ・データを指定できます。 Field
オブジェクトが受け入れる値には制限はありません。これと同じ理由で、利用可能なすべてのメタ・データ・キーの参照リストはありません。 Field
オブジェクトで定義された各キーは異なるコンポーネントで使用でき、それらのコンポーネントのみがそれについて知っています。プロジェクトで他の Field
キーを定義して使用することもできます。 Field
オブジェクトの主な目的は、すべてのフィールド・メタ・データを1か所で定義する方法を提供することです。 通常、各フィールドに動作が依存するコンポーネントは、特定のフィールド・キーを使用してその動作を構成します。 各コンポーネントで使用されているメタ・データ・キーを確認するには、ドキュメントを参照する必要があります。
アイテムの宣言に使用される Field
オブジェクトは、クラス属性として割り当てられたままにならないことに注意することが重要です。 代わりに、 Item.fields
属性を介してアクセスできます。
アイテムで作業する¶
ここで、 先程宣言した Product
アイテムを使って、アイテムで実行される一般的なタスクの例をいくつか示します。 APIは辞書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'
読み込まれたすべての値へのアクセス¶
読み込まれたすべての値にアクセスするには、典型的な辞書API(dict API)を使用するだけです:
>>> product.keys()
['price', 'name']
>>> product.items()
[('price', 1000), ('name', 'Desktop PC')]
アイテムのコピー¶
アイテムをコピーするには、あなたは最初に浅いコピーとディープ・コピーのどちらを使用するかを決定する必要があります。
アイテムにリストや辞書などのミュータブル(mutable)値が含まれている場合、浅いコピーは、すべての異なるコピー間で同じミュータブル値への参照を保持します。
たとえば、タグのリストを持つアイテムがあり、そのアイテムの浅いコピーを作成する場合、元のアイテムとコピーの両方に同じタグのリストがあります。 アイテムの1つのリストにタグを追加すると、他のアイテムにもタグが追加されます。
それが望ましい振る舞いでない場合は、代わりにディープ・コピーを使用します。
詳細は documentation of the copy module 参照。
アイテムの浅いコピーを作成するには、あなたは、既存のアイテムで copy()
を呼び出す(product2 = product.copy()
)か、あるいは、既存のアイテムからアイテム・クラスをインスタンス化(product2 = Product(product)
)のいずれかが可能です。
ディープ・コピーを作成するには、代わりに deepcopy()
を呼び出します(product2 = product.deepcopy()
)。
その他の一般的な作業¶
アイテムから辞書を作成する:
>>> 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'
アイテムの拡張¶
あなたは、元のアイテムのサブクラスを宣言することにより、アイテムを拡張できます(フィールドを追加したり、フィールドのメタ・データを変更したりできます)。
例えば:
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
メタ・データ・キーを追加(または置換)し、以前に存在したすべてのメタ・データ値を保持します。