スパイダー コントラクト

バージョン 0.15 で追加.

注釈

これは新機能(Scrapy 0.15で導入)であり、細かい機能やAPIの更新が行われる場合があります。更新を知る為に リリースノート をチェックしてください。

スパイダーのテストは特にウンコで、単体テストを書くのは楽チンだけど、テスト作業はマンドクサ。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 (function) -- コントラクトが関連付けられているコールバック関数

  • 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