リクエストとレスポンス

Scrapyは、Webサイトのクロールに RequestResponse オブジェクトを使用します。

通常、 Request オブジェクトはスパイダーで生成され、ダウンローダーに到達するまでシステム内をあちこち旅行(pass across)します。ダウンローダーはリクエストを実行し、リクエストを発行したスパイダーに Response オブジェクトを返します。

Request クラスと Response クラスの両方には、基本クラスでは必要のない機能を追加するサブクラスがあります。これらについては、 RequestのサブクラスResponseのサブクラス で説明しています。

Requestオブジェクト

class scrapy.http.Request(url[, callback, method='GET', headers, body, cookies, meta, encoding='utf-8', priority=0, dont_filter=False, errback, flags, cb_kwargs])

Request オブジェクトはHTTPリクエストを表します。これは通常スパイダーで生成され、ダウンローダーによって実行され、そして、 Response が生成されます。

パラメータ
  • url (string) -- このリクエストのURL

  • callback (callable) -- 最初のパラメーターとしてこのリクエストのレスポンス(ダウンロード後)に呼び出される関数。詳細については、以下の 追加のデータをコールバック関数に渡す を参照してください。リクエストでコールバックが指定されていない場合、スパイダーの parse() メソッドが使用されます。 処理中に例外が発生した場合、代わりにエラーバック(errback)が呼び出されることに注意してください。

  • method (string) -- このリクエストのHTTPメソッド。デフォルトは 'GET' です。

  • meta (dict) -- Request.meta 属性の初期値。指定すると、このパラメーターに渡された辞書は浅いコピー(shallow copy)されます。

  • body (str or unicode) -- リクエスト・ボディ。 unicode が渡されると、渡された encoding (デフォルトは utf-8 )を使用して str にエンコードされます。 body が与えられない場合、空の文字列が保存されます。この引数のタイプに関係なく、保存される最終的な値は str (決して unicodeNone ではありません)。

  • headers (dict) -- このリクエストのヘッダー。 辞書値は、文字列(単一値のヘッダーの場合)またはリスト(複数値のヘッダーの場合)です。 値として None が渡された場合、HTTPヘッダーはまったく送信されません。

  • cookies (dict or list) --

    リクエスト・クッキー。これらは2つの形式で送信できます。

    1. 辞書の使用:

      request_with_cookies = Request(url="http://www.example.com",
                                     cookies={'currency': 'USD', 'country': 'UY'})
      
    2. 辞書のリストの使用:

      request_with_cookies = Request(url="http://www.example.com",
                                     cookies=[{'name': 'currency',
                                              'value': 'USD',
                                              'domain': 'example.com',
                                              'path': '/currency'}])
      

    後者の形式では、クッキーの domain および path 属性をカスタマイズできます。これは、クッキーが後のリクエストのために保存される場合にのみ役立ちます。

    一部のサイトが(レスポンスで)クッキーを返すと、それらはそのドメインのクッキーに保存され、今後のリクエストで再度送信されます。これは通常のWebブラウザの一般的な動作です。けれども、何らかの理由で既存のクッキーとのマージを避けたい場合は、 Request.metadont_merge_cookies キーをTrueに設定することで、Scrapyにそうするよう指示できます。

    クッキーをマージしないリクエストの例:

    request_with_cookies = Request(url="http://www.example.com",
                                   cookies={'currency': 'USD', 'country': 'UY'},
                                   meta={'dont_merge_cookies': True})
    

    詳細については、 CookiesMiddleware を参照してください。

  • encoding (string) -- このリクエストのエンコーディング(デフォルトは 'utf-8' )。このエンコードは、URLをパーセントエンコードし、本文を str に変換するために使用されます( unicode として指定された場合)。

  • priority (int) -- このリクエストの優先度(デフォルトは 0)。スケジューラーは優先度を使用して、リクエストの処理に使用される順序を定義します。より高い優先度値を持つリクエストは、より早く実行されます。比較的低い優先度を示すために、負の値が許可されています。

  • dont_filter (boolean) -- このリクエストは、スケジューラによってフィルタリングされるべきではないことを示します。 これは、重複フィルターを無視するために、同じリクエストを複数回実行する場合に使用されます。注意して使用しないと、クロールループに陥ります。デフォルトは False です。

  • errback (callable) -- リクエストの処理中に例外が発生した場合に呼び出される関数。これには、404 HTTPエラーなどで失敗したページが含まれます。最初のパラメーターとして Twisted Failure インスタンスを受け取ります。 詳細については、以下の リクエスト処理で例外をキャッチするためにエラーバック(errback)を使用する を参照してください。

  • flags (list) -- リクエストに送信されたフラグは、ロギングまたは同様の目的に使用できます。

  • cb_kwargs (dict) -- キーワード引数としてリクエストのコールバックに渡される任意のデータを含む辞書。

url

このリクエストのURLを含む文字列。 この属性にはエスケープされたURLが含まれているため、コンストラクターで渡されるURLとは異なる場合があることに注意してください。

この属性は読み取り専用です。リクエストのURLを変更するには、 replace() を使用します。

method

リクエスト内のHTTPメソッドを表す文字列。 これは大文字であることが保証されています。 例: "GET""POST""PUT" など

headers

リクエスト・ヘッダーを含む辞書のようなオブジェクト。

body

リクエスト・ボディを含む文字列(str)。

この属性は読み取り専用です。リクエストの本文を変更するには、 replace() を使用します。

meta

このリクエストの任意のメタデータを含む辞書。 この辞書は、新しいリクエストに対して空であり、通常、さまざまなScrapyコンポーネント(拡張機能、ミドルウェアなど)によって設定されます。したがって、この辞書に含まれるデータは、有効にした拡張機能によって異なります。

Scrapyによって認識される特殊なメタ・キーのリストについては、 Request.meta 特殊キー を参照してください。

この辞書は copy() または replace() メソッドを使用してリクエストが複製されたときに浅いコピーされ(shallow copied)、スパイダーで response.meta 属性からアクセスすることもできます。

cb_kwargs

このリクエストの任意のメタデータを含む辞書。その内容は、キーワード引数としてリクエストのコールバックに渡されます。新しいリクエストの場合は空です。つまり、デフォルトではコールバックは引数として Response オブジェクトのみを取得します。

この辞書は、 copy() または replace() メソッドを使用してリクエストが複製されたときに浅いコピーされ(shallow copied)、スパイダーで response.cb_kwargs 属性からアクセスすることもできます。

copy()

このリクエストのコピーである新しいリクエストを返します。 追加のデータをコールバック関数に渡す も参照してください。

replace([url, method, headers, body, cookies, meta, flags, encoding, priority, dont_filter, callback, errback, cb_kwargs])

指定されたキーワード引数によって新しい値が指定されたメンバーを除き、同じメンバーを持つリクエスト・オブジェクトを返します。 Request.cb_kwargs および Request.meta 属性は(新しい値が引数として与えられない限り)デフォルトでは浅くコピー(shallow copy)されます。 追加のデータをコールバック関数に渡す も参照してください。

追加のデータをコールバック関数に渡す

リクエストのコールバックは、そのリクエストのレスポンスがダウンロードされるときに呼び出される関数です。コールバック関数は、ダウンロードされた Response オブジェクトを最初の引数として呼び出されます。

例:

def parse_page1(self, response):
    return scrapy.Request("http://www.example.com/some_page.html",
                          callback=self.parse_page2)

def parse_page2(self, response):
    # this would log http://www.example.com/some_page.html
    self.logger.info("Visited %s", response.url)

場合によっては、後で2番目のコールバックで引数を受け取ることができるように、これらのコールバック関数に引数を渡すことに興味があるかもしれません。 次の例は、 Request.cb_kwargs 属性を使用してこれを実現する方法を示しています:

def parse(self, response):
    request = scrapy.Request('http://www.example.com/index.html',
                             callback=self.parse_page2,
                             cb_kwargs=dict(main_url=response.url))
    request.cb_kwargs['foo'] = 'bar'  # add more arguments for the callback
    yield request

def parse_page2(self, response, main_url, foo):
    yield dict(
        main_url=main_url,
        other_url=response.url,
        foo=foo,
    )

ご用心

Request.cb_kwargs はバージョン 1.7 で導入されました。 それ以前は、コールバックに情報を渡すために Request.meta を使用することが推奨されていました。1.7 以降では、 Request.cb_kwargs がユーザー情報を処理するための好ましい方法となり、 Request.meta は、ミドルウェアや拡張機能などのコンポーネントとの通信のために残されています。

リクエスト処理で例外をキャッチするためにエラーバック(errback)を使用する

リクエストのエラーバック(errback)は、処理中に例外が発生したときに呼び出される関数です。

最初のパラメーターとして Twisted Failure インスタンスを受け取り、接続確立タイムアウト、DNSエラーなどを追跡するために使用できます。

すべてのエラーをログに記録し、必要に応じて特定のエラーをキャッチするスパイダーの例を次に示します:

import scrapy

from scrapy.spidermiddlewares.httperror import HttpError
from twisted.internet.error import DNSLookupError
from twisted.internet.error import TimeoutError, TCPTimedOutError

class ErrbackSpider(scrapy.Spider):
    name = "errback_example"
    start_urls = [
        "http://www.httpbin.org/",              # HTTP 200 expected
        "http://www.httpbin.org/status/404",    # Not found error
        "http://www.httpbin.org/status/500",    # server issue
        "http://www.httpbin.org:12345/",        # non-responding host, timeout expected
        "http://www.httphttpbinbin.org/",       # DNS error expected
    ]

    def start_requests(self):
        for u in self.start_urls:
            yield scrapy.Request(u, callback=self.parse_httpbin,
                                    errback=self.errback_httpbin,
                                    dont_filter=True)

    def parse_httpbin(self, response):
        self.logger.info('Got successful response from {}'.format(response.url))
        # do something useful here...

    def errback_httpbin(self, failure):
        # log all failures
        self.logger.error(repr(failure))

        # in case you want to do something special for some errors,
        # you may need the failure's type:

        if failure.check(HttpError):
            # these exceptions come from HttpError spider middleware
            # you can get the non-200 response
            response = failure.value.response
            self.logger.error('HttpError on %s', response.url)

        elif failure.check(DNSLookupError):
            # this is the original request
            request = failure.request
            self.logger.error('DNSLookupError on %s', request.url)

        elif failure.check(TimeoutError, TCPTimedOutError):
            request = failure.request
            self.logger.error('TimeoutError on %s', request.url)

Request.meta 特殊キー

Request.meta 属性には任意のデータを含めることができますが、Scrapyとその組み込み拡張機能によって認識される特殊なキーがあります。

以下がその特殊キーです:

bindaddress

リクエストの実行に使用する発信IPアドレスのIP

download_timeout

ダウンローダーがタイムアウトするまで待機する時間(秒)。 DOWNLOAD_TIMEOUT も参照してください。

download_latency

リクエストが開始されてから、つまりネットワークを介して送信されたHTTPメッセージから、レスポンスの取得に費やされた時間。 このメタ・キーは、レスポンスがダウンロードされた場合にのみ使用可能になります。他のほとんどのメタ・キーはScrapyの動作を制御するために使用されますが、これは読み取り専用であると想定されています。

download_fail_on_dataloss

壊れたレスポンスで失敗するかどうか。 DOWNLOAD_FAIL_ON_DATALOSS を参照してください。

max_retry_times

メタ・キーを使用して、リクエストごとに再試行回数を設定します。初期化されると、 max_retry_times メタ・キーは RETRY_TIMES 設定よりも優先されます。

Requestのサブクラス

以下は組み込みの Request のサブクラスのリストです。また、サブクラス化して独自のカスタム機能を実装することもできます。

FormRequestオブジェクト

FormRequestクラスは、ベースの Request をHTMLフォームを処理する機能に関して拡張します。 lxml.html forms を使用して、フォームフィールドに Response オブジェクトからのフォームデータを事前入力します。

class scrapy.http.FormRequest(url[, formdata, ...])

FormRequest クラスはコンストラクターに新しい引数を追加します。残りの引数は Request クラスと同じであり、ここでは説明しません。

パラメータ

formdata (dict or iterable of tuples) -- これは、URLエンコードされてリクエストの本文に割り当てられるHTMLフォームデータを含む辞書(または (キー, 値)タプルの反復可能要素)です。

FormRequest オブジェクトは、標準の Request メソッドに加えて、次のクラスメソッドをサポートします:

classmethod from_response(response[, formname=None, formid=None, formnumber=0, formdata=None, formxpath=None, formcss=None, clickdata=None, dont_click=False, ...])

指定のレスポンスに含まれるHTML <form> 要素で見つかった値が事前に入力されたフォームフィールド値を持つ新しい FormRequest オブジェクトを返します。例については、 FormRequest.from_response() を使用してユーザーログインをシミュレートする を参照してください。

ポリシーは、デフォルトでは、 <input type="submit"> のようにクリック可能に見えるフォームコントロールのクリックを自動的にシミュレートすることです。 これは非常に便利で、多くの場合望ましい動作ですが、時にはデバッグが困難な問題を引き起こす可能性があります。 たとえば、javascriptを使用して、入力 and/or 送信されたフォームを操作する場合、デフォルトの from_response() 動作は最適ではない場合があります。この動作を無効にするには、 dont_click 引数を True に設定します。 また、(無効にするのではなく)クリックしたコントロールを変更したい場合は、 clickdata 引数を使用することもできます。

ご用心

オプション値に先頭または末尾の空白があるselect要素でこのメソッドを使用すると、lxml 3.8で修正されるべきlxmlのバグ(bug in lxml)のために機能しません。

パラメータ
  • response (Response object) -- フォームフィールドに事前入力するために使用されるHTMLフォームを含むレスポンス

  • formname (string) -- 指定した場合、name属性をこの値に設定したフォームが使用されます。

  • formid (string) -- 指定した場合、この値に設定されたid属性を持つフォームが使用されます。

  • formxpath (string) -- 指定すると、xpathに一致する最初のフォームが使用されます。

  • formcss (string) -- 指定した場合、cssセレクターに一致する最初のフォームが使用されます。

  • formnumber (integer) -- レスポンスに複数のフォームが含まれる場合に使用するフォームの数。 最初のもの(およびデフォルト)は 0 です。

  • formdata (dict) -- フォームデータでオーバーライドするフィールド。レスポンス <form> 要素にフィールドが既に存在する場合、その値はこのパラメーターで渡された値によってオーバーライドされます。このパラメーターに渡された値が None の場合、フィールドはレスポンス <form> 要素に存在していても、リクエストに含まれません。

  • clickdata (dict) -- クリックされたコントロールを検索する属性。 指定されていない場合、最初のクリック可能な要素のクリックをシミュレートしてフォームデータが送信されます。 html属性に加えて、コントロールは nr 属性を介して、フォーム内の他の送信可能な入力に対するゼロベースのインデックスによって識別できます。

  • dont_click (boolean) -- Trueの場合、要素をクリックせずにフォームデータが送信されます。

このクラスメソッドの他のパラメーターは、 FormRequest コンストラクターに直接渡されます。

バージョン 0.10.3 で追加: formname パラメータ。

バージョン 0.17 で追加: formxpath パラメータ。

バージョン 1.1.0 で追加: formcss パラメータ。

バージョン 1.1.0 で追加: formid パラメータ。

Request使用例

HTTP POST経由でデータを送信するためにFormRequestを使う

スパイダーでHTMLフォームPOSTをシミュレートし、いくつかのキー値フィールドを送信する場合、以下のように(スパイダーから) FormRequest オブジェクトを返すことができます:

return [FormRequest(url="http://www.example.com/post/action",
                    formdata={'name': 'John Doe', 'age': '27'},
                    callback=self.after_post)]

FormRequest.from_response() を使用してユーザーログインをシミュレートする

Webサイトでは通常、セッション関連データや認証トークン(ログインページ用)などの <input type="hidden"> 要素を介して事前入力されたフォームフィールドを提供します。 スクレイピングするとき、これらのフィールドは自動的に事前入力され、ユーザー名やパスワードなどのいくつかのフィールドのみがオーバーライド必須です。この作業には FormRequest.from_response() メソッドを使用できます。以下はこれを使用するスパイダーの例です:

import scrapy

def authentication_failed(response):
    # TODO: Check the contents of the response and return True if it failed
    # or False if it succeeded.
    pass

class LoginSpider(scrapy.Spider):
    name = 'example.com'
    start_urls = ['http://www.example.com/users/login.php']

    def parse(self, response):
        return scrapy.FormRequest.from_response(
            response,
            formdata={'username': 'john', 'password': 'secret'},
            callback=self.after_login
        )

    def after_login(self, response):
        if authentication_failed(response):
            self.logger.error("Login failed")
            return

        # continue scraping with authenticated session...

JsonRequest

JsonRequestクラスは、ベースの Request クラスにJSONリクエストを処理する機能をくわえます。

class scrapy.http.JsonRequest(url[, ... data, dumps_kwargs])

JsonRequest クラスは、コンストラクターに2つの新しい引数を追加します。残りの引数は Request クラスと同じであり、ここでは説明しません。

JsonRequest を使用すると、Content-Type ヘッダーを application/json にセットし、そして、 Accept ヘッダーを application/json, text/javascript, */*; q=0.01 にセットします。

パラメータ
  • data (JSON serializable object) -- JSONエンコードして本文に割り当てる必要があるJSONシリアル化可能オブジェクトです。 Request.body 引数が指定されている場合、このパラメーターは無視されます。 Request.body 引数が提供されておらず、データ引数が提供されている場合、 Request.method'POST' に自動的に設定されます。

  • dumps_kwargs (dict) -- データをJSON形式にシリアル化するために使用される、基礎となる json.dumps メソッドに渡されるパラメーター。

JsonRequest使用例

JSONペイロードを含むJSON POSTリクエストを送信する:

data = {
    'name1': 'value1',
    'name2': 'value2',
}
yield JsonRequest(url='http://www.example.com/post/action', data=data)

Responseオブジェクト

class scrapy.http.Response(url[, status=200, headers=None, body=b'', flags=None, request=None])

Response オブジェクトはHTTPレスポンスを表し、通常は(ダウンローダーによって)ダウンロードされ、処理のためにスパイダーに送られます。

パラメータ
  • url (string) -- このレスポンスのURL

  • status (integer) -- レスポンスのHTTPステータス。デフォルトは 200 です。

  • headers (dict) -- このレスポンスのヘッダー。 辞書値は、文字列(単一値のヘッダーの場合)またはリスト(複数値のヘッダーの場合)です。

  • body (bytes) -- レスポンス・ボディ。 デコードされたテキストにstr(Python2ではユニコード)としてアクセスするには、エンコード対応(encoding-aware)である、 TextResponse のような Responseのサブクラスresponse.text を使用できます。

  • flags (list) -- Response.flags 属性の初期値を含むリストです。 指定すると、リストは浅くコピー(shallow copy)されます。

  • request (Request object) -- Response.request 属性の初期値。これは、このレスポンスを生成した Request を表します。

url

レスポンスのURLを含む文字列。

この属性は読み取り専用です。レスポンスのURLを変更するには、 replace() を使用します。

status

レスポンスのHTTPステータスを表す整数。例: 200404

headers

レスポンス・ヘッダーを含む辞書のようなオブジェクト。値にアクセスするには、 get() を使用して指定した名前の最初のヘッダー値を返すか、 getlist() を使用して指定した名前のすべてのヘッダー値を返します。たとえば、以下のの呼び出しはヘッダーのすべてのクッキーを提供します:

response.headers.getlist('Set-Cookie')
body

このResponseのボディ。Response.bodyは常にバイト・オブジェクトであることに注意してください。Unicodeバージョンが必要な場合は、 TextResponse.text を使用します( TextResponse と、そのサブクラスでのみ使用可能)。

この属性は読み取り専用です。 レスポンスのボディを変更するには、 replace() を使用します。

request

このレスポンスを生成した Request オブジェクト。この属性は、レスポンスとリクエストが、すべての ダウンローダー・ミドルウェア を通過した後、Scrapyエンジンで割り当てられます。 特に、これは以下を意味します:

  • HTTPリダイレクトにより、元のリクエスト(リダイレクト前のURLへ)がリダイレクトされたレスポンス(リダイレクト後の最終URL)に割り当てられます。

  • Response.request.urlは必ずしもResponse.urlと同じではありません

  • この属性は、スパイダー・コード、および スパイダー・ミドルウェア でのみ使用できます。ただし、(他の方法でリクエストを使用できる場合の)ダウンローダー・ミドルウェアと response_downloaded シグナルのハンドラーには含まれません。

meta

Response.request オブジェクトの Request.meta 属性(つまり self.request.meta )へのショートカット。

Response.request 属性とは異なり、 Response.meta 属性はリダイレクトと再試行に沿って伝播されるため、元の Request.meta がスパイダーから送信されます。

参考

Request.meta 属性

flags

このレスポンスのフラグを含むリスト。フラグは、レスポンスのタグ付けに使用されるラベルです。 例: 'cached''redirected' など。これらは、エンジンがログ記録に使用するResponse ( __str__ メソッド)の文字列表現に表示されます。

copy()

このレスポンスのコピーである新しいレスポンスを返します。

replace([url, status, headers, body, request, flags, cls])

指定されたキーワード引数によって新しい値が指定されたメンバーを除き、同じメンバーを持つレスポンスオブジェクトを返します。属性 Response.meta はデフォルトでコピーされます。

urljoin(url)

指定の url (たぶん相対URL)と レスポンスの url ( Response.url ) を組み合わせて、絶対URLを構築します。

これは urlparse.urljoin のラッパーであり、以下の呼び出しを行うための単なるエイリアスです:

urlparse.urljoin(response.url, url)

Responseのサブクラス

使用可能な組み込みResponseのサブクラスのリストは以下のとおりです。 Responseクラスをサブクラス化して、独自の機能を実装することもできます。

TextResponseオブジェクト

class scrapy.http.TextResponse(url[, encoding[, ...]])

TextResponse オブジェクトは、エンコード機能を、ベースの Response クラスに追加します。これは、画像、音声、メディアファイルなどのバイナリデータにのみ使用することを目的としています。

TextResponse オブジェクトは、ベースの Response オブジェクトに加えて、新しいコンストラクター引数をサポートします。残りの機能は Response クラスと同じであり、ここでは説明しません。

パラメータ

encoding (string) -- このレスポンスに使用するエンコーディングを含む文字列です。 ユニコード・ボディで TextResponse オブジェクトを作成する場合、このエンコードを使用してエンコードされます(body属性は常に文字列であることに注意してください)。 encodingNone (デフォルト値)の場合、代わりにレスポンス・ヘッダーとボディからエンコードを検索します。

TextResponse オブジェクトは、標準の Response に加えて、次の属性をサポートします:

text

ユニコードとしてのレスポンス・ボディ

response.body.decode(response.encoding) と同じですが、最初の呼び出し後に結果がキャッシュされるため、余分なオーバーヘッドなしで response.text に複数回アクセスできます。

注釈

unicode(response.body) はレスポンス・ボディをユニコードに変換する正しい方法ではありません。レスポンス・エンコーディングの代わりにシステムのデフォルト・エンコーディング(通常は ascii )を使用することになります。

encoding

このレスポンスのエンコードを含む文字列。 エンコードは、次のメカニズムを順番に試して解決されます:

  1. コンストラクタ encoding 引数に渡されたエンコーディング

  2. Content-Type HTTPヘッダーで宣言されたエンコーディング。 このエンコードが有効でない(つまり不明の)場合、無視され、次の解決メカニズムが試行されます。

  3. レスポンス・ボディで宣言されたエンコーディング。 TextResponseクラスは、このための特別な機能を提供しません。 ただし、 HtmlResponseXmlResponse クラスはサポートします。

  4. レスポンス・ボディを見て推測するエンコーディング。 これはより壊れやすい方法ですが、最後に試す方法でもあります。

selector

レスポンスをターゲットとして使用する Selector インスタンス。セレクターは最初のアクセスで遅延的(lazily)にインスタンス化されます。

TextResponse オブジェクトは標準の Response に加えて以下のメソッドをサポートします:

xpath(query)

TextResponse.selector.xpath(query) へのショートカット:

response.xpath('//p')
css(query)

TextResponse.selector.css(query) へのショートカット:

response.css('p')
body_as_unicode()

text と同じですが、メソッドとして使用できます。 このメソッドは、後方互換性のために残されています。 response.text を優先してください。

HtmlResponseオブジェクト

class scrapy.http.HtmlResponse(url[, ...])

HtmlResponse クラスは TextResponse のサブクラスで、HTMLの meta http-equiv 属性を調べることでエンコーディングの自動検出サポートを追加します。 TextResponse.encoding 参照。

XmlResponseオブジェクト

class scrapy.http.XmlResponse(url[, ...])

XmlResponse クラスは TextResponse のサブクラスで、XML宣言行を調べることでエンコーディングの自動検出サポートを追加します。 TextResponse.encoding 参照。