スパイダー規約(contract)¶
スパイダーのテストは特にウンコで、単体テストを書くのは楽チンだけど、テスト作業はマンドクサ。Scrapyは規約(contract)によってスパイダーを統一的にテストする方法を提供します。
これにより、サンプルURLをハード・コーディングしてスパイダーの各コールバックをテストし、コールバックがレスポンスを処理する方法のさまざまな制約を確認できます。各規約はdocstringに含め、各規約の先頭には @
が付けられています。次の例をご覧ください:
def parse(self, response):
""" This function parses a sample response. Some contracts are mingled
with this docstring.
@url http://www.amazon.com/s?field-keywords=selfish+gene
@returns items 1 16
@returns requests 0 0
@scrapes Title Author Year Price
"""
このコールバックは、3つの組み込み規約を使用してテストされます:
- class scrapy.contracts.default.UrlContract[ソース]¶
この規約(
@url
)は、このスパイダーの他の規約条件をチェックするときに使用されるサンプルURLを設定します。 この規約は必須です。 チェックを実行する場合、この規約がないコールバックはすべて無視されます:@url url
- class scrapy.contracts.default.CallbackKeywordArgumentsContract[ソース]¶
この規約(
@cb_kwargs
)は、サンプル・リクエストのcb_kwargs
属性を設定します。 有効なJSON辞書である必要があります:@cb_kwargs {"arg1": "value1", "arg2": "value2", ...}
- class scrapy.contracts.default.ReturnsContract[ソース]¶
この規約(
@returns
)は、スパイダーによって返されるアイテムとリクエストの下限と上限を設定します。 上限はオプションです:@returns item(s)|request(s) [min [max]]
- class scrapy.contracts.default.ScrapesContract[ソース]¶
この規約(
@scrapes
)は、コールバックによって返されたすべてのアイテムに指定されたフィールドがあることを確認します:@scrapes field_1 field_2 ...
check
コマンドを使用して、規約チェックを実行します。
カスタム規約¶
うぬはチカラが欲しくないか? 組み込みScrapy規約よりも多くのチカラを。その場合は、 SPIDER_CONTRACTS
設定を使用して、プロジェクトに独自の規約を作成してロードできます:
SPIDER_CONTRACTS = {
'myproject.contracts.ResponseCheck': 10,
'myproject.contracts.ItemValidate': 10,
}
各規約は Contract
から継承する必要があり、3つのメソッドをオーバーライドできます:
- class scrapy.contracts.Contract(method, *args)[ソース]¶
- パラメータ
method (collections.abc.Callable) -- 規約が関連付けられているコールバック関数
args (list) -- docstringに渡される引数のリスト(空白区切り)
- adjust_request_args(args)[ソース]¶
これは、リクエスト・オブジェクトのデフォルト引数を含む引数として
dict
を受け取ります。Request
はデフォルトで使用されますが、これはrequest_cls
属性で変更できます。 チェーン内の複数の規約にこの属性が定義されている場合、最後の規約が使用されます。同じまたは変更されたバージョンを返す必要があります。
- pre_process(response)¶
これにより、コールバックに渡される前に、サンプル・リクエストから受信したレスポンスのさまざまなチェックをフックすることを許します。
- post_process(output)¶
これにより、コールバックの出力を処理できます。 反復可能オブジェクトは、このフックに渡される前に変換されてリスト化されます。
期待どおりで無い場合、 pre_process
または post_process
から ContractFail
例外が送出されます。
以下に、受信したレスポンスのカスタム・ヘッダーの存在を確認するデモ規約を示します:
from scrapy.contracts import Contract
from scrapy.exceptions import ContractFail
class HasHeaderContract(Contract):
""" Demo contract which checks the presence of a custom header
@has_header X-CustomHeader
"""
name = 'has_header'
def pre_process(self, response):
for header in self.args:
if header not in response.headers:
raise ContractFail('X-CustomHeader not present')
scrapy check
実行の検出¶
scrapy check
が実行されているとき、 SCRAPY_CHECK
環境変数を true
文字列に設定します。 scrapy check
が使用されている場合、 os.environ
を使用して、スパイダーや設定に変更を加えることができます:
import os
import scrapy
class ExampleSpider(scrapy.Spider):
name = 'example'
def __init__(self):
if os.environ.get('SCRAPY_CHECK'):
pass # Do some scraper adjustments when a check is running