アイテム¶
スクレイピングの主な目標は、非構造化ソース(通常はWebページ)から構造化データを抽出することです。 スパイダー は、抽出されたデータを アイテム 、つまりkey-valueペアを定義するPythonオブジェクトとして返す場合があります。
Scrapyは 複数のタイプのアイテム をサポートしています。 あなたがアイテムを作成したいときは、任意のタイプのアイテムを使用できます。 アイテムを受け取るコードを作成する場合、そのコードは 任意のアイテムタイプ で機能する必要があります。
アイテム型¶
Scrapyは、 itemadapter ライブラリを介して以下の型のアイテムをサポートします: 辞書 、 Item オブジェクト 、 dataclass オブジェクト 、 attrs オブジェクト 。
Itemオブジェクト¶
Item
は dict
風のAPIに加えて、アイテム型としての豊富な機能を提供します:
- class scrapy.item.Item([arg])[ソース]¶
Item
オブジェクトは、__init__
メッソドを含む標準のdict
APIを複製(replicate)します。Item
ではフィールド名を定義できるため、以下のようになります:KeyError
は、未定義のフィールド名を使用すると発生(raise)します(つまり、タイプミスが見過ごされないようにします)アイテム・エクスポーター は、最初にスクレイプされたオブジェクトにすべてのフィールドの値が揃ってない場合でも、デフォルト値をセットしてすべてのフィールドをエクスポートできます
Item
はフィールド・メタ・データを定義することもできます。これは シリアライズのカスタマイズ に使用できます。trackref
は、Item
を追跡しメモリ・リークを見つけるのに役立ちます(see trackref を使用したメモリ・リークのデバッグ)。Item
オブジェクトは、以下の追加APIメンバーも提供します:- copy()¶
- deepcopy()¶
このアイテムの
deepcopy()
を返す。
例:
from scrapy.item import Item, Field
class CustomItem(Item):
one_field = Field()
another_field = Field()
Dataclassオブジェクト¶
バージョン 2.2 で追加.
dataclass()
を使用すると、フィールド名を使用してアイテム・クラスを定義できるため、 アイテム・エクスポーター は、最初にスクレイプされたオブジェクトにすべての値がない場合でも、デフォルトでそれらすべてのフィールドをエクスポートできます。
さらに、 dataclass
アイテムは以下も可能にします:
定義された各フィールドの型とデフォルト値を定義します。
dataclasses.field()
を介してカスタム・フィールド・メタ・データを定義します。これは、 シリアル化のカスタマイズ に使用できます。
これらはPython3.7以降はネイティブに機能します。また、Python3.6では dataclasses backport を使用します。
例:
from dataclasses import dataclass
@dataclass
class CustomItem:
one_field: str
another_field: int
注釈
フィールド型は実行時に強要されません。
attr.sオブジェクト¶
バージョン 2.2 で追加.
attr.s()
を使用すると、フィールド名を使用してアイテム・クラスを定義できるため、 アイテム・エクスポーター は、最初にスクレイプされたオブジェクトにすべてのフィールドの値がない場合でも、デフォルトですべてのフィールドをエクスポートできます。
さらに、 attr.s
アイテムは以下も可能にします:
定義された各フィールドの型とデフォルト値を定義します。
カスタムフィールド metadata を定義します。これは シリアル化のカスタマイズ に使用できます。
この型を使用するには、 attrsパッケージ をインストールする必要があります。
例:
import attr
@attr.s
class CustomItem:
one_field = attr.ib()
another_field = attr.ib()
Itemオブジェクトで作業する¶
Itemサブクラス宣言¶
Itemsサブクラスは、単純なクラス定義構文と 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
属性を介してアクセスできます。
- class scrapy.item.Field([arg])[ソース]¶
Field
クラスは組み込みのdict
クラスの単なるエイリアスであり、追加の機能や属性を提供しません。 言い換えれば、Field
オブジェクトは昔ながらのPython辞書です。 別のクラスを使用して、クラス属性に基づいて アイテム宣言構文 をサポートします。
注釈
metadataフィールドは、 dataclass
と attrs
アイテムに対しても宣言できます。 詳細については、 dataclasses.field と attr.ib の文書を参照してください。
Itemオブジェクトで作業する¶
ここで、 先程宣言した Product
アイテムを使って、アイテムで実行される一般的なタスクの例をいくつか示します。 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')]
アイテムのコピー¶
アイテムをコピーするには、あなたは最初に浅いコピーとディープ・コピーのどちらを使用するかを決定する必要があります。
アイテムにリストや辞書などのミュータブル( mutable )値が含まれている場合、浅いコピーは、すべての異なるコピー間で同じミュータブル値への参照を保持します。
たとえば、タグのリストを持つアイテムがあり、そのアイテムの浅いコピーを作成する場合、元のアイテムとコピーの両方に同じタグのリストがあります。 アイテムの1つのリストにタグを追加すると、他のアイテムにもタグが追加されます。
それが望ましい振る舞いでない場合は、代わりにディープ・コピーを使用します。
詳細は copy
参照。
アイテムの浅いコピーを作成するには、あなたは、既存のアイテムで 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'
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
メタ・データ・キーを追加(または置換)し、以前に存在したすべてのメタ・データ値を保持します。
全アイテム型のサポート¶
アイテム・パイプライン または スパイダー・ミドルウェア のメソッドなど、アイテムを受け取るコードでは、任意の サポートされているアイテム型 で機能するコードを書くために ItemAdapter
クラスと is_item()
関数を使用することをお勧めします。