Scrapy 2.5 文書

Scrapyは高速で高レベルのWebクロール(web crawling)およびWebスクレイピング(web scraping)フレームワークであり、Webサイトをクロールし、ページから構造化データを抽出するために使用されます。 データ・マイニングから監視、自動テストまで、幅広い目的に使用できます。

お助け

問題がありますか? でしたらこれらが助けになるでしょう。

入門

Scrapyを3行で説明シル

Scrapyは、Webサイトをクロールし、構造化されたデータを抽出するためのアプリケーション・フレームワークです。データ・フレームワークは、データ・マイニング、情報処理、履歴アーカイブなど、さまざまな有用なアプリケーションに使用できます。

Scrapyは元々「ウェブ・スクレイピング(web scraping)」用に設計されていましたが、API(Amazon Associates Web Services など)を使用してデータを抽出したり、汎用のWebクローラーとして使用することもできます。

スパイダー例概観

Scrapyの恩恵を示すために、最も簡単な方法でスパイダーを実行するScrapy Spiderの例を紹介します。

以下は、Webサイトhttp://quotes.toscrape.comから有名な引用をスクレイピングするスパイダーのコードです:

import scrapy


class QuotesSpider(scrapy.Spider):
    name = 'quotes'
    start_urls = [
        'http://quotes.toscrape.com/tag/humor/',
    ]

    def parse(self, response):
        for quote in response.css('div.quote'):
            yield {
                'author': quote.xpath('span/small/text()').get(),
                'text': quote.css('span.text::text').get(),
            }

        next_page = response.css('li.next a::attr("href")').get()
        if next_page is not None:
            yield response.follow(next_page, self.parse)

これをテキスト・ファイルに入れ、「quotes_spider.py」などの名前を付けて、 runspider コマンドを使用してスパイダーを実行します:

scrapy runspider quotes_spider.py -o quotes.jl

これが完了すると、 quotes.jl ファイルに、以下のようなテキストと著者を含むJSON形式の引用のリストができます:

{"author": "Jane Austen", "text": "\u201cThe person, be it gentleman or lady, who has not pleasure in a good novel, must be intolerably stupid.\u201d"}
{"author": "Steve Martin", "text": "\u201cA day without sunshine is like, you know, night.\u201d"}
{"author": "Garrison Keillor", "text": "\u201cAnyone who thinks sitting in church can make you a Christian must also think that sitting in a garage can make you a car.\u201d"}
...
あ…ありのまま 今 起こった事を話すぜ!

あなたがコマンド scrapy runspider quotes_spider.py を実行すると、Scrapyはその内部でスパイダー定義を探し、そのクローラー・エンジンを介して実行しました。

クロールは start_urls 属性で定義されたURL群(この場合、 humor カテゴリのquoteのURLのみ)にリクエストを行うことで開始し、デフォルトのコールバック・メソッド parse を呼び出して、引数としてレスポンス・オブジェクトを渡します。 parse コールバックでは、CSSセレクターを使用してquote要素をループし、抽出されたquoteテキストと著者を含むPython辞書を生成(yield)し、次のページへのリンクを探し、同一のコールバック・メソッド parse を使用して次のリクエストをスケジュールします。

ここで、Scrapyの主な利点の1つに気付きます。リクエストの スケジューリングと処理は非同期 です。つまり、Scrapyはリクエストが終了して処理されるのを待つ必要がなく、その間に別のリクエストを送信したり、他のことを実行したりできます。 これは、一部のリクエストが失敗したり、処理中にエラーが発生した場合でも、他のリクエストが続行できることも意味します。

これにより、非常に高速なクロール(フォールトトレラント(訳注:その構成部品の一部が故障しても正常に処理を続行するシステム)な方法で複数の同時要求を同時に送信)が可能になるけれども、更にScrapyでは いくつかの設定 を通してクロールのポライトネス(訳注:円滑な人間関係を確立・維持するための言語行動)を制御することもできます。各リクエスト間にダウンロード遅延を設定したり、ドメインごとまたはIPごとの同時リクエストの量を制限したり、これらを自動的に把握しようとする 自動スロットル拡張の使用 も可能です。

注釈

これは フィード・エクスポート を使用してJSONファイルを生成します。エクスポート形式(例えばXMLやCSVなど)またはストレージ・バックエンド(例えば(FTPや Amazon S3 )。あなたは アイテム・パイプライン を記述して、アイテムをデータベースに保存することもできます。

他に何かある?

Scrapyを使用してWebサイトからアイテムを抽出および保存する方法を見てきましたが、これはほんのさわりです。 Scrapyはスクレイピングを簡単かつ効率的にするための次のような強力な機能を多数提供します:

  • HTML/XMLソースからの、データ 選択と抽出 のための拡張CSSセレクターとXPath式の使用と、正規表現を使用して抽出するヘルパー・メソッドを組み込みでサポート。

  • 対話シェル (IPython対応)は、CSSおよびXPath式を試してデータをスクレイピングするためのもので、スパイダーを作成またはデバッグするときに非常に便利です。

  • 複数の形式(JSON、CSV、XML)でのデータ生成と、複数のバックエンド・タイプ(FTP、S3、ローカルファイルシステム)に保存するための フィード・エクスポート生成 を組み込みでサポート。

  • 不明な、非標準や壊れたエンコーディング宣言を処理するための、強力なエンコード支援と自動検出。

  • 強力な拡張性サポート により、 シグナル と明確に定義されたAPI(ミドルウェアと 拡張機能パイプライン)を使用して、あなた独自の機能をプラグインできます。

  • 広範な組み込み拡張機能と処理用のミドルウェア:

    • クッキーやセッションの取扱

    • 圧縮、認証、キャッシングなどのHTTP機能

    • ユーザ・エージェントのなりすまし(spoofing)

    • robots.txt

    • クロールの深さの制限

    • などなど

  • Telnet は、クローラー内部の調査およびデバッグのために、あなたのScrapyプロセス内で実行されているPythonコンソールにフックします。

  • さらに、その他の便利な機能として、サイトマップ(Sitemaps)およびXML/CSVフィードからサイトをクロールするための再利用可能なスパイダーや、 スクレイプされたアイテムに関連付けられている、 画像(または他の媒体)を自動ダウンロードするための 媒体パイプライン や、DNSリゾルバのキャッシングなど、その他多数あります!

さてお次は?

お次は、 Scrapyインストール を行い チュートリアル で本格的なScrapyプロジェクトを作成する方法を学び、Scrapyコミュニティに参加(join the community)します。あなたがScrapyに興味を持ってくれてありがうございます!

インストール ガイド

対象とするPythonのバージョン

Scrapyには、CPython 実装(デフォルト)または PyPy 7.2.0+ 実装のいずれかの Python3.6+ が必要です( Alternate Implementations 参照)。

Scrapyのインストール

あなたが Anaconda または Miniconda を使用している場合、Linux用 や Windows用 や macOS用の最新のパッケージがある conda-forge チャンネルからパッケージをインストールできます。

conda を使用してScrapyをインストールするには、以下を実行します:

conda install -c conda-forge scrapy

代わりに、既にPythonパッケージのインストールに精通している場合は、Scrapyとその依存関係をPyPIからインストールできます:

pip install Scrapy

システムパッケージとの競合を避けるため、Scrapyを 専用のvirtualenv環境 にインストールすることを、私たちは強くお勧めします(訳注:python3であればvenv環境)。

あなたのご使用のオペレーティングシステムによっては、一部のScrapy依存関係のコンパイルの問題を解決する必要がある場合があるため、必ず プラットフォーム別インストール・ノート を確認してください。

より詳細なプラットフォーム固有の手順、およびトラブルシューティング情報については、以下をお読みください。

あなたが知っておくべきこと

Scrapyは純粋なPythonで書かれており、いくつかの主要なPythonパッケージに依存しています。(とりわけ以下に依存します):

  • lxml 、効率的なXMLおよびHTMLパーサー

  • parsel 、lxmlで記述されたHTML/XMLデータ抽出ライブラリ

  • w3lib 、URLとWebページのエンコーディングを扱うための多目的ヘルパー

  • twisted 、非同期ネットワーキングフレームワーク

  • さまざまなネットワークレベルのセキュリティニーズに対処するための cryptography (暗号化) と pyOpenSSL

Scrapyがテストできる最小バージョンは次のとおりです:

  • Twisted 14.0

  • lxml 3.4

  • pyOpenSSL 0.14

Scrapyはこれらのパッケージの古いバージョンで動作する可能性がありますが、それらに対してテストされていないため、動作を継続する保証はありません。

これらのPythonパッケージのいくつかは、プラットフォームによっては追加のインストールが必要な非Pythonパッケージに依存しています。 プラットフォーム固有のガイド で確認して下さい。

これらの依存関係に関連する問題が発生した場合は、それぞれのインストール手順を参照してください:

プラットフォーム別インストール・ノート

Windows

pipを使用してWindowsにScrapyをインストールすることは不可能ではありませんが、インストールにまつわる多くの問題を回避するために、 Anaconda または Miniconda をインストールし、 conda-forge チャンネルのパッケージを使用することをお勧めします。

あなたが Anaconda または Miniconda をインストールしたら、次のコマンドでScrapyをインストールします:

conda install -c conda-forge scrapy

pip を使用してWindowsにScrapyをインストールするには:

警告

このインストール方法では、Scrapyの依存関係をインストールするために “Microsoft Visual C++” が必要です。これには、Anacondaより非常に多くのディスク容量が必要です。

  1. Microsoft C++ Build Tools をダウンロードして実行し、Visual Studio インストーラーをインストールします。

  2. Visual Studio インストーラーを実行します。

  3. [Workloads]セクションで、 C++ build tools を選択します。

  4. インストールの詳細を確認し、以下のパッケージがオプションのコンポーネントとして選択されていることを確認してください。

    • MSVC (e.g MSVC v142 - VS 2019 C++ x64/x86 build tools (v14.23) )

    • Windows SDK (e.g Windows 10 SDK (10.0.18362.0))

  5. Visual Studio Build Tools をインストールします。

これで、あなたは pip を使用して Scrapyのインストール を実行できるようになります。

Ubuntu 14.04またはそれ以上

Scrapyは現在、lxml、twisted、pyOpenSSLの割と最近のバージョンでテストされており、最近のUbuntuディストリビューションと互換性があります。 しかし、TLS接続に潜在的な問題があるUbuntu 14.04などの古いバージョンのUbuntuもサポートされるべきです。

Ubuntuが提供する python-scrapy パッケージを 使用しないでください 。これらはたいてい古すぎて、最新のScrapyに追いつくことができていません。

Ubuntu(またはUbuntuベース)システムにScrapyをインストールするには、以下の依存関係をインストールする必要があります:

sudo apt-get install python3 python3-dev python3-pip libxml2-dev libxslt1-dev zlib1g-dev libffi-dev libssl-dev
  • python3-devzlib1g-devlibxml2-devlibxslt1-dev は、 lxml の為に必要です。

  • libssl-devlibffi-devcryptography の為に必要です。

その後、 virtualenv 内で pip でScrapyをインストールできます:

pip install scrapy

注釈

Python以外の同様の依存関係を使用して、Debian Jessie(8.0)以降にScrapyをインストールできます。

macOS

Scrapyの依存関係を構築するには、Cコンパイラと開発ヘッダーが必要です。 macOSでは、通常これはAppleのXcode開発ツールによって提供されます。 Xcodeコマンドラインツールをインストールするには、ターミナルウィンドウを開き、以下を実行します:

xcode-select --install

pip によるシステムパッケージの更新を妨げる既知の問題(known issue)があります。 Scrapyとその依存関係を正常にインストールするには、これに対処する必要があります。 以下にいくつかの解決策を示します:

  • (推奨) システムのpythonを使用しないでください。 システムの他の部分と競合しない新しい更新バージョンをインストールしてください。 homebrew パッケージマネージャーを使用して行う方法は次のとおりです:

    • https://brew.sh/ の指示に従って homebrew をインストールします。

    • PATH 環境変数を更新して、システムパッケージより先にhomebrewパッケージを使用するように指定します(デフォルトのシェルとして zsh を使用している場合は、 .bashrc.zshrc に変更します):

      echo "export PATH=/usr/local/bin:/usr/local/sbin:$PATH" >> ~/.bashrc
      
    • .bashrc をリロードして、変更が行われたことを確認します:

      source ~/.bashrc
      
    • pythonのインストール:

      brew install python
      
    • pythonの最新バージョンには pip がバンドルされているため、個別にインストールする必要はありません。 そうでない場合は、pythonをアップグレードします:

      brew update; brew upgrade python
      
  • (オプション) Python仮想環境内にScrapyをインストール

この方法は、上記のmacOSの問題の回避策ですが、依存関係を管理するための全体的なグッドプラクティスであり、最初の方法を補完できます。

これらの回避策のいずれかを行った後、Scrapyをインストールできるはずです:

pip install Scrapy
PyPy

私たちは最新のPyPyバージョンを使用することをお勧めします。 テストされたバージョンは5.9.0です。 PyPy3では、Linuxインストールのみがテストされました。

現在、Scrapyが依存するほとんどの依存コンポーネントには、CPython用のバイナリホイール形式のパッケージがありますが、PyPy用ではありません。 これは、これらの依存関係がインストール中に構築されることを意味します。 macOSでは、暗号化の依存関係の構築に関する問題に直面する可能性があります。この問題の解決策は こちら で説明されています。 brew install openssl してから、このコマンドが推奨するフラグをエクスポートします(Scrapyのインストール時にのみ必要)。 Linuxへのインストールには、ビルドの依存関係のインストール以外に特別な問題はありません。 WindowsでPyPyを使用したScrapyのインストールはテストされていません。

あなたは、 scrapy bench を実行して、Scrapyが正しくインストールされていることを確認できます。 このコマンドが TypeError: ... got 2 unexpected keyword arguments のようなエラーを出す場合、これはsetuptoolsが1つのPyPy固有の依存関係を選択できなかったことを意味します。 この問題を修正するには、 pip install 'PyPyDispatcher>=2.1.0' を実行します。

トラブルシューティング

AttributeError: 'module' object has no attribute 'OP_NO_TLSv1_1'

Scrapy、Twisted、またはpyOpenSSLをインストールまたはアップグレードした後、トレースバックで以下の例外が発生する場合があります:

[…]
  File "[…]/site-packages/twisted/protocols/tls.py", line 63, in <module>
    from twisted.internet._sslverify import _setAcceptableProtocols
  File "[…]/site-packages/twisted/internet/_sslverify.py", line 38, in <module>
    TLSVersion.TLSv1_1: SSL.OP_NO_TLSv1_1,
AttributeError: 'module' object has no attribute 'OP_NO_TLSv1_1'

この例外が発生する理由は、TwistedのバージョンがサポートしていないpyOpenSSLのバージョンがシステムまたは仮想環境にあるためです。

TwistedのバージョンがサポートするpyOpenSSLのバージョンをインストールするには、 tls 追加オプションでTwistedを再インストールします:

pip install twisted[tls]

詳細は Issue #2473 をご覧ください。

Scrapyチュートリアル

このチュートリアルでは、Scrapyがシステムに既にインストールされていると仮定します。 そうでない場合は、 インストール ガイド を参照してください。

ここでは quotes.toscrape.com という、有名な著者からの引用をリストするウェブサイトをスクレイピングします。

このチュートリアルでは以下の作業について説明します。

  1. 新しいScrapyプロジェクトの作成

  2. スパイダー(spider) を作成してサイトをクロールし、データを抽出します。

  3. コマンドラインを使用してスクレイピングされたデータをエクスポートする。

  4. 再帰的にリンクをたどるようにスパイダーを変更する。

  5. スパイダー引数の使用

Scrapyは Python で書かれています。 この言語を初めて使用する場合は、Scrapyを最大限に活用するために、この言語がどのようなものかを理解することから始めてください。

すでに他の言語に精通しており、Pythonをすばやく学習したい場合は、 Python Tutorial (訳注:日本語版 https://docs.python.org/ja/3/tutorial/)が優れた文書です。

プログラミングが初めてで、Pythonを使い始めたい場合は、以下の書籍が役立ちます:

また、 this list of Python resources for non-programmers (この非プログラマ向けのPythonリソースのリスト)と、 suggested resources in the learnpython-subreddit (learnpython-subredditの推奨リソース)を参照することもできます。

プロジェクトの作成

スクレイピングを開始する前に、新しいScrapyプロジェクトをセットアップする必要があります。 あなたのコードを保存して実行するディレクトリを入力してください:

scrapy startproject tutorial

これにより、以下の内容の tutorial ディレクトリが作成されます:

tutorial/
    scrapy.cfg            # deploy configuration file

    tutorial/             # project's Python module, you'll import your code from here
        __init__.py

        items.py          # project items definition file

        middlewares.py    # project middlewares file

        pipelines.py      # project pipelines file

        settings.py       # project settings file

        spiders/          # a directory where you'll later put your spiders
            __init__.py

私たちの最初のスパイダー

スパイダーはユーザが定義するクラスであり、ScrapyはWebサイト(またはWebサイトのグループ)から情報をスクレイピングするために使用します。 Spider をサブクラス化して最初のリクエストを作成し、オプションで、ページ内のリンクをたどる方法やダウンロードしたページ内容をパースしてデータを抽出する方法を定義する必要があります。

以下は、最初のスパイダーのコードです。 プロジェクトの tutorial/spiders ディレクトリの下の quotes_spider.py という名前のファイルに保存します:

import scrapy


class QuotesSpider(scrapy.Spider):
    name = "quotes"

    def start_requests(self):
        urls = [
            'http://quotes.toscrape.com/page/1/',
            'http://quotes.toscrape.com/page/2/',
        ]
        for url in urls:
            yield scrapy.Request(url=url, callback=self.parse)

    def parse(self, response):
        page = response.url.split("/")[-2]
        filename = f'quotes-{page}.html'
        with open(filename, 'wb') as f:
            f.write(response.body)
        self.log(f'Saved file {filename}')

ご覧のとおり、スパイダーは scrapy.Spider をサブクラス化し、いくつかの属性とメソッドを定義しています:

  • name は、スパイダーを識別します。 プロジェクト内で一意である必要があります。つまり、異なるスパイダーに同じ名前を設定することはできません。

  • start_requests() は、スパイダーがクロールを開始するリクエストの反復可能オブジェクト(iterable)を返す必要があります(リクエストのリストを返すか、ジェネレーター関数を作成できます)。これらの初期リクエストから後続のリクエストが連続して生成されます(訳注:iterableの意味はPythonドキュメント/用語集 https://docs.python.org/ja/3/glossary.html 参照)。

  • parse() は、行われたリクエストごとにダウンロードされたレスポンスを処理するために呼び出されるメソッドです。 リクエスト・パラメーターは TextResponse のインスタンスで、ページ内容を保持し、さらにそれを処理するための便利なメソッドを持っています。

    parse() メソッドは通常、レスポンスをパースし、スクレイプされたデータを辞書として抽出し、追跡する新しいURLを見つけて、それらから新しいリクエスト(Request)を作成します。

私たちのスパイダーの実行方法

スパイダーを動作させるには、プロジェクトの最上位ディレクトリに移動して、以下を実行します:

scrapy crawl quotes

このコマンドは、追加したばかりの quotes という名前のスパイダーを実行し、 quotes.toscrape.com ドメインへのリクエストを送信します。以下のような出力が得られます:

... (omitted for brevity)
2016-12-16 21:24:05 [scrapy.core.engine] INFO: Spider opened
2016-12-16 21:24:05 [scrapy.extensions.logstats] INFO: Crawled 0 pages (at 0 pages/min), scraped 0 items (at 0 items/min)
2016-12-16 21:24:05 [scrapy.extensions.telnet] DEBUG: Telnet console listening on 127.0.0.1:6023
2016-12-16 21:24:05 [scrapy.core.engine] DEBUG: Crawled (404) <GET http://quotes.toscrape.com/robots.txt> (referer: None)
2016-12-16 21:24:05 [scrapy.core.engine] DEBUG: Crawled (200) <GET http://quotes.toscrape.com/page/1/> (referer: None)
2016-12-16 21:24:05 [scrapy.core.engine] DEBUG: Crawled (200) <GET http://quotes.toscrape.com/page/2/> (referer: None)
2016-12-16 21:24:05 [quotes] DEBUG: Saved file quotes-1.html
2016-12-16 21:24:05 [quotes] DEBUG: Saved file quotes-2.html
2016-12-16 21:24:05 [scrapy.core.engine] INFO: Closing spider (finished)
...

次に、現在のディレクトリのファイルを確認します。 parse メソッドが指示するように、それぞれのURLのコンテンツを持つ2つの新しいファイル quotes-1.htmlquotes-2.html が作成されていることに気付くはずです。

注釈

なぜまだHTMLをパースしていないのかって?順番に説明するからもうちょい待ってくれ。

一体全体どういう仕組みなのか?

Scrapyは、スパイダーの start_requests メソッドによって返される scrapy.Request オブジェクトをスケジュールします。 それぞれのレスポンスを受信すると、 Response オブジェクトをインスタンス化し、リクエストに関連付けられたコールバック・メソッド(この場合は parse メソッド)を呼び出して、レスポンスを引数として渡します。

start_requestsメソッドへのショートカット

URLから start_requests() オブジェクトを生成する start_requests() メソッドを実装する代わりに、単にURLのリストで start_urls を定義できます。 このリストはそれから start_requests() のデフォルト実装で使用され、あなたのスパイダーの初期リクエストを作成します:

import scrapy


class QuotesSpider(scrapy.Spider):
    name = "quotes"
    start_urls = [
        'http://quotes.toscrape.com/page/1/',
        'http://quotes.toscrape.com/page/2/',
    ]

    def parse(self, response):
        page = response.url.split("/")[-2]
        filename = f'quotes-{page}.html'
        with open(filename, 'wb') as f:
            f.write(response.body)

parse() メソッドは、Scrapyに明示的に指示していない場合でも、これらのURLの各リクエストを処理するために呼び出されます。 これは、 parse() がScrapyのデフォルトのコールバック・メソッドであり、明示的にコールバックが割り当てられていないリクエストに対して呼び出されるためです。

データの抽出

Scrapyでデータを抽出する方法を学ぶ最良の方法は、 Scrapyシェル を使用してセレクターを試すことです。 以下のように実行します:

scrapy shell 'http://quotes.toscrape.com/page/1/'

注釈

コマンドラインからScrapyシェルを実行するときは、常にURLをクォーテーションで囲むことを忘れないでください。そうしないと、引数(つまり、 & キャラクタ)を含むURLは機能しません。

Windowsでは代わりにダブルクォーテーションを使って下さい:

scrapy shell "http://quotes.toscrape.com/page/1/"

あなたは以下のようなものを見る事になるでしょう:

[ ... Scrapy log here ... ]
2016-09-19 12:09:27 [scrapy.core.engine] DEBUG: Crawled (200) <GET http://quotes.toscrape.com/page/1/> (referer: None)
[s] Available Scrapy objects:
[s]   scrapy     scrapy module (contains scrapy.Request, scrapy.Selector, etc)
[s]   crawler    <scrapy.crawler.Crawler object at 0x7fa91d888c90>
[s]   item       {}
[s]   request    <GET http://quotes.toscrape.com/page/1/>
[s]   response   <200 http://quotes.toscrape.com/page/1/>
[s]   settings   <scrapy.settings.Settings object at 0x7fa91d888c10>
[s]   spider     <DefaultSpider 'default' at 0x7fa91c8af990>
[s] Useful shortcuts:
[s]   shelp()           Shell help (print this help)
[s]   fetch(req_or_url) Fetch request (or URL) and update local objects
[s]   view(response)    View response in a browser

シェルを使用して、あなたはレスポンス・オブジェクトで CSS を使用して要素の選択を試す事ができます:

>>> response.css('title')
[<Selector xpath='descendant-or-self::title' data='<title>Quotes to Scrape</title>'>]

response.css('title') を実行した結果は、 SelectorList というリストのようなオブジェクトになり、これはXML/HTML要素をラップし、さらにクエリを実行して選択範囲を細かくしたり、データを抽出したりできるオブジェクトである Selector のリストになっています。

上記のタイトルからテキストを抽出するには、以下のようにします:

>>> response.css('title::text').getall()
['Quotes to Scrape']

ここで注意すべき点が2つあります。1つは、CSSクエリに ::text を追加したことです。これは、 <title> 要素内のテキスト要素のみを直接選択することを意味します。 ::text を指定しない場合、そのタグを含む完全なタイトル要素を取得します:

>>> response.css('title').getall()
['<title>Quotes to Scrape</title>']

もう1つは、 .getall() を呼び出した結果がリストであるということです。セレクターが複数の結果を返す可能性があり、そしてそれらの全てを抽出します。この場合のように、最初の結果だけが必要であることがわかったら、次の操作を実行できます:

>>> response.css('title::text').get()
'Quotes to Scrape'

代わりに以下のように書くこともできます:

>>> response.css('title::text')[0].get()
'Quotes to Scrape'

けれども、 SelectorList インスタンスで .get() を直接使用すると、 IndexError を回避し、セレクターに一致する要素が見つからない場合 None を返します。

ここに教訓があります。ほとんどのスクレイピングコードでは、ページ上で見つからないものに起因するエラーに対して回復力を持たせ、一部のスクレイピングに失敗した場合でも、少なくとも いくつかの データを取得できるようにします。

getall() メソッドや get() メソッドに加えて、 正規表現 (訳注: https://docs.python.org/ja/3/library/re.html ) により抽出する re() メソッドも使用できます:

>>> response.css('title::text').re(r'Quotes.*')
['Quotes to Scrape']
>>> response.css('title::text').re(r'Q\w+')
['Quotes']
>>> response.css('title::text').re(r'(\w+) to (\w+)')
['Quotes', 'Scrape']

使用する適切なCSSセレクターを見つけるには、 view(response) を使用してWebブラウザーのシェルからレスポンス・ページを開くと便利です。 ブラウザの開発ツールを使用してHTMLを調査し、セレクターを作成できます(Webブラウザの開発ツールを使ってスクレイピングする 参照)。

Selector Gadget という、多くのブラウザで動作する、選択された要素のCSSセレクターを視覚的にすばやく探せる素晴らしいツールもあります。

XPathの簡単な紹介

CSS に加えて、Scrapyセレクターは XPath 式の使用もサポートしています:

>>> response.xpath('//title')
[<Selector xpath='//title' data='<title>Quotes to Scrape</title>'>]
>>> response.xpath('//title/text()').get()
'Quotes to Scrape'

XPath式は非常に強力であり、Scrapyセレクターの基盤です。 実際、CSSセレクターは内部でXPathに変換されます。 シェル内のセレクター・オブジェクトのテキスト表現をよく読んでいれば、あなたはそれに気付く事ができるでしょう。

CSSセレクターほど一般的ではないかもしれませんが、XPath式は構造をナビゲートするだけでなく、内容を探すことができるため、より強力になります。 XPathを使用すると、「『Next Page』というテキストを含むリンクを選択」というような事ができます。これにより、XPathはスクレイピングのタスクに非常に適合します。CSSセレクターの構築方法を既に知っている場合でも、XPathを学ぶことをお勧めします。

ここではXPathについてはあまり取り上げませんが、 ScrapyセレクターでXPathを使用 に詳しく載っています。XPathの詳細については、 this tutorial to learn XPath through examplesthis tutorial to learn "how to think in XPath" を私たちはお勧めします。

引用と著者の抽出

選択と抽出について少し理解できたので、Webページから引用を抽出するコードを作成して、スパイダーを完成させましょう。

http://quotes.toscrape.com の各引用は、次のようなHTML要素で表されます:

<div class="quote">
    <span class="text">“The world as we have created it is a process of our
    thinking. It cannot be changed without changing our thinking.”</span>
    <span>
        by <small class="author">Albert Einstein</small>
        <a href="/author/Albert-Einstein">(about)</a>
    </span>
    <div class="tags">
        Tags:
        <a class="tag" href="/tag/change/page/1/">change</a>
        <a class="tag" href="/tag/deep-thoughts/page/1/">deep-thoughts</a>
        <a class="tag" href="/tag/thinking/page/1/">thinking</a>
        <a class="tag" href="/tag/world/page/1/">world</a>
    </div>
</div>

Scrapyシェルで少しいじって、必要なデータを抽出する方法を見つけましょう:

$ scrapy shell 'http://quotes.toscrape.com'

引用HTML要素のセレクターのリストを取得します:

>>> response.css("div.quote")
[<Selector xpath="descendant-or-self::div[@class and contains(concat(' ', normalize-space(@class), ' '), ' quote ')]" data='<div class="quote" itemscope itemtype...'>,
 <Selector xpath="descendant-or-self::div[@class and contains(concat(' ', normalize-space(@class), ' '), ' quote ')]" data='<div class="quote" itemscope itemtype...'>,
 ...]

上記のクエリによって返された各セレクターを使用すると、サブ要素に対してさらにクエリを実行できます。 最初のセレクターを変数に割り当てて、特定の引用でCSSセレクターを直接実行できるようにします:

>>> quote = response.css("div.quote")[0]

それでは、作成したばかりの quote オブジェクトを使用して、その引用から textauthortags を抽出しましょう:

>>> text = quote.css("span.text::text").get()
>>> text
'“The world as we have created it is a process of our thinking. It cannot be changed without changing our thinking.”'
>>> author = quote.css("small.author::text").get()
>>> author
'Albert Einstein'

タグは文字列のリストになっているので、 .getall() メソッドを使用してそれらすべてを取得できます:

>>> tags = quote.css("div.tags a.tag::text").getall()
>>> tags
['change', 'deep-thoughts', 'thinking', 'world']

各パーツを抽出する方法を考え出したので、すべての引用要素を反復処理して、それらをPython辞書にまとめることができます:

>>> for quote in response.css("div.quote"):
...     text = quote.css("span.text::text").get()
...     author = quote.css("small.author::text").get()
...     tags = quote.css("div.tags a.tag::text").getall()
...     print(dict(text=text, author=author, tags=tags))
{'text': '“The world as we have created it is a process of our thinking. It cannot be changed without changing our thinking.”', 'author': 'Albert Einstein', 'tags': ['change', 'deep-thoughts', 'thinking', 'world']}
{'text': '“It is our choices, Harry, that show what we truly are, far more than our abilities.”', 'author': 'J.K. Rowling', 'tags': ['abilities', 'choices']}
...
私たちのスパイダーでデータを抽出する

私たちのスパイダーに戻ります。これまでは、特にデータを抽出せず、HTMLページ全体をローカルファイルに保存するだけでした。それでは、ここで、上記の抽出ロジックを私たちのスパイダーに組み込みましょう。

Scrapyスパイダーは通常、ページから抽出されたデータを含む多くのPython辞書を生成します。 これを行うには、以下に示すように、コールバックでPythonキーワード yield を使用します:

import scrapy


class QuotesSpider(scrapy.Spider):
    name = "quotes"
    start_urls = [
        'http://quotes.toscrape.com/page/1/',
        'http://quotes.toscrape.com/page/2/',
    ]

    def parse(self, response):
        for quote in response.css('div.quote'):
            yield {
                'text': quote.css('span.text::text').get(),
                'author': quote.css('small.author::text').get(),
                'tags': quote.css('div.tags a.tag::text').getall(),
            }

あなたがこのスパイダーを実行すると、抽出されたデータがlogとともに出力されます:

2016-09-19 18:57:19 [scrapy.core.scraper] DEBUG: Scraped from <200 http://quotes.toscrape.com/page/1/>
{'tags': ['life', 'love'], 'author': 'André Gide', 'text': '“It is better to be hated for what you are than to be loved for what you are not.”'}
2016-09-19 18:57:19 [scrapy.core.scraper] DEBUG: Scraped from <200 http://quotes.toscrape.com/page/1/>
{'tags': ['edison', 'failure', 'inspirational', 'paraphrased'], 'author': 'Thomas A. Edison', 'text': "“I have not failed. I've just found 10,000 ways that won't work.”"}

スクレイピングしたデータの格納

スクレイピングされたデータを保存する最も簡単な方法は、 フィード・エクスポート を以下のコマンドで使用することです:

scrapy crawl quotes -O quotes.json

それにより、スクレイピングされたすべてのアイテムを含み JSON でシリアライズされた quotes.json ファイルを生成します。

-O コマンドラインスイッチは既存のファイルを上書きします。 一方 -o を使用すると、既存のファイルに新しいコンテンツを追加します。 ただし、JSONファイルに追加をすると、無効なJSONになります。ファイルに追加するときは、 JSON Lines など別のシリアル化形式の使用を検討してください:

scrapy crawl quotes -o quotes.jl

JSON Lines フォーマットは、ストリームに似ているため便利です。新しいレコードを簡単に追加できます。 2回実行する場合、JSONと違って壊れる事はありません。また、各レコードは個別の行であるため、メモリにすべてを収めなくても大きなファイルを処理できます。コマンドラインでそれを行うのに役立つ JQ などのツールがあります。

小さなプロジェクト(このチュートリアルのようなプロジェクト)では、これで十分です。 ただし、スクレイピングされたアイテムを使用してより複雑な操作を実行する場合は、 アイテム・パイプライン を記述できます。 アイテム・パイプラインのプレースホルダーファイルは、プロジェクトの作成時に tutorial/pipelines.py に設定されています。 ただし、スクレイピングされたアイテムを保存するだけの場合は、アイテム・パイプラインを実装する必要はありません。

スパイダー引数の使用

あなたはスパイダーの実行時に -a オプションを使用して、スパイダーにコマンドライン引数を提供できます:

scrapy crawl quotes -O quotes-humor.json -a tag=humor

これらの引数はSpiderの __init__ メソッドに渡され、デフォルトでspider属性になります。

この例では、 tag 引数に指定された値は self.tag を介して利用できます。 これを使用して、スパイダーに特定のタグを持つ引用のみを読み込み(fetch)させ、引数に基づいてURLを構築できます:

import scrapy


class QuotesSpider(scrapy.Spider):
    name = "quotes"

    def start_requests(self):
        url = 'http://quotes.toscrape.com/'
        tag = getattr(self, 'tag', None)
        if tag is not None:
            url = url + 'tag/' + tag
        yield scrapy.Request(url, self.parse)

    def parse(self, response):
        for quote in response.css('div.quote'):
            yield {
                'text': quote.css('span.text::text').get(),
                'author': quote.css('small.author::text').get(),
            }

        next_page = response.css('li.next a::attr(href)').get()
        if next_page is not None:
            yield response.follow(next_page, self.parse)

あなたがこのスパイダーに tag=humor 引数を渡すと、 http://quotes.toscrape.com/tag/humor などの humor タグのURLのみにアクセスすることに気付くでしょう。

スパイダー引数の取扱について更に学ぶ をご覧ください。

さぁてお次は?

このチュートリアルでは、Scrapyの基本のみを説明しましたが、ここには記載されていない他の多くの機能があります。 最も重要なものの簡単な概要については、 Scrapyを3行で説明シル の章の 他に何かある? 節を確認してください。

基本の概念 節では続けて、コマンドラインツール、スパイダー、セレクター、およびスクレイプデータのモデリングのようにチュートリアルで扱っていないその他のことについて詳しく知ることができます。 サンプルプロジェクトで遊びたい場合は、 節を確認してください。

学ぶための最良の方法は例であり、Scrapyも例外ではありません。 このため、 quotesbot という名前のサンプルScrapyプロジェクトがあります。あなたはこのプロジェクトを使用して、Scrapyをプレイし、学習することができます。 これには、 http://quotes.toscrape.com 2つのスパイダーが含まれています。1つはCSSセレクターを使用し、もう1つはXPath式を使用します。

quotesbot プロジェクトは、https://github.com/scrapy/quotesbot で入手できます。 プロジェクトのREADMEで詳細を確認できます。

あなたがgitに精通している場合は、コードをチェックアウトできます。 それ以外の場合は、 here ( https://github.com/scrapy/quotesbot/archive/master.zip )をクリックして、プロジェクトをzipファイルとしてダウンロードできます。

Scrapyを3行で説明シル

Scrapyとは何か、それがどのようにあなたに役立つかの理解。

インストール ガイド

Scrapyをあなたのコンピュータにインストール。

Scrapyチュートリアル

あなたは最初のScrapyプロジェクトを書きます。

作成済みのScrapyプロジェクトを題材に、もっともっと学びます。

基本の概念

コマンドラインツール

Scrapyは、 scrapy コマンドラインツール(ここでは「Scrapyツール」と呼びます)を通じて制御され、単に「コマンド」または「Scrapyコマンド」と呼ばれるサブコマンドと区別します。

Scrapyツールは複数の目的のためにいくつかのコマンドを提供し、それぞれが異なる引数とオプションの組を受け入れます。

(「scrapy deploy」コマンドは1.0で削除され、スタンドアロンの「scrapyd-deploy」に置き換えられました。 Deploying your project を参照してください。)

構成(configuration)の設定

Scrapyは、標準の場所にあるはずの、iniファイルスタイルの scrapy.cfg ファイルの構成パラメーターを探します。:

  1. /etc/scrapy.cfg または c:\scrapy\scrapy.cfg (お使いのコンピューターシステム全体の設定)、

  2. ~/.config/scrapy.cfg ($XDG_CONFIG_HOME) and ~/.scrapy.cfg ($HOME) は、当該ユーザー全体の設定で、

  3. (あなたの)Scrapyプロジェクトのルート内にある scrapy.cfg (詳しくは次節参照)。

これらのファイルの設定は、リストされている優先順位でマージされます。ユーザー定義の値は、システム全体のデフォルトよりも優先度が高く、プロジェクト全体の設定は、定義時に他のすべてを上書きします。

Scrapyは、多くの環境変数もまた理解しており、それらを使用して構成できます。 現在、これらは以下のとおりです。:

Scrapyプロジェクトのデフォルト構造

コマンドラインツールとそのサブコマンドを掘り下げる前に、まずScrapyプロジェクトのディレクトリ構造を理解しましょう。

変更も可能ではありますが、すべてのScrapyプロジェクトはデフォルトでは同じファイル構造を持ち、以下のようになります。:

scrapy.cfg
myproject/
    __init__.py
    items.py
    middlewares.py
    pipelines.py
    settings.py
    spiders/
        __init__.py
        spider1.py
        spider2.py
        ...

scrapy.cfg ファイルが存在するディレクトリは プロジェクトルートディレクトリ と呼ばれます。 そのファイルには、プロジェクト設定を定義するpythonモジュールの名前が含まれています。 以下に例を示します:

[settings]
default = myproject.settings

プロジェクト間でルートディレクトリを共有する

scrapy.cfg を含むプロジェクトルートディレクトリは、それぞれ独自の設定モジュールを持つ複数のScrapyプロジェクトで共有できます。

その場合、あなたの scrapy.cfg ファイルの [settings] の下で、これらの設定モジュールの1つ以上のエイリアスを定義する必要があります:

[settings]
default = myproject1.settings
project1 = myproject1.settings
project2 = myproject2.settings

デフォルトでは、 scrapy コマンドラインツールは default 設定を使用します。 scrapy コマンドラインツールを別プロジェクトのために使うには SCRAPY_PROJECT 環境変数を設定します。:

$ scrapy settings --get BOT_NAME
Project 1 Bot
$ export SCRAPY_PROJECT=project2
$ scrapy settings --get BOT_NAME
Project 2 Bot

Scrapyツールの使用

あなたは引数なしでScrapyツールを実行することから始める事ができます。そうすると、いくつかの使用方法のヘルプと使用可能なコマンドが出力されます。:

Scrapy X.Y - no active project

Usage:
  scrapy <command> [options] [args]

Available commands:
  crawl         Run a spider
  fetch         Fetch a URL using the Scrapy downloader
[...]

Scrapyプロジェクト内にいる場合、最初の行は現在アクティブなプロジェクトを印刷します。 上の例では、プロジェクトの外部から実行されました。 プロジェクト内から実行すると、以下のようなものが出力されます。:

Scrapy X.Y - project: myproject

Usage:
  scrapy <command> [options] [args]

[...]
プロジェクトの作成

Scrapyツールで通常最初に行うことは、Scrapyプロジェクトの作成です。:

scrapy startproject myproject [project_dir]

これは project_dir ディレクトリの下にScrapyプロジェクトを作成します。 project_dir を指定しなかった場合、 project_dirmyproject と同じになります。

次に、あなたは新しいプロジェクトディレクトリ内に移動します。:

cd project_dir

いまや、 あなたは、 scrapy コマンドを使用して、プロジェクトを管理および制御する準備が整いました。

プロジェクトの制御

あなたはプロジェクト内でScrapyツールを使用して、プロジェクトを制御および管理します。

例えば、新しいスパイダーを作成するには、:

scrapy genspider mydomain mydomain.com

一部のScrapyコマンド(crawl のような)は、Scrapyプロジェクト内から実行する必要があります。 プロジェクト内から実行する必要があるコマンドと実行しないコマンドの詳細については、 コマンド リファレンス をご覧ください。

また、一部のコマンドは、プロジェクト内から実行する場合、動作が若干異なる場合があることに注意してください。 たとえば、フェッチされるURLが特定のスパイダーに関連付けられている場合、fetchコマンドはスパイダーによってオーバーライドされる動作(user-agentをオーバーライドする user_agent 属性など)を使用します。 fetch コマンドはスパイダーがどのようにページをダウンロードしているかを確認するために使用されることを意図しているため、これは意図的なものです。

利用可能なツールコマンド

この節には、使用可能な組み込みコマンドの一覧とその説明および使用例が含まれています。 以下のコマンドを実行すると、いつでも各コマンドに関する詳細情報を見ることができます。:

scrapy <command> -h

そして、以下のコマンドですべての利用可能なコマンドの一覧を見ることができます。:

scrapy -h

コマンドには2種類あります。Scrapyプロジェクト内からのみ動作するコマンド(プロジェクト固有のコマンド)とアクティブなScrapyプロジェクトなしで動作するコマンド(グローバルコマンド)です。ただし、プロジェクト内から実行すると動作が若干異なる場合があります(プロジェクトのオーバーライドされた設定を使用するため)。

グローバルコマンド

プロジェクト内のみのコマンド

startproject
  • 文法: scrapy startproject <project_name> [project_dir]

  • Scrapyプロジェクト内で実行させる必要があるか: いいえ

project_dir ディレクトリの下に project_name という名前の新しいScrapyプロジェクトを作成します。 project_dir を指定しなかった場合、 project_dirproject_name と同じになります。

使用例:

$ scrapy startproject myproject
genspider
  • 文法: scrapy genspider [-t template] <name> <domain>

  • Scrapyプロジェクト内で実行させる必要があるか: いいえ

プロジェクト内から呼び出された場合、現在のフォルダーまたは現在のプロジェクトの spiders フォルダーに新しいスパイダーを作成します。 <name> パラメーターはスパイダーの name として設定され、 <domain>``はスパイダー属性の ``allowed_domains および start_urls を生成するために使用されます。

使用例:

$ scrapy genspider -l
Available templates:
  basic
  crawl
  csvfeed
  xmlfeed

$ scrapy genspider example example.com
Created spider 'example' using template 'basic'

$ scrapy genspider -t crawl scrapyorg scrapy.org
Created spider 'scrapyorg' using template 'crawl'

これは、事前定義されたテンプレートに基づいてスパイダーを作成する便利なショートカットコマンドですが、スパイダーを作成する唯一の方法ではありません。 このコマンドを使用する代わりに、自分でスパイダーソースコードファイルを作成することもできます。

crawl
  • 文法: scrapy crawl <spider>

  • Scrapyプロジェクト内で実行させる必要があるか: はい

スパイダーを使用してクロールを開始します。

使用例:

$ scrapy crawl myspider
[ ... myspider starts crawling ... ]
check
  • 文法: scrapy check [-l] <spider>

  • Scrapyプロジェクト内で実行させる必要があるか: はい

規約(contract)チェックを実行します。

使用例:

$ scrapy check -l
first_spider
  * parse
  * parse_item
second_spider
  * parse
  * parse_item

$ scrapy check
[FAILED] first_spider:parse_item
>>> 'RetailPricex' field is missing

[FAILED] first_spider:parse
>>> Returned 92 requests, expected 0..4
list
  • 文法: scrapy list

  • Scrapyプロジェクト内で実行させる必要があるか: はい

現在のプロジェクトで利用可能なすべてのスパイダーをリストします。 出力は1行につき1つのスパイダーです。

使用例:

$ scrapy list
spider1
spider2
edit
  • 文法: scrapy edit <spider>

  • Scrapyプロジェクト内で実行させる必要があるか: はい

EDITOR 環境変数または、(未設定の場合) EDITOR 設定で定義されているエディターを使用して、指定されたスパイダーを編集します。

このコマンドは、最も一般的な場合の便利なショートカットとしてのみ提供されています。もちろん開発者は、スパイダーを作成およびデバッグするためのツールまたはIDEを自由に選択できます。

使用例:

$ scrapy edit spider1
fetch
  • 文法: scrapy fetch <url>

  • Scrapyプロジェクト内で実行させる必要があるか: いいえ

Scrapyダウンローダーを使用して指定されたURLをダウンロードし、コンテンツを標準出力に書き込みます。

このコマンドの興味深い点は、ページを取得するのに、あなたのスパイダーを使ってどのようにダウンロードするかを示すということです。たとえば、スパイダーがユーザーエージェントを上書きするUSER_AGENT属性を持っていた場合、上書きしたその属性を使用します。

したがって、このコマンドを使用して、あなたは、あなたのスパイダーが特定のページを取得する方法を「見る」ことができます。

もし、このコマンドがプロジェクトの外部で使用される場合、特定のスパイダーごとの動作は適用されず、デフォルトのScrapyダウンローダー設定が使用されます。

コマンドラインオプション:

  • --spider=SPIDER: スパイダーの自動検出をバイパスし、指定のスパイダーの使用を強制する。

  • --headers: レスポンス・ボディではなく、レスポンスのHTTPヘッダーを出力します。

  • --no-redirect: HTTP 3xxリダイレクトに従わない(デフォルトではそれらに従う)。

使用例:

$ scrapy fetch --nolog http://www.example.com/some/page.html
[ ... html content here ... ]

$ scrapy fetch --nolog --headers http://www.example.com/
{'Accept-Ranges': ['bytes'],
 'Age': ['1263   '],
 'Connection': ['close     '],
 'Content-Length': ['596'],
 'Content-Type': ['text/html; charset=UTF-8'],
 'Date': ['Wed, 18 Aug 2010 23:59:46 GMT'],
 'Etag': ['"573c1-254-48c9c87349680"'],
 'Last-Modified': ['Fri, 30 Jul 2010 15:30:18 GMT'],
 'Server': ['Apache/2.2.3 (CentOS)']}
view
  • 文法: scrapy view <url>

  • Scrapyプロジェクト内で実行させる必要があるか: いいえ

あなたのScrapyスパイダーが「見ている」ように、指定されたURLをブラウザーで開きます。 スパイダーは通常のユーザーとは異なるページを見ることがあるので、これを使用してスパイダーが「見ている」ものを確認し、期待どおりであることを確認できます。

コマンドラインオプション:

  • --spider=SPIDER: スパイダーの自動検出をバイパスし、指定のスパイダーの使用を強制する。

  • --no-redirect: HTTP 3xxリダイレクトに従わない(デフォルトではそれらに従う)。

使用例:

$ scrapy view http://www.example.com/some/page.html
[ ... browser starts ... ]
shell
  • 文法: scrapy shell [url]

  • Scrapyプロジェクト内で実行させる必要があるか: いいえ

(指定されている場合)指定したURLでScrapyシェルを開始します。URLが指定されていない場合は空です。 また、UNIXスタイルのローカルファイルパス(「./」または「../」プレフィックス付きの相対パス、または絶対ファイルパス)をサポートします。 詳細については、 Scrapyシェル を参照してください。

コマンドラインオプション:

  • --spider=SPIDER: スパイダーの自動検出をバイパスし、指定のスパイダーの使用を強制する。

  • -c code: シェル内でcodeを評価し、結果を出力してexitする。

  • --no-redirect: HTTP 3xxリダイレクトに従いません(デフォルトではそれらに従います)。 これは、コマンドラインで引数として渡すことができるURLにのみ影響します。 シェル内に入ると、 fetch(url) はデフォルトでHTTPリダイレクトに従います。

使用例:

$ scrapy shell http://www.example.com/some/page.html
[ ... scrapy shell starts ... ]

$ scrapy shell --nolog http://www.example.com/ -c '(response.status, response.url)'
(200, 'http://www.example.com/')

# shell follows HTTP redirects by default
$ scrapy shell --nolog http://httpbin.org/redirect-to?url=http%3A%2F%2Fexample.com%2F -c '(response.status, response.url)'
(200, 'http://example.com/')

# you can disable this with --no-redirect
# (only for the URL passed as command line argument)
$ scrapy shell --no-redirect --nolog http://httpbin.org/redirect-to?url=http%3A%2F%2Fexample.com%2F -c '(response.status, response.url)'
(302, 'http://httpbin.org/redirect-to?url=http%3A%2F%2Fexample.com%2F')
parse
  • 文法: scrapy parse <url> [options]

  • Scrapyプロジェクト内で実行させる必要があるか: はい

指定されたURLを取得し、 --callback オプションで渡されたメソッドを使用して、または指定されていない場合は parse を使用して、それを処理するスパイダーで解析します。

コマンドラインオプション:

  • --spider=SPIDER: スパイダーの自動検出をバイパスし、指定のスパイダーの使用を強制する。

  • --a NAME=VALUE: スパイダー引数を設定(繰り返し指定可能)

  • --callback または -c: レスポンスを解析するためのコールバックとして使用するスパイダーメソッド

  • --meta または -m: コールバックリクエストに渡される追加のリクエスト meta。 これは有効なJSON文字列でなければなりません。 例: --meta='{"foo" : "bar"}'

  • --cbkwargs: コールバックに渡される追加のキーワード引数。 これは有効なJSON文字列でなければなりません。 例: --cbkwargs='{"foo" : "bar"}'

  • --pipelines: パイプラインを介してアイテムを処理する。

  • --rules または -r: CrawlSpider ルールを使用して、レスポンスの解析に使用するコールバック(スパイダーメソッド)を検出します。

  • --noitems: スクレイプしたアイテムを表示しない。

  • --nolinks: 抽出したリンクを表示しません。

  • --nocolour: pygmentsを使用して出力を色付けするのを回避します。

  • --depth `` または ``-d: リクエストを再帰的に追跡する深さレベル(デフォルト: 1)。

  • --verbose または -v: 各深度レベルの情報を表示。

  • --output または -o: スクレイピングされたアイテムをファイルにダンプします

    バージョン 2.3 で追加.

使用例:

$ scrapy parse http://www.example.com/ -c parse_item
[ ... scrapy log lines crawling example.com spider ... ]

>>> STATUS DEPTH LEVEL 1 <<<
# Scraped Items  ------------------------------------------------------------
[{'name': 'Example item',
 'category': 'Furniture',
 'length': '12 cm'}]

# Requests  -----------------------------------------------------------------
[]
settings
  • 文法: scrapy settings [options]

  • Scrapyプロジェクト内で実行させる必要があるか: いいえ

Scrapy設定の値を取得します。

プロジェクト内で使用すると、プロジェクト設定値が表示されます。それ以外の場合は、Scrapyでのその設定のデフォルト値を表示します。

使用例:

$ scrapy settings --get BOT_NAME
scrapybot
$ scrapy settings --get DOWNLOAD_DELAY
0
runspider
  • 文法: scrapy runspider <spider_file.py>

  • Scrapyプロジェクト内で実行させる必要があるか: いいえ

プロジェクトを作成せずに、Pythonファイルに含まれるスパイダーを実行します。

使用例:

$ scrapy runspider myspider.py
[ ... spider starts crawling ... ]
version
  • 文法: scrapy version [-v]

  • Scrapyプロジェクト内で実行させる必要があるか: いいえ

Scrapyバージョンを出力します。 -v とともに使用すると、Python、Twisted、Platformの情報も出力します。これはバグレポートに役立ちます。

bench
  • 文法: scrapy bench

  • Scrapyプロジェクト内で実行させる必要があるか: いいえ

簡単なベンチマークテストを実行します。 ベンチマーキング

カスタム プロジェクト コマンド

COMMANDS_MODULE 設定を使用して、カスタムプロジェクトコマンドを追加することもできます。 コマンドの実装方法の例については、 scrapy/commands Scrapyコマンドを参照してください。

COMMANDS_MODULE

デフォルト: '' (空文字列)

カスタムのScrapyコマンドを検索するために使用するモジュール。 これは、Scrapyプロジェクトにカスタムコマンドを追加するために使用されます。

例:

COMMANDS_MODULE = 'mybot.commands'
setup.pyエントリポイントを介してコマンドを登録する。

ライブラリ setup.py ファイルのエントリポイントに scrapy.commands セクションを追加することにより、外部ライブラリからScrapyコマンドを追加することもできます。

以下の例は my_command コマンドを追加します:

from setuptools import setup, find_packages

setup(name='scrapy-mymodule',
  entry_points={
    'scrapy.commands': [
      'my_command=my_scrapy_module.commands:MyCommand',
    ],
  },
 )

スパイダー

スパイダーは、特定のサイト(またはサイトのグループ)のスクレイピング方法を定義するクラスです。クロールの実行方法(リンクの追跡など)やページから構造化データを抽出する方法(アイテムのスクレイピングなど)を含みます。 つまり、スパイダーは、特定のサイト(場合によってはサイトのグループ)のページをクロールおよび解析するためのカスタム動作を定義する場所です。

スパイダーのためのスクレイピング・サイクルは以下の通りです:

  1. 最初のリクエストを生成して最初のURLをクロールし、それらのリクエストからダウンロードされたレスポンスで呼び出されるコールバック関数を指定することから始めます。

    実行する最初のリクエストは、(デフォルトで) start_urls で指定されたURLの Request を生成する start_requests() メソッドと、リクエストのコールバック関数として parse メソッドを呼び出すことによって取得されます。

  2. コールバック関数では、レスポンス (Web ページ) をパースし、 アイテム・オブジェクト または Request オブジェクトまたはこれらのオブジェクトの反復可能オブジェクトイテラブル(iterable)を返します。 これらのリクエストにはコールバック(同じコールバックの場合もあります) も含まれ、Scrapy によってダウンロードされ、指定されたコールバックによってレスポンスが処理されます。

  3. コールバック関数内では、通常 セレクター を使用してページ内容をパースし、パースしたデータでアイテムを生成します(しかし、パースには、BeautifulSoup、lxml、または任意のメカニズムを使用することもできます)。

  4. 最後に、スパイダーから返されたアイテムは通常、データベースに保存されます(アイテム パイプライン を使う事もあります)または フィード・エクスポート を使用してファイルに書き込まれます。

このサイクルはあらゆる種類のスパイダーに適用されます。そして更に、さまざまな目的の為のさまざまな種類のデフォルト・スパイダーがScrapyに同梱されています。以降、これらについても説明します。

scrapy.Spider

class scrapy.spiders.Spider[ソース]

これは最も単純なスパイダーであり、他のすべてのスパイダーの継承元となるものです(Scrapyにバンドルされているスパイダーや、自分で作成したスパイダーを含む)。特別な機能は提供しません。 start_urls スパイダー属性からリクエストを送信し、結果の各レスポンスに対してスパイダーのメソッド parse を呼び出すデフォルトの start_requests() 実装を提供するだけです。

name

このスパイダーの名前を定義する文字列。 スパイダー名は、スパイダーがScrapyによってどのように配置(およびインスタンス化)されるかであるため、一意でなければなりません。 ただし、同じスパイダーの複数のインスタンスをインスタンス化することを妨げるものはありません。 これは最も重要なスパイダーの属性であり、必須です。

スパイダーが単一のドメインをスクレイピングする場合、一般的な方法は、TLD の有無にかかわらず、ドメインに基づいてスパイダーに名前を付けることです。よって、たとえば、 mywebsite.com をクロールするスパイダーは、しばしば mywebsite と呼ばれます。

allowed_domains

このスパイダーがクロールできるドメインを含む文字列のオプションのリスト。 OffsiteMiddleware が有効になっている場合、このリスト(またはそのサブドメイン)で指定されたドメイン名に属さないURLのリクエストは追跡されません。

あなたのターゲットURLが https://www.example.com/1.html である場合、リストに 'example.com' を追加します。

start_urls

特定のURLが指定されていない場合に、スパイダーがクロールを開始するURLのリスト。 したがって、ダウンロードされる最初のページはここにリストされているページになります。 後続の Request は、開始URLに含まれるデータから連続して生成されます。

custom_settings

このスパイダーを実行するときにプロジェクト全体の設定から上書きされる設定の辞書。 インスタンス化の前に設定が更新されるため、クラス属性として定義する必要があります。

利用可能な組み込み設定のリストについては、 組み込みの設定リファレンス を参照してください。

crawler

この属性は、クラスを初期化した後に from_crawler() クラスメソッドによって設定され、このスパイダーインスタンスがバインドされている Crawler オブジェクトにリンクします。

クローラーは、単一のエントリアクセス(拡張機能、ミドルウェア、シグナルマネージャーなど)のために、プロジェクト内の多くのコンポーネントをカプセル化します。 クローラーAPI を参照して、それらの詳細を確認してください。

settings

このスパイダーを実行するための構成(Configuration)。 これは Settings のインスタンスです。この主題の詳細な紹介については 設定 トピックを参照してください。

logger

Spiderの name で作成されたPythonロガー。 スパイダーからのロギング で説明されているように、これを使用してログメッセージを送信できます。

from_crawler(crawler, *args, **kwargs)[ソース]

これは、Scrapyがスパイダーを作成するために使用するクラスメソッドです。

デフォルトの実装は __init__() メソッドのプロキシとして機能し、指定された引数 args および名前付き引数 kwargs で呼び出すため、おそらくあなたがこれを直接オーバーライドする必要はありません。

それにもかかわらず、このメソッドは新しいインスタンスで crawler および settings 属性を設定するため、スパイダーのコード内で後からアクセスできます。

パラメータ
  • crawler (Crawler instance) -- スパイダーをバインドするクローラー

  • args (list) -- __init__() メソッドに渡される引数

  • kwargs (dict) -- __init__() メソッドに渡されるキーワード引数

start_requests()[ソース]

このメソッドは、このスパイダーの最初のクロール要求で反復可能オブジェクト(iterable)を返す必要があります。 スパイダーがスクレイピングのために開かれると、Scrapyによって呼び出されます。 Scrapyはこれを1回だけ呼び出すため、ジェネレータとして start_requests() を実装しても安全です。

デフォルトの実装は、 start_urls の各URLに対して Request(url, dont_filter=True) を生成します。

ドメインのスクレイピングを開始するために使用されるリクエストを変更する場合、これはオーバーライドするメソッドです。 たとえば、POST要求を使用してログインすることから開始する必要がある場合は、以下の通りです:

class MySpider(scrapy.Spider):
    name = 'myspider'

    def start_requests(self):
        return [scrapy.FormRequest("http://www.example.com/login",
                                   formdata={'user': 'john', 'pass': 'secret'},
                                   callback=self.logged_in)]

    def logged_in(self, response):
        # here you would extract links to follow and return Requests for
        # each of them, with another callback
        pass
parse(response)[ソース]

これは、リクエストでコールバックが指定されていない場合に、ダウンロードされたレスポンスを処理するためにScrapyが使用するデフォルトのコールバックです。

parse メソッドは、レスポンスを処理し、スクレイピングされたデータや後続のURLを返します。 他のリクエストのコールバックには、 Spider クラスと同じ必要条件があります。

このメソッドは、他の Request コールバックと同様に、 Request および/または アイテム・オブジェクト の反復可能オブジェクト(iterable)を返さなければなりません。

パラメータ

response (Response) -- パース対象のレスポンス

log(message[, level, component])[ソース]

Spiderの logger を介してログメッセージを送信するラッパー。後方互換性のために保持されています。 詳細については、 スパイダーからのロギング を参照してください。

closed(reason)

スパイダーが閉じるときに呼び出されます。 このメソッドは、 spider_closed シグナルの signals.connect() へのショートカットを提供します。

ある例を見てみましょう:

import scrapy


class MySpider(scrapy.Spider):
    name = 'example.com'
    allowed_domains = ['example.com']
    start_urls = [
        'http://www.example.com/1.html',
        'http://www.example.com/2.html',
        'http://www.example.com/3.html',
    ]

    def parse(self, response):
        self.logger.info('A response from %s just arrived!', response.url)

単一のコールバックから複数のリクエストとアイテムを返します:

import scrapy

class MySpider(scrapy.Spider):
    name = 'example.com'
    allowed_domains = ['example.com']
    start_urls = [
        'http://www.example.com/1.html',
        'http://www.example.com/2.html',
        'http://www.example.com/3.html',
    ]

    def parse(self, response):
        for h3 in response.xpath('//h3').getall():
            yield {"title": h3}

        for href in response.xpath('//a/@href').getall():
            yield scrapy.Request(response.urljoin(href), self.parse)

start_urls の代わりに start_requests() を直接使用できます。データをさらに構造化するには、 Item オブジェクトを使用できます:

import scrapy
from myproject.items import MyItem

class MySpider(scrapy.Spider):
    name = 'example.com'
    allowed_domains = ['example.com']

    def start_requests(self):
        yield scrapy.Request('http://www.example.com/1.html', self.parse)
        yield scrapy.Request('http://www.example.com/2.html', self.parse)
        yield scrapy.Request('http://www.example.com/3.html', self.parse)

    def parse(self, response):
        for h3 in response.xpath('//h3').getall():
            yield MyItem(title=h3)

        for href in response.xpath('//a/@href').getall():
            yield scrapy.Request(response.urljoin(href), self.parse)

スパイダー引数

スパイダーは、振る舞いを変更する引数を受け取ることができます。 スパイダー引数の一般的な使用法のいくつかは、開始URLを定義するか、サイトの特定のセクションへのクロールを制限することですが、スパイダーの機能を構成(configure)するためでも使用できます。

スパイダー引数は、 crawl コマンドの -a コマンドライン・オプションを使用して渡します。

scrapy crawl myspider -a category=electronics

スパイダーは、 __init__ メソッド内の引数にアクセスできます。:

import scrapy

class MySpider(scrapy.Spider):
    name = 'myspider'

    def __init__(self, category=None, *args, **kwargs):
        super(MySpider, self).__init__(*args, **kwargs)
        self.start_urls = [f'http://www.example.com/categories/{category}']
        # ...

デフォルトの __init__ メソッドはスパイダー引数を取り、それらを属性としてスパイダーにコピーします。 上記の例は次のように書くこともできます:

import scrapy

class MySpider(scrapy.Spider):
    name = 'myspider'

    def start_requests(self):
        yield scrapy.Request(f'http://www.example.com/categories/{self.category}')

スパイダー引数は文字列にすぎないことに注意してください。 スパイダー自身はスパイダー引数文字列の解析を行いません。 コマンドラインから start_urls 属性を設定する場合、 ast.literal_eval() または json.loads() のようなものを使用して自分でリストに落とし込み、それを属性として設定する必要があります。そうしないと、start_urls 文字列を反復して、各文字が個別のURLとして認識されることになります(訳注:pythonによくある落とし穴で、list('hoge')['h','o','g','e'] になる)。

有効なユースケースは、 http認証資格情報(auth credentials)に使用される HttpAuthMiddleware またはユーザエージェントとして使用される UserAgentMiddleware を設定することです。

scrapy crawl myspider -a http_user=myuser -a http_pass=mypassword -a user_agent=mybot

スパイダー引数は、Scrapyd schedule.json APIを介して渡すこともできます。 Scrapyd documentation をご覧ください。

汎用スパイダー

Scrapyには、スパイダーのサブクラス化に使用できる便利な汎用スパイダーがいくつか付属しています。 それらの目的は、特定のルールに基づいてサイト上のすべてのリンクをたどったり、 Sitemaps からクロールしたり、XML/CSVフィードを解析するなど、いくつかの一般的なスクレイピング・パターンに便利な機能を提供することです。

※この節のスパイダー例は、 myproject.items モジュールで宣言された TestItem を含むプロジェクトがあると仮定しています:

import scrapy

class TestItem(scrapy.Item):
    id = scrapy.Field()
    name = scrapy.Field()
    description = scrapy.Field()
CrawlSpider
class scrapy.spiders.CrawlSpider[ソース]

これは、一連のルールを定義してリンクをたどる便利なメカニズムを提供するため、通常のWebサイトをクロールするために最も一般的に使用されるスパイダーです。 特定のWebサイトやプロジェクトには最適ではないかもしれませんが、いくつかのケースでは十分に汎用的であるため、このスパイダーから始めて、必要に応じてカスタム機能をオーバーライドしたり、独自のスパイダーを実装したりできます。

Spiderから継承された(指定必須の)属性以外に、このclassは新しい属性をサポートします。:

rules

これは、1つ(または複数)の Rule オブジェクトのリストです。 各 Rule サイトをクロールするための特定の動作を定義します。 規則オブジェクトについては以下で説明します。 複数の規則が同じリンクに一致する場合、この属性で定義されている順序に従って、一致する最初の規則が使用されます。

このスパイダーにはオーバーライド可能なメソッドもあります:

parse_start_url(response, **kwargs)[ソース]

このメソッドは、スパイダーの start_urls 属性の URL に対して生成されたレスポンスごとに呼び出されます。初期レスポンス群のパースを可能にし、 アイテム・オブジェクト または Request オブジェクトまたはそれらのいずれかを含む反復可能オブジェクト(iterable)を返さなければなりません。

クロール規則
class scrapy.spiders.Rule(link_extractor=None, callback=None, cb_kwargs=None, follow=None, process_links=None, process_request=None, errback=None)[ソース]

link_extractor は、クロールされた各ページからリンクを抽出する方法を定義する リンク抽出 オブジェクトです。生成された各リンクは、 Request オブジェクトを生成するために使用されます。このオブジェクトでは、meta 辞書(link_text キー)にリンクのテキストを含みます。省略した場合、引数なしで作成されたデフォルトのリンク抽出器が使用され、すべてのリンクを抽出します。

callback は、指定のリンク抽出器で抽出された各リンクに対して呼び出される呼び出し可能オブジェクト(callable)または文字列(この場合、その名前のスパイダー・オブジェクトのメソッドが使用されます)です。 このコールバックは Response を最初の引数として受け取り、単一のインスタンスまたは アイテム・オブジェクト の反復可能オブジェクト(iterable) そして/または Request オブジェクト(またはそのサブクラス)、のいずれかを返す必要があります。上記のように、受け取った Response オブジェクトには、その meta 辞書に Request を生成したリンクのテキストを含みます(link_text キー)。

cb_kwargs は、コールバック関数に渡されるキーワード引数を含む辞書です。

follow は、このルールで抽出された各レスポンスからリンクをたどるかどうかを指定するブール値です。 callback がNoneの場合、 follow のデフォルトは True になります。それ以外の場合、デフォルトは False になります。

process_links は呼び出し可能オブジェクト(callable)、または指定された link_extractor を使用して各レスポンスから抽出されたリンクのリストごとに呼び出される文字列(この場合、その名前のスパイダー・オブジェクトのメソッドが使用されます)です。これは主にフィルタリングの目的で使用されます。

process_request は、この規則によって抽出されたすべての Request に対して呼び出される呼び出し可能オブジェクト(callable)(または文字列、その場合はその名前のスパイダー・オブジェクトのメソッドが使用されます)です。 この呼び出し可能オブジェクト(callable)は、最初の引数としてリクエストを受け取り、2番目の引数としてリクエストの発信元である Response を受け取る必要があります。 Request オブジェクト、または None を返す必要があります(リクエストを除外するため)。

errback は、ルールによって生成されたリクエストの処理中に例外が発生した場合に呼び出される呼び出し可能オブジェクトまたは文字列(この場合、その名前のスパイダーオブジェクトのメソッドが使用されます)です。 最初のパラメータとして Twisted Failure インスタンスを受け取ります。

警告

内部実装のため、CrawlSpider ベースのスパイダーを作成するときは、新しいリクエストのコールバックを明示的に設定する必要があります。 そうしないと、予期しない動作が発生する可能性があります。

バージョン 2.0 で追加: errback パラメータ。

CrawlSpider例

では、規則を使用したCrawlSpiderの例を見てみましょう:

import scrapy
from scrapy.spiders import CrawlSpider, Rule
from scrapy.linkextractors import LinkExtractor

class MySpider(CrawlSpider):
    name = 'example.com'
    allowed_domains = ['example.com']
    start_urls = ['http://www.example.com']

    rules = (
        # Extract links matching 'category.php' (but not matching 'subsection.php')
        # and follow links from them (since no callback means follow=True by default).
        Rule(LinkExtractor(allow=('category\.php', ), deny=('subsection\.php', ))),

        # Extract links matching 'item.php' and parse them with the spider's method parse_item
        Rule(LinkExtractor(allow=('item\.php', )), callback='parse_item'),
    )

    def parse_item(self, response):
        self.logger.info('Hi, this is an item page! %s', response.url)
        item = scrapy.Item()
        item['id'] = response.xpath('//td[@id="item_id"]/text()').re(r'ID: (\d+)')
        item['name'] = response.xpath('//td[@id="item_name"]/text()').get()
        item['description'] = response.xpath('//td[@id="item_description"]/text()').get()
        item['link_text'] = response.meta['link_text']
        url = response.xpath('//td[@id="additional_data"]/@href').get()
        return response.follow(url, self.parse_additional_page, cb_kwargs=dict(item=item))

    def parse_additional_page(self, response, item):
        item['additional_data'] = response.xpath('//p[@id="additional_data"]/text()').get()
        return item

このスパイダーはexample.comのホームページのクロールを開始し、カテゴリ・リンクとアイテム・リンクを収集し、後者を parse_item メソッドでパースします。 各アイテムのレスポンスに対して、XPathを使用してHTMLからいくつかのデータを抽出し、 Item は抽出されたデータで満たされます。

XMLFeedSpider
class scrapy.spiders.XMLFeedSpider[ソース]

XMLFeedSpiderは、特定のノード名でXMLフィードを反復処理することにより、XMLフィードをパースするために設計されています。 イテレータは、「iternodes」、「xml」、および「html」から選択できます。 xml および html イテレータはパースするために一度DOM全体を生成します。そのため、パフォーマンス上の理由から iternodes イテレータを使用することをお勧めします。 ただし、不正なマークアップを使用したXMLを解析する場合は、イテレータとして html を使用すると便利です。

イテレータとタグ名を設定するには、以下のクラス属性を定義する必要があります:

iterator

使用するイテレータを定義する文字列。 以下のいずれかです:

  • 'iternodes' - 正規表現に基づく高速イテレータ

  • 'html' - Selector を使用するイテレータ。 これはDOM解析を使用し、すべてのDOMをメモリにロードする必要があることに注意してください。これは大きなフィードの場合に問題になる可能性があります。

  • 'xml' - Selector を使用するイテレータ。 これはDOM解析を使用し、すべてのDOMをメモリにロードする必要があることに注意してください。これは大きなフィードの場合に問題になる可能性があります。

デフォルトは 'iternodes' です。

itertag

反復するノード(または要素)の名前を表す文字列。例:

itertag = 'product'
namespaces

このスパイダーで処理されるドキュメントで利用可能な名前空間を定義する (prefix, uri) タプルのリスト。 prefixuri は、 register_namespace() メソッドを使用して名前空間を自動的に登録するために使用されます。

あなたは、それから、 itertag 属性に名前空間を持つノードを指定できます。

例:

class YourSpider(XMLFeedSpider):

    namespaces = [('n', 'http://www.sitemaps.org/schemas/sitemap/0.9')]
    itertag = 'n:url'
    # ...

これらの新しい属性とは別に、このスパイダーには以下のオーバーライド可能なメソッドもあります。:

adapt_response(response)[ソース]

スパイダー・ミドルウェアから到着するとすぐに、スパイダーがパース開始する前に、レスポンスを受信するメソッド。 パース前にレスポンス・ボディを変更するために使用できます。 このメソッドはレスポンスを受け取り、レスポンスを返します(同じ、または別のレスポンスになる可能性があります)。

parse_node(response, selector)[ソース]

このメソッドは、指定されたタグ名(itertag)に一致するノードに対して呼び出されます。 各ノードのレスポンス Selector を受け取ります。 このメソッドのオーバーライドは必須です。 そうしないと、このスパイダーは動作しません。 このメソッドは、 アイテム・オブジェクト または、 Request オブジェクト、またはそれらのいずれかを含む反復可能オブジェクト(iterable)のいずれかを返す必要があります。

process_results(response, results)[ソース]

このメソッドは、スパイダーによって返された各結果(アイテムまたはリクエスト)に対して呼び出され、結果をフレームワーク・コアに返す前に必要な最後の処理(アイテムIDの設定など)を実行することを目的としています。 結果のリストと、それらの結果を生成したレスポンスを受け取ります。 結果(アイテムまたはリクエスト)のリストを返す必要があります。

警告

内部実装のため、XMLFeedSpider ベースのスパイダーを作成するときは、新しいリクエストのコールバックを明示的に設定する必要があります。 そうしないと、予期しない動作が発生する可能性があります。

XMLFeedSpiderの例

これらのスパイダーは非常に使いやすいので、例を見てみましょう:

from scrapy.spiders import XMLFeedSpider
from myproject.items import TestItem

class MySpider(XMLFeedSpider):
    name = 'example.com'
    allowed_domains = ['example.com']
    start_urls = ['http://www.example.com/feed.xml']
    iterator = 'iternodes'  # This is actually unnecessary, since it's the default value
    itertag = 'item'

    def parse_node(self, response, node):
        self.logger.info('Hi, this is a <%s> node!: %s', self.itertag, ''.join(node.getall()))

        item = TestItem()
        item['id'] = node.xpath('@id').get()
        item['name'] = node.xpath('name').get()
        item['description'] = node.xpath('description').get()
        return item

私たちがここで行ったことは、基本的には、指定した start_urls からフィードをダウンロードし、それぞれの item タグを反復処理し、それらを出力し、いくつかのランダムなデータを Item に保存するスパイダーを作成することです。

CSVFeedSpider
class scrapy.spiders.CSVFeedSpider[ソース]

このスパイダーはXMLFeedSpiderに非常に似ていますが、ノードではなく行を反復処理する点が異なります。 各反復で呼び出されるメソッドは parse_row() です。

delimiter

CSVファイルの各フィールドを区切る文字(文字列)。デフォルトは ',' (カンマ)。

quotechar

CSVファイルの各フィールドを囲い込む文字(文字列)。デフォルトは '\"' (ダブルクォーテーション)。

headers

CSVファイルの列名のリスト。

parse_row(response, row)[ソース]

CSVファイルの、レスポンスと、提供された(または検出された)ヘッダー行ごとにキーを持つ、(各行を表す)辞書を受け取ります。 このスパイダーは、前処理および後処理のために adapt_response および process_results メソッドをオーバーライドする機会も与えます。

CSVFeedSpider例

いささか前の例に似ているけれども、 CSVFeedSpider を使用している例を見てみましょう:

from scrapy.spiders import CSVFeedSpider
from myproject.items import TestItem

class MySpider(CSVFeedSpider):
    name = 'example.com'
    allowed_domains = ['example.com']
    start_urls = ['http://www.example.com/feed.csv']
    delimiter = ';'
    quotechar = "'"
    headers = ['id', 'name', 'description']

    def parse_row(self, response, row):
        self.logger.info('Hi, this is a row!: %r', row)

        item = TestItem()
        item['id'] = row['id']
        item['name'] = row['name']
        item['description'] = row['description']
        return item
SitemapSpider
class scrapy.spiders.SitemapSpider[ソース]

SitemapSpiderでは、 Sitemaps を使用してURLを検出することにより、サイトをクロールできます。

ネストされたサイトマップをサポートし、 robots.txt からサイトマップのURLを検出します。

sitemap_urls

あなたがクロールしたいサイトマップのURLを指定するURLのリスト。

また、 あなたは robots.txt を指定することもできます。robots.txtは、サイトマップのURLをパースするために解析されます。

sitemap_rules

タプル (regex, callback) のリスト。その内訳は以下の通りです:

  • regex は、サイトマップから抽出するURLに一致する正規表現です。 regex は文字列またはコンパイル済みの正規表現オブジェクトのいずれかです。

  • callback は、正規表現に一致するURLの処理に使用するコールバックです。 callback は文字列(スパイダーメソッドの名前を示す)または呼び出し可能オブジェクト(callable)です。

例えば:

sitemap_rules = [('/product/', 'parse_product')]

順番に規則の適用を試み、一致する最初の規則のみが使用されます。

あなたがこの属性を省略すると、サイトマップで見つかったすべてのURLは parse コールバックで処理されます。

sitemap_follow

追跡すべきサイトマップの正規表現のリスト。 これは、他のサイトマップファイルを指す Sitemap index files を使用するサイト専用です。

デフォルトでは、すべてのサイトマップが追跡されます。

ある url の代替リンクをたどるかどうかを指定します。 これらは、同じ url ブロック内で渡される別の言語の同じWebサイトへのリンクです。

例えば:

<url>
    <loc>http://example.com/</loc>
    <xhtml:link rel="alternate" hreflang="de" href="http://example.com/de"/>
</url>

sitemap_alternate_links を設定すると、両方のURLが取得されます。 sitemap_alternate_links を無効にすると、 http://example.com/ のみが取得されます。

デフォルトでは sitemap_alternate_links は無効です。

sitemap_filter(entries)[ソース]

これは、属性に基づいてサイトマップ・エントリを選択するためにオーバーライドできるフィルター関数です。

例えば:

<url>
    <loc>http://example.com/</loc>
    <lastmod>2005-01-01</lastmod>
</url>

私たちは、日付で entries をフィルタリングする sitemap_filter 関数を定義できます:

from datetime import datetime
from scrapy.spiders import SitemapSpider

class FilteredSitemapSpider(SitemapSpider):
    name = 'filtered_sitemap_spider'
    allowed_domains = ['example.com']
    sitemap_urls = ['http://example.com/sitemap.xml']

    def sitemap_filter(self, entries):
        for entry in entries:
            date_time = datetime.strptime(entry['lastmod'], '%Y-%m-%d')
            if date_time.year >= 2005:
                yield entry

これにより、2005年以降に変更された entries のみが取得されます。

エントリは、サイトマップ・ドキュメントから抽出された辞書オブジェクトです。 通常、キーはタグ名で、値はその中のテキストです。

重要な注意 :

  • loc属性が必要なため、このタグのないエントリは破棄されます。

  • 代替リンクはキー alternate でリストに保存されます(sitemap_alternate_links 参照)

  • 名前空間が削除されるため、 {namespace}tagname という名前のlxmlタグは tagname のみになります。

あなたがこのメソッドを省略すると、サイトマップで見つかったすべてのエントリが処理され、他の属性とその設定を参照します。

SitemapSpider例

最も単純な例: parse コールバックを使用して、サイトマップを通じて検出されたすべてのURLを処理します:

from scrapy.spiders import SitemapSpider

class MySpider(SitemapSpider):
    sitemap_urls = ['http://www.example.com/sitemap.xml']

    def parse(self, response):
        pass # ... scrape item here ...

特定のコールバックでいくつかのURLを処理し、別個のコールバックでその他のURLを処理します:

from scrapy.spiders import SitemapSpider

class MySpider(SitemapSpider):
    sitemap_urls = ['http://www.example.com/sitemap.xml']
    sitemap_rules = [
        ('/product/', 'parse_product'),
        ('/category/', 'parse_category'),
    ]

    def parse_product(self, response):
        pass # ... scrape product ...

    def parse_category(self, response):
        pass # ... scrape category ...

robots.txt ファイルで定義されたサイトマップに従い、URLに /sitemap_shop が含まれるサイトマップのみを追跡します:

from scrapy.spiders import SitemapSpider

class MySpider(SitemapSpider):
    sitemap_urls = ['http://www.example.com/robots.txt']
    sitemap_rules = [
        ('/shop/', 'parse_shop'),
    ]
    sitemap_follow = ['/sitemap_shops']

    def parse_shop(self, response):
        pass # ... scrape shop here ...

SitemapSpiderとurlsの他のソースを組み合わせます:

from scrapy.spiders import SitemapSpider

class MySpider(SitemapSpider):
    sitemap_urls = ['http://www.example.com/robots.txt']
    sitemap_rules = [
        ('/shop/', 'parse_shop'),
    ]

    other_urls = ['http://www.example.com/about']

    def start_requests(self):
        requests = list(super(MySpider, self).start_requests())
        requests += [scrapy.Request(x, self.parse_other) for x in self.other_urls]
        return requests

    def parse_shop(self, response):
        pass # ... scrape shop here ...

    def parse_other(self, response):
        pass # ... scrape other here ...

セレクター

あなたがWebページをスクレイピングする場合、実行する必要がある最も一般的なタスクは、HTMLソースからデータを抽出することです。 これを実現するために利用可能ないくつかのライブラリがあります。:

  • BeautifulSoup は、Pythonプログラマーの間で非常に人気のあるWebスクレイピングライブラリであり、HTMLコードの構造に基づいてPythonオブジェクトを構築し、悪いマークアップも合理的に処理しますが、1つの欠点があります。遅いんです。

  • lxml は、 ElementTree に基づいたPython APIを備えたXMLパースライブラリ(HTMLもパースします)です。(lxmlはPython標準ライブラリの一部ではありません。)

Scrapyには、データを抽出するための独自のメカニズムが備わっています。 これらは、 XPath または CSS 式で指定されたHTMLドキュメントの特定の部分を「選択(select)」するため、セレクター(selector)と呼ばれます。

XPath は、XMLドキュメントでノードを選択するための言語であり、HTMLでも使用できます。 CSS は、HTMLドキュメントにスタイルを適用するための言語です。 これらのスタイルを特定のHTML要素に関連付けるセレクターを定義します。

注釈

Scrapyセレクターは、 parsel ライブラリの薄いラッパーです。 このラッパーの目的は、Scrapy Responseオブジェクトとの統合を改善することです。

parsel は、Scrapyなしで使用できるスタンドアロンのWebスクレイピングライブラリです。 内部で lxml ライブラリを使用し、lxml APIの上に簡単なAPIを実装します。 これは、Scrapyセレクターの速度と解析精度が、lxmlに非常に似ていることを意味します。

セレクターの使用

セレクターの構築

Responseオブジェクトは .selector 属性で Selector インスタンスを公開します:

>>> response.selector.xpath('//span/text()').get()
'good'

XPathとCSSを使用したレスポンスのクエリは非常によく使われるので、レスポンスにはさらに2つのショートカットが含まれます。 response.xpath()response.css() です:

>>> response.xpath('//span/text()').get()
'good'
>>> response.css('span::text').get()
'good'

Scrapy セレクターは Selector クラスのインスタンスであり、 TextResponse オブジェクトまたはマークアップを文字列( text 引数に)として渡すことによって構築されます。

通常は Scrapy セレクターを手動で構築する必要はありません。 response オブジェクトはスパイダーのコールバックで利用できるので、ほとんどの場合、 response.css()response.xpath() のショートカットを使うほうが便利です。 response.selector またはこれらのショートカットのいずれかを使用することで、レスポンスのボディが1回だけ解析されるようにすることもできます。

ただし、必要に応じて、セレクターを直接使用することができます。 テキストから構築する場合は以下です:

>>> from scrapy.selector import Selector
>>> body = '<html><body><span>good</span></body></html>'
>>> Selector(text=body).xpath('//span/text()').get()
'good'

レスポンスから構築する場合、 HtmlResponseTextResponse のサブクラスの1つです:

>>> from scrapy.selector import Selector
>>> from scrapy.http import HtmlResponse
>>> response = HtmlResponse(url='http://example.com', body=body)
>>> Selector(response=response).xpath('//span/text()').get()
'good'

セレクターは、入力タイプに基づいて最適なパース・ルール(XMLかHTML)を自動的に選択します。

セレクターの使用

セレクターの使用方法を説明するために、私たちは、「Scrapyシェル」(対話的なテストを提供します)とScrapyドキュメントサーバーにあるサンプルページを使用します。:

完全を期すために、完全なHTMLコードを次に示します。:

<html>
 <head>
  <base href='http://example.com/' />
  <title>Example website</title>
 </head>
 <body>
  <div id='images'>
   <a href='image1.html'>Name: My image 1 <br /><img src='image1_thumb.jpg' /></a>
   <a href='image2.html'>Name: My image 2 <br /><img src='image2_thumb.jpg' /></a>
   <a href='image3.html'>Name: My image 3 <br /><img src='image3_thumb.jpg' /></a>
   <a href='image4.html'>Name: My image 4 <br /><img src='image4_thumb.jpg' /></a>
   <a href='image5.html'>Name: My image 5 <br /><img src='image5_thumb.jpg' /></a>
  </div>
 </body>
</html>

まず、シェルを開きましょう。:

scrapy shell https://docs.scrapy.org/en/latest/_static/selectors-sample1.html

次に、シェルがロードされると、レスポンスが response シェル変数として使用可能になり、 response.selector 属性にそのセレクターが当てはめられます。

HTMLを扱っているため、セレクターは自動的にHTMLパーサーを使用します。

それでは、そのページの HTMLコード を見て、タイトルタグ内のテキストを選択するためのXPathを作成しましょう:

>>> response.xpath('//title/text()')
[<Selector xpath='//title/text()' data='Example website'>]

テキストデータを実際に抽出するには、次のようにセレクターの .get() または .getall() メソッドを呼び出す必要があります:

>>> response.xpath('//title/text()').getall()
['Example website']
>>> response.xpath('//title/text()').get()
'Example website'

.get() は常に単一の結果を返します。 複数の一致がある場合、最初の一致のコンテンツが返されます。 一致するものがない場合はNoneが返されます。 .getall() はすべての結果を含むリストを返します。

CSSセレクターは、CSS3疑似要素を使用してテキストまたは属性ノードを選択できることに注意してください:

>>> response.css('title::text').get()
'Example website'

あなたがご覧のとおり、 .xpath().css() メソッドは SelectorList のインスタンスを返します。これは新しいセレクターのリストです。 このAPIは、ネストされたデータをすばやく選択するために使用できます:

>>> response.css('img').xpath('@src').getall()
['image1_thumb.jpg',
 'image2_thumb.jpg',
 'image3_thumb.jpg',
 'image4_thumb.jpg',
 'image5_thumb.jpg']

あなたが最初に一致した要素のみを抽出したい場合は、セレクターの .get() (または以前のScrapyバージョンで一般的に使用されていたエイリアス .extract_first() )を呼び出すことができます:

>>> response.xpath('//div[@id="images"]/a/text()').get()
'Name: My image 1 '

要素が見つからなかった場合は None を返します:

>>> response.xpath('//div[@id="not-exists"]/text()').get() is None
True

None の代わりに使用されるデフォルトの戻り値を引数として提供できます。:

>>> response.xpath('//div[@id="not-exists"]/text()').get(default='not-found')
'not-found'

例えば '@src' のようなXPathを使用する代わりに、 Selector.attrib プロパティを使用して属性を問い合わせることができます:

>>> [img.attrib['src'] for img in response.css('img')]
['image1_thumb.jpg',
 'image2_thumb.jpg',
 'image3_thumb.jpg',
 'image4_thumb.jpg',
 'image5_thumb.jpg']

ショートカットとして、 .attrib はSelectorListでも直接利用できます。 最初に一致する要素の属性を返します:

>>> response.css('img').attrib['src']
'image1_thumb.jpg'

これは、単一の結果のみが予想される場合に最も役立ちます。例えばIDで選択する場合、またはWebページ上の一意の要素を選択する場合:

>>> response.css('base').attrib['href']
'http://example.com/'

今や、私たちは、ベースURLといくつかの画像リンクを取得します:

>>> response.xpath('//base/@href').get()
'http://example.com/'
>>> response.css('base::attr(href)').get()
'http://example.com/'
>>> response.css('base').attrib['href']
'http://example.com/'
>>> response.xpath('//a[contains(@href, "image")]/@href').getall()
['image1.html',
 'image2.html',
 'image3.html',
 'image4.html',
 'image5.html']
>>> response.css('a[href*=image]::attr(href)').getall()
['image1.html',
 'image2.html',
 'image3.html',
 'image4.html',
 'image5.html']
>>> response.xpath('//a[contains(@href, "image")]/img/@src').getall()
['image1_thumb.jpg',
 'image2_thumb.jpg',
 'image3_thumb.jpg',
 'image4_thumb.jpg',
 'image5_thumb.jpg']
>>> response.css('a[href*=image] img::attr(src)').getall()
['image1_thumb.jpg',
 'image2_thumb.jpg',
 'image3_thumb.jpg',
 'image4_thumb.jpg',
 'image5_thumb.jpg']
CSSセレクターの拡張機能

W3C標準では、 CSS selectors はテキストノードまたは属性値の選択をサポートしていません。 しかし、これらを選択することは、Webスクレイピングコンテキストでは非常に重要であるため、Scrapy(parsel)はいくつかの 非標準の擬似要素 を実装しています。:

  • テキストノードを選択するには ::text を使用します

  • 属性値を選択するには ::attr(name) を使用します。 name は、あなたが値を取得したい属性の名前です

警告

これらの擬似要素はScrapy/Parsel固有です。 ほとんどの場合、 lxmlPyQuery などの他のライブラリでは動作しません。

例:

  • title::text<title> の子孫のテキストノードを選択します:

>>> response.css('title::text').get()
'Example website'
  • *::text は、現在のセレクターコンテキストの全ての子孫テキストノードを選択します:

>>> response.css('#images *::text').getall()
['\n   ',
 'Name: My image 1 ',
 '\n   ',
 'Name: My image 2 ',
 '\n   ',
 'Name: My image 3 ',
 '\n   ',
 'Name: My image 4 ',
 '\n   ',
 'Name: My image 5 ',
 '\n  ']
  • foo::text は、 foo 要素が存在するが、テキストを含まない場合(つまり、テキストが空の場合)の場合、結果を返しません:

>>> response.css('img::text').getall()
[]

つまり、 .css('foo::text').get() は、要素が存在する場合でもNoneを返す可能性があることを意味します。 常に文字列が必要な場合は default='' 引数を使用してください:

>>> response.css('img::text').get()
>>> response.css('img::text').get(default='')
''
  • a::attr(href) は、リンクにぶら下がってる href 属性値を選択します:

>>> response.css('a::attr(href)').getall()
['image1.html',
 'image2.html',
 'image3.html',
 'image4.html',
 'image5.html']

注釈

要素属性の選択 も参照下さい。

注釈

あなたは、これらの擬似要素をチェインさせることはできません。 ただし、実際にはあまり意味がありません。テキストノードには属性がなく、属性値は既に文字列値であり、子ノードはありません。

セレクターを入れ子にする

選択メソッド(.xpath() または .css())は同じタイプのセレクターのリストを返すため、これらのセレクターの選択メソッドも呼び出すことができます。 以下に例を示します:

>>> links = response.xpath('//a[contains(@href, "image")]')
>>> links.getall()
['<a href="image1.html">Name: My image 1 <br><img src="image1_thumb.jpg"></a>',
 '<a href="image2.html">Name: My image 2 <br><img src="image2_thumb.jpg"></a>',
 '<a href="image3.html">Name: My image 3 <br><img src="image3_thumb.jpg"></a>',
 '<a href="image4.html">Name: My image 4 <br><img src="image4_thumb.jpg"></a>',
 '<a href="image5.html">Name: My image 5 <br><img src="image5_thumb.jpg"></a>']
>>> for index, link in enumerate(links):
...     href_xpath = link.xpath('@href').get()
...     img_xpath = link.xpath('img/@src').get()
...     print(f'Link number {index} points to url {href_xpath!r} and image {img_xpath!r}')
Link number 0 points to url 'image1.html' and image 'image1_thumb.jpg'
Link number 1 points to url 'image2.html' and image 'image2_thumb.jpg'
Link number 2 points to url 'image3.html' and image 'image3_thumb.jpg'
Link number 3 points to url 'image4.html' and image 'image4_thumb.jpg'
Link number 4 points to url 'image5.html' and image 'image5_thumb.jpg'
要素属性の選択

属性の値を取得する方法はいくつかあります。 まず、XPath構文を使用できます:

>>> response.xpath("//a/@href").getall()
['image1.html', 'image2.html', 'image3.html', 'image4.html', 'image5.html']

XPath構文にはいくつかの利点があります。これは標準のXPath機能であり、 @attributes はXPath式の他の部分で使用できます。 属性値でフィルタリングすることが可能です。

Scrapyは、属性値を取得できるCSSセレクター(::attr(...))の拡張機能も提供します:

>>> response.css('a::attr(href)').getall()
['image1.html', 'image2.html', 'image3.html', 'image4.html', 'image5.html']

それに加えて、Selectorの .attrib プロパティがあります。 XPathまたはCSS拡張機能を使用せずに、Pythonコードで属性を検索する場合に使用できます:

>>> [a.attrib['href'] for a in response.css('a')]
['image1.html', 'image2.html', 'image3.html', 'image4.html', 'image5.html']

このプロパティはSelectorListでも使用できます。 最初に一致した要素の属性を持つ辞書を返します。 セレクターが単一の結果を返すと予想される場合(たとえば、要素IDで選択する場合、またはページ上の一意の要素を選択する場合)に使用すると便利です:

>>> response.css('base').attrib
{'href': 'http://example.com/'}
>>> response.css('base').attrib['href']
'http://example.com/'

空のSelectorListの .attrib プロパティは空です:

>>> response.css('foo').attrib
{}
セレクターで正規表現を使う

Selector には、正規表現を使用してデータを抽出する .re() メソッドもあります。 ただし、 .xpath() または .css() メソッドを使用するのとは異なり、 .re() は文字列のリストを返します。 したがって、ネストした .re() 呼び出しを構築することはできません。

上記の HTMLコード から画像名を抽出する例を次に示します:

>>> response.xpath('//a[contains(@href, "image")]/text()').re(r'Name:\s*(.*)')
['My image 1',
 'My image 2',
 'My image 3',
 'My image 4',
 'My image 5']

.re() のために .get() (およびそのエイリアス .extract_first())に対応する追加のヘルパーがあり、名前は .re_first() です。 これを使用して、最初に一致する文字列のみを抽出します:

>>> response.xpath('//a[contains(@href, "image")]/text()').re_first(r'Name:\s*(.*)')
'My image 1'
extract() と extract_first()

あなたが長年のScrapyユーザーなら、おそらく .extract().extract_first() セレクターメソッドに慣れているでしょう。 多くのブログ投稿とチュートリアルも同様にそれらを使用しています。 これらのメソッドはまだScrapyでサポートされており、それらを 非推奨にする計画はありません

けれども、Scrapyの使用法の文書は .get().getall() メソッドを使用して記述されるようになりました。 私たちは、これらの新しいメソッドは、より簡潔で読みやすいコードになると思います。

次の例は、これらのメソッドが互いにどのようにマッピングされるかを示しています。

  1. SelectorList.get()SelectorList.extract_first() と同じです:

    >>> response.css('a::attr(href)').get()
    'image1.html'
    >>> response.css('a::attr(href)').extract_first()
    'image1.html'
    
  2. SelectorList.getall()SelectorList.extract() と同じです:

    >>> response.css('a::attr(href)').getall()
    ['image1.html', 'image2.html', 'image3.html', 'image4.html', 'image5.html']
    >>> response.css('a::attr(href)').extract()
    ['image1.html', 'image2.html', 'image3.html', 'image4.html', 'image5.html']
    
  3. Selector.get()Selector.extract() と同じです:

    >>> response.css('a::attr(href)')[0].get()
    'image1.html'
    >>> response.css('a::attr(href)')[0].extract()
    'image1.html'
    
  4. 一貫性のために、リストを返す Selector.getall() もあります:

    >>> response.css('a::attr(href)')[0].getall()
    ['image1.html']
    

したがって、主な違いは、.get().getall() メソッドの出力はより予測可能なことです。 .get()``は常に単一の結果、 ``.getall() は常に抽出されたすべての結果のリストを返します。 .extract() メソッドでは、結果がリストであるかどうかは必ずしも明らかではありませんでした。 単一の結果を得るには、 .extract() または .extract_first() を呼び出す必要があります。

XPathsで作業する

ScrapyセレクターでXPathを効果的に使用するのに役立つヒントをいくつか紹介します。 XPathにまだ慣れていない場合は、まず、 XPath tutorial をご覧ください。

注釈

いくつかのヒントは this post from Zyte's blog に基づいています。

相対XPathで作業する

セレクターをネストし、/ で始まるXPathを使用する場合、そのXPathはドキュメントの絶対パスであり、呼び出し元のセレクターに対して相対的ではないことに注意してください。

たとえば、 <div> 要素内のすべての <p> 要素を抽出するとします。最初に、すべての <div> 要素を取得します:

>>> divs = response.xpath('//div')

最初は、以下のアプローチを使用したくなるかもしれませんが、実際には <div> 要素内の要素だけでなく、ドキュメント内すべての <p> 要素を抽出するため、間違っています:

>>> for p in divs.xpath('//p'):  # this is wrong - gets all <p> from the whole document
...     print(p.get())

以下が適切な方法です( .//p XPath のように先頭にドットが付いていることに注意してください):

>>> for p in divs.xpath('.//p'):  # extracts all <p> inside
...     print(p.get())

もう一つの一般的なやり方は、すべての子 <p> を直接抽出することです:

>>> for p in divs.xpath('p'):
...     print(p.get())

相対XPathの詳細については、XPath仕様の Location Paths 節を参照してください。

クラスによってクエリーする場合、CSSの使用を検討してください

要素には複数のCSSクラスを含めることができるため、クラスごとに要素を選択するXPathの方法はかなり冗長です:

*[contains(concat(' ', normalize-space(@class), ' '), ' someclass ')]

あなたが @class='someclass' を使用すると、他のクラスを持つ要素が欠落する可能性があります。それを補うために、単に contains(@class, 'someclass') を使用すると、文字列 someclass を共有する別のクラス名がある場合、より多くの要素が必要になる可能性があります。

この場合、Scrapyセレクターを使用するとセレクターをチェインできるため、ほとんどの場合、CSSを使用してクラスごとに選択し、それから必要に応じてXPathに切り替えることができます:

>>> from scrapy import Selector
>>> sel = Selector(text='<div class="hero shout"><time datetime="2014-07-23 19:00">Special date</time></div>')
>>> sel.css('.shout').xpath('./time/@datetime').getall()
['2014-07-23 19:00']

これは、上記の詳細なXPathトリックを使用するよりもクリーンです。 後に続くXPath式で . を使用することを忘れないでください。

//node[1] と (//node)[1] の違いに注意してください

//node[1] は、それぞれの親(parents)の下で最初に発生するすべてのノードを選択します。

(//node)[1] ドキュメント内のすべてのノードを選択し、その最初のノードのみを取得します。

例:

>>> from scrapy import Selector
>>> sel = Selector(text="""
....:     <ul class="list">
....:         <li>1</li>
....:         <li>2</li>
....:         <li>3</li>
....:     </ul>
....:     <ul class="list">
....:         <li>4</li>
....:         <li>5</li>
....:         <li>6</li>
....:     </ul>""")
>>> xp = lambda x: sel.xpath(x).getall()

これは、<li> 要素の親(parent)である全ての要素の子としてある、<li> 要素達の最初のを取得します:

>>> xp("//li[1]")
['<li>1</li>', '<li>4</li>']

ドキュメント全体の <li> 要素の最初のものを返します:

>>> xp("(//li)[1]")
['<li>1</li>']

これは `` <ul> `` の子に `` <li> `` があるパターン全てが対象となり、それぞれでの最初の``<li>`` 要素を取得します:

>>> xp("//ul/li[1]")
['<li>1</li>', '<li>4</li>']

ドキュメント全体の、 <ul> の子に <li> があるパターン全てが対象となり、その中で、一番最初の <li> 要素を取得します:

>>> xp("(//ul/li)[1]")
['<li>1</li>']
条件によるテキストノードの使用

あなたがテキスト内容をXPath文字列関数(XPath string function)の引数として使用する必要がある場合、 .//text() の使用を避け、代わりに . のみを使用してください。

これは、.//text() 式が ノードセット -- テキスト要素のコレクション -- を生成するためです。 そして、ノードセットが文字列に変換されるとき、つまり、 contains() または starts-with() のような文字列関数への引数として渡されるとき、最初の要素のテキストのみが渡されます。

例:

>>> from scrapy import Selector
>>> sel = Selector(text='<a href="#">Click here to go to the <strong>Next Page</strong></a>')

ノードセット から文字列への変換:

>>> sel.xpath('//a//text()').getall() # take a peek at the node-set
['Click here to go to the ', 'Next Page']
>>> sel.xpath("string(//a[1]//text())").getall() # convert it to string
['Click here to go to the ']

ただし、文字列に変換された ノード は、それ自体のテキストとそのすべての子孫のテキストを一緒にします:

>>> sel.xpath("//a[1]").getall() # select the first node
['<a href="#">Click here to go to the <strong>Next Page</strong></a>']
>>> sel.xpath("string(//a[1])").getall() # convert it to string
['Click here to go to the Next Page']

したがって、 .//text() ノードセットを使用しても、この場合は何も選択されません:

>>> sel.xpath("//a[contains(.//text(), 'Next Page')]").getall()
[]

しかし、ノードを意味するために . を使用すると、動作します:

>>> sel.xpath("//a[contains(., 'Next Page')]").getall()
['<a href="#">Click here to go to the <strong>Next Page</strong></a>']
XPath式の変数

XPathでは、 $somevariable 構文を使用して、XPath式の変数を参照できます。 これは、SQLの世界での、クエリの引数を ? のようなプレースホルダーに置き換え、クエリで渡された値で置換されるパラメータークエリまたはプリペアードステートメントに似ているところがあります。

"id" 属性値に基づいて、ハードコーディングせずに要素をマッチする例を次に示します(ハードコーディングする例は前述しました):

>>> # `$val` used in the expression, a `val` argument needs to be passed
>>> response.xpath('//div[@id=$val]/a/text()', val='images').get()
'Name: My image 1 '

別の例として、5つの子 <a> を含む <div> タグの "id" 属性を見つけます(ここでは整数として値 5 を渡します):

>>> response.xpath('//div[count(a)=$cnt]/@id', cnt=5).get()
'images'

.xpath() を呼び出すときは、すべての変数参照にバインディング値が必要です(そうでない場合は ValueError: XPath error: 例外が発生します)。これは、必要な数の名前付き引数を渡すことで実行されます。

Scapyセレクターを駆動するライブラリである parsel には、XPath変数(XPath variables)の詳細と例があります。

名前空間(namespace)の削除

スクレイピングプロジェクトを処理する場合、名前空間を完全に削除し、要素名を操作して、より単純で便利なXPathを作成すると非常に便利です。それには Selector.remove_namespaces() メソッドを使用できます。

Python Insider blog atom フィードでこれを説明する例を示しましょう。

まず、あなたがスクレイプしたいURLでシェルを開きます:

$ scrapy shell https://feeds.feedburner.com/PythonInsider

これがファイルの開始方法です:

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet ...
<feed xmlns="http://www.w3.org/2005/Atom"
      xmlns:openSearch="http://a9.com/-/spec/opensearchrss/1.0/"
      xmlns:blogger="http://schemas.google.com/blogger/2008"
      xmlns:georss="http://www.georss.org/georss"
      xmlns:gd="http://schemas.google.com/g/2005"
      xmlns:thr="http://purl.org/syndication/thread/1.0"
      xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0">
  ...

デフォルトの http://www.w3.org/2005/Atom と、 http://schemas.google.com/g/2005 の gd: プレフィックスを使用する別の宣言を含む、いくつかの名前空間宣言を確認できます。

シェルに入ったら、すべての <link> オブジェクトを選択して、機能しないことを確認できます(Atom XML名前空間がこれらのノードを難読化しているため):

>>> response.xpath("//link")
[]

しかし、一度、 Selector.remove_namespaces() メソッドを呼び出すと、すべてのノードに名前で直接アクセスできます:

>>> response.selector.remove_namespaces()
>>> response.xpath("//link")
[<Selector xpath='//link' data='<link rel="alternate" type="text/html" h'>,
    <Selector xpath='//link' data='<link rel="next" type="application/atom+'>,
    ...

あなたは、名前空間削除手順が手動になっていて、デフォルトで常に呼び出されるとは限らないのを疑問に思うかもしれません。これは2つの理由によるものです:

  1. 名前空間を削除するには、ドキュメント内のすべてのノードを反復して変更する必要があります。これは、Scrapyによってクロールされたすべてのドキュメントに対してデフォルトで実行するのにかなりコストのかかる操作です

  2. いくつかの要素名が名前空間間で衝突する場合、実際には名前空間を使用する必要がある場合があります。 ただし、これらのケースは非常にまれです。

EXSLT拡張機能の使用

lxml の上に構築されるScrapyセレクターは、いくつかの EXSLT 拡張をサポートし、XPath式で使用できる、事前登録されたこれらの名前空間が付属します:

プレフィックス

名前空間

使い方

re

http://exslt.org/regular-expressions

regular expressions 参照

set

http://exslt.org/sets

set manipulation 参照

正規表現

たとえば、 test() 関数は、XPathの starts-with() または contains() が十分でない場合に非常に便利です。

数字で終わるクラス属性を持つリスト項目内のリンクを選択する例:

>>> from scrapy import Selector
>>> doc = """
... <div>
...     <ul>
...         <li class="item-0"><a href="link1.html">first item</a></li>
...         <li class="item-1"><a href="link2.html">second item</a></li>
...         <li class="item-inactive"><a href="link3.html">third item</a></li>
...         <li class="item-1"><a href="link4.html">fourth item</a></li>
...         <li class="item-0"><a href="link5.html">fifth item</a></li>
...     </ul>
... </div>
... """
>>> sel = Selector(text=doc, type="html")
>>> sel.xpath('//li//@href').getall()
['link1.html', 'link2.html', 'link3.html', 'link4.html', 'link5.html']
>>> sel.xpath('//li[re:test(@class, "item-\d$")]//@href').getall()
['link1.html', 'link2.html', 'link4.html', 'link5.html']

警告

Cライブラリ libxslt はEXSLT正規表現をネイティブにサポートしていないため、 lxml の実装はPythonの re モジュールへのフックを使用します。 したがって、XPath式で正規表現関数を使用すると、パフォーマンスが若干低下する可能性があります。

組(set)の操作

これらは、たとえばテキスト要素を抽出する前にドキュメントツリーの一部を除外するのに便利です。

アイテムスコープのグループと対応するitempropを使用してmicrodata(http://schema.org/Productから取得したサンプルコンテンツ)を抽出する例:

>>> doc = """
... <div itemscope itemtype="http://schema.org/Product">
...   <span itemprop="name">Kenmore White 17" Microwave</span>
...   <img src="kenmore-microwave-17in.jpg" alt='Kenmore 17" Microwave' />
...   <div itemprop="aggregateRating"
...     itemscope itemtype="http://schema.org/AggregateRating">
...    Rated <span itemprop="ratingValue">3.5</span>/5
...    based on <span itemprop="reviewCount">11</span> customer reviews
...   </div>
...
...   <div itemprop="offers" itemscope itemtype="http://schema.org/Offer">
...     <span itemprop="price">$55.00</span>
...     <link itemprop="availability" href="http://schema.org/InStock" />In stock
...   </div>
...
...   Product description:
...   <span itemprop="description">0.7 cubic feet countertop microwave.
...   Has six preset cooking categories and convenience features like
...   Add-A-Minute and Child Lock.</span>
...
...   Customer reviews:
...
...   <div itemprop="review" itemscope itemtype="http://schema.org/Review">
...     <span itemprop="name">Not a happy camper</span> -
...     by <span itemprop="author">Ellie</span>,
...     <meta itemprop="datePublished" content="2011-04-01">April 1, 2011
...     <div itemprop="reviewRating" itemscope itemtype="http://schema.org/Rating">
...       <meta itemprop="worstRating" content = "1">
...       <span itemprop="ratingValue">1</span>/
...       <span itemprop="bestRating">5</span>stars
...     </div>
...     <span itemprop="description">The lamp burned out and now I have to replace
...     it. </span>
...   </div>
...
...   <div itemprop="review" itemscope itemtype="http://schema.org/Review">
...     <span itemprop="name">Value purchase</span> -
...     by <span itemprop="author">Lucas</span>,
...     <meta itemprop="datePublished" content="2011-03-25">March 25, 2011
...     <div itemprop="reviewRating" itemscope itemtype="http://schema.org/Rating">
...       <meta itemprop="worstRating" content = "1"/>
...       <span itemprop="ratingValue">4</span>/
...       <span itemprop="bestRating">5</span>stars
...     </div>
...     <span itemprop="description">Great microwave for the price. It is small and
...     fits in my apartment.</span>
...   </div>
...   ...
... </div>
... """
>>> sel = Selector(text=doc, type="html")
>>> for scope in sel.xpath('//div[@itemscope]'):
...     print("current scope:", scope.xpath('@itemtype').getall())
...     props = scope.xpath('''
...                 set:difference(./descendant::*/@itemprop,
...                                .//*[@itemscope]/*/@itemprop)''')
...     print(f"    properties: {props.getall()}")
...     print("")

current scope: ['http://schema.org/Product']
    properties: ['name', 'aggregateRating', 'offers', 'description', 'review', 'review']

current scope: ['http://schema.org/AggregateRating']
    properties: ['ratingValue', 'reviewCount']

current scope: ['http://schema.org/Offer']
    properties: ['price', 'availability']

current scope: ['http://schema.org/Review']
    properties: ['name', 'author', 'datePublished', 'reviewRating', 'description']

current scope: ['http://schema.org/Rating']
    properties: ['worstRating', 'ratingValue', 'bestRating']

current scope: ['http://schema.org/Review']
    properties: ['name', 'author', 'datePublished', 'reviewRating', 'description']

current scope: ['http://schema.org/Rating']
    properties: ['worstRating', 'ratingValue', 'bestRating']

ここでは、まず itemscope 要素を反復処理し、各要素について、すべての itemscope 要素を探し、別の itemscope 内にある要素を除外します。

その他のXPath拡張機能

Scrapyセレクターは、指定されたすべてのHTMLクラスを持つノードに対して True を返す、非常に間違ったXPath拡張関数 has-class も提供します。

次のHTMLの場合:

<p class="foo bar-baz">First</p>
<p class="foo">Second</p>
<p class="bar">Third</p>
<p>Fourth</p>

あなたは以下のように使用できます:

>>> response.xpath('//p[has-class("foo")]')
[<Selector xpath='//p[has-class("foo")]' data='<p class="foo bar-baz">First</p>'>,
 <Selector xpath='//p[has-class("foo")]' data='<p class="foo">Second</p>'>]
>>> response.xpath('//p[has-class("foo", "bar-baz")]')
[<Selector xpath='//p[has-class("foo", "bar-baz")]' data='<p class="foo bar-baz">First</p>'>]
>>> response.xpath('//p[has-class("foo", "bar")]')
[]

XPath //p[has-class("foo", "bar-baz")] は、CSS p.foo.bar-baz とほぼ同等です。 CSS探索はXPathに変換されてより効率的に実行されるのに対し、これは問題のすべてのノードに対して呼び出される純粋なPython関数であるため、ほとんどの場合は、CSSセレクターではありえないぐらい遅いことに注意してください。

また、Parselは、独自のXPath拡張機能の追加も簡単にします。

parsel.xpathfuncs.set_xpathfunc(fname, func)[ソース]

XPath式で使用するカスタム拡張機能を登録します。

fname 識別子の下に登録された関数 func は、一致するすべてのノードに対して呼び出され、 context パラメーターだけでなく、対応するXPath式から渡されたパラメーターが渡されます。

funcNone の場合、拡張関数は削除されます。

詳細は in lxml documentation を参照してください。

組み込みセレクター・リファレンス

セレクター・オブジェクト
class scrapy.selector.Selector(*args, **kwargs)[ソース]

Selector のインスタンスは、コンテンツの特定の部分を選択するためのレスポンスのラッパーです。

responseHtmlResponse または XmlResponse オブジェクトで、データの選択と抽出に使用されます。

textresponse が利用できない場合のためのUnicode文字列またはutf-8エンコードされたテキストです。 textresponse を一緒に使用することは未定義の動作です。

type はセレクターのタイプを定義します。これは "html" または "xml" または None (デフォルト)です。

typeNone の場合、セレクターは response タイプ(下記参照)に基づいて最適なタイプを自動的に選択するか、 text と一緒に使用される場合はデフォルトで "html" になります。

type の内容が None である response が渡された場合、セレクタータイプは応答タイプから次のように推測されます:

それ以外の場合、 type が設定されていると、セレクターのタイプは強制され、検出は行われません。

xpath(query, namespaces=None, **kwargs)[ソース]

xpath query に一致するノードを見つけ、すべての要素がフラット化された SelectorList インスタンスとして結果を返します。 リスト要素は Selector インターフェースも実装しています。

query は、適用するXPATHクエリを含む文字列です。

namespaces はオプションの prefix: namespace-uri マッピング(辞書)であり、これは register_namespace(prefix, uri) で登録されたプレフィックスに追加されます。 register_namespace() とは逆に、これらのプレフィックスは将来の呼び出しのために保存されません。

任意の追加の名前付き引数を使用して、XPath式内のXPath変数の値を渡すことができます。例:

selector.xpath('//a[href=$url]', url="http://www.example.com")

注釈

便宜上、このメソッドは response.xpath() として呼び出すことができます

css(query)[ソース]

指定のCSSセレクターを適用し、 SelectorList インスタンスを返します。

query は、適用するCSSセレクターを含む文字列です。

バックグラウンドで、CSSクエリは cssselect ライブラリを使用してXPathクエリに変換され、 .xpath() メソッドを実行します。

注釈

便宜上、このメソッドは response.css() として呼び出すことができます

get()[ソース]

単一のUnicode文字列で一致したノードをシリアル化して返します。 パーセント文字でエンコードされたコンテンツは引用符で囲まれていません。

extract() と extract_first() も参照下さい。

attrib

基になる要素の属性辞書を返します。

要素属性の選択 も参照下さい。

re(regex, replace_entities=True)[ソース]

与えられた正規表現を適用し、一致するUnicode文字列のリストを返します。

regex は、コンパイル済みの正規表現、または re.compile(regex) を使用して正規表現にコンパイルされる文字列のいずれかです。

デフォルトでは、文字エンティティ参照は対応する文字に置き換えられます(&amp;&lt; を除く)。 replace_entitiesFalse にして渡すと、これらの置換がオフになります。

re_first(regex, default=None, replace_entities=True)[ソース]

与えられた正規表現を適用し、一致する最初のUnicode文字列を返します。 一致するものがない場合、デフォルト値を返します(引数が指定されていない場合は None )。

デフォルトでは、文字エンティティ参照は対応する文字に置き換えられます(&amp;&lt; を除く)。 replace_entitiesFalse にして渡すと、これらの置換がオフになります。

register_namespace(prefix, uri)[ソース]

この Selector で使用する、与えられた名前空間を登録します。 名前空間を登録しないと、非標準の名前空間からデータを選択または抽出できません。 XMLレスポンスでのSelector例 を参照してください。

remove_namespaces()[ソース]

すべての名前空間を削除し、名前空間のないxpathを使用してドキュメントを走査できるようにします。 名前空間(namespace)の削除 を参照してください。

__bool__()[ソース]

実際のコンテンツが選択されている場合は True を返し、そうでない場合は False を返します。 言い換えれば、 Selector のブール値は、選択するコンテンツによって与えられます。

getall()[ソース]

ユニコード文字列の1要素リストで一致したノードをシリアル化して返します。

このメソッドは、一貫性のためにセレクターに追加されます。 SelectorListの方が便利です。 extract() と extract_first() 参照。

SelectorListオブジェクト
class scrapy.selector.SelectorList(iterable=(), /)[ソース]

SelectorList クラスは組み込みの list クラスのサブクラスであり、いくつかの追加メソッドを提供します。

xpath(xpath, namespaces=None, **kwargs)[ソース]

このリストの各要素に対して .xpath() メソッドを呼び出し、別の SelectorList としてフラット化された結果を返します。

querySelector.xpath() のそれと同じです

namespaces はオプションの prefix: namespace-uri マッピング(辞書)であり、これは register_namespace(prefix, uri) で登録されたプレフィックスに追加されます。 register_namespace() とは逆に、これらのプレフィックスは将来の呼び出しのために保存されません。

任意の追加の名前付き引数を使用して、XPath式内のXPath変数の値を渡すことができます。例:

selector.xpath('//a[href=$url]', url="http://www.example.com")
css(query)[ソース]

このリストの各要素に対して .css() メソッドを呼び出し、結果を別の SelectorList としてフラット化して返します。

querySelector.css() のそれと同じです

getall()[ソース]

このリストの各要素に対して .get() メソッドを呼び出し、その結果をユニコード文字列のリストとしてフラット化して返します。

extract() と extract_first() も参照下さい。

get(default=None)[ソース]

このリストの最初の要素に対して .get() の結果を返します。 リストが空の場合、デフォルト値を返します。

extract() と extract_first() も参照下さい。

re(regex, replace_entities=True)[ソース]

このリストの各要素に対して .re() メソッドを呼び出し、その結果をユニコード文字列のリストとしてフラット化して返します。

デフォルトでは、文字実体参照は対応する文字に置き換えられます(&amp;&lt; を除きます)。 replace_entitiesFalse として渡すと、これらの置き換えがオフになります。

re_first(regex, default=None, replace_entities=True)[ソース]

このリストの最初の要素に対して .re() メソッドを呼び出して、結果をUnicode文字列で返します。 リストが空であるか、正規表現が何とも一致しない場合、デフォルト値を返します(引数が指定されていない場合は None )。

デフォルトでは、文字実体参照は対応する文字に置き換えられます(&amp;&lt; を除きます)。 replace_entitiesFalse として渡すと、これらの置き換えがオフになります。

attrib

最初の要素の属性辞書を返します。 リストが空の場合、空の辞書を返します。

要素属性の選択 も参照下さい。

HTMLレスポンスのSelectorの例

ここで、いくつかの概念を説明するため Selector の例を示します。すべての場合において、このような HtmlResponse オブジェクトでインスタンス化された Selector が既に存在すると仮定します:

sel = Selector(html_response)
  1. HTMLレスポンス・ボディのすべての <h1> 要素を選択し、 Selector オブジェクトのリスト(つまり、 SelectorList オブジェクト)を返します:

    sel.xpath("//h1")
    
  2. HTMLレスポンス・ボディのすべての <h1> 要素のテキストを抽出し、文字列のリストを返します:

    sel.xpath("//h1").getall()         # this includes the h1 tag
    sel.xpath("//h1/text()").getall()  # this excludes the h1 tag
    
  3. すべての <p> タグを反復処理し、それらのクラス属性を出力します:

    for node in sel.xpath("//p"):
        print(node.attrib['class'])
    
XMLレスポンスでのSelector例

XmlResponse オブジェクトでインスタンス化された Selector オブジェクトの概念を説明するための例をいくつか示します:

sel = Selector(xml_response)
  1. XMLレスポンス・ボディのすべての <product> 要素を選択し、 Selector オブジェクトのリスト(つまり、 SelectorList オブジェクト)を返します:

    sel.xpath("//product")
    
  2. 名前空間の登録が必要な Google Base XML feed からすべての価格を抽出します:

    sel.register_namespace("g", "http://base.google.com/ns/1.0")
    sel.xpath("//g:price").getall()
    

アイテム

スクレイピングの主な目標は、非構造化ソース(通常はWebページ)から構造化データを抽出することです。 スパイダー は、抽出されたデータを アイテム 、つまりkey-valueペアを定義するPythonオブジェクトとして返す場合があります。

Scrapyは 複数のタイプのアイテム をサポートしています。 あなたがアイテムを作成したいときは、任意のタイプのアイテムを使用できます。 アイテムを受け取るコードを作成する場合、そのコードは 任意のアイテムタイプ で機能する必要があります。

アイテム型

Scrapyは、 itemadapter ライブラリを介して以下の型のアイテムをサポートします: 辞書Item オブジェクトdataclass オブジェクトattrs オブジェクト

辞書

アイテム型として辞書( dict )は便利でおなじみです。

Itemオブジェクト

Itemdict 風のAPIに加えて、アイテム型としての豊富な機能を提供します:

class scrapy.item.Item([arg])[ソース]

Item オブジェクトは、__init__ メッソドを含む標準の dict APIを複製(replicate)します。

Item ではフィールド名を定義できるため、以下のようになります:

  • KeyError は、未定義のフィールド名を使用すると発生(raise)します(つまり、タイプミスが見過ごされないようにします)

  • アイテム・エクスポーター は、最初にスクレイプされたオブジェクトにすべてのフィールドの値が揃ってない場合でも、デフォルト値をセットしてすべてのフィールドをエクスポートできます

Item はフィールド・メタ・データを定義することもできます。これは シリアライズのカスタマイズ に使用できます。

trackref は、 Item を追跡しメモリ・リークを見つけるのに役立ちます(see trackref を使用したメモリ・リークのデバッグ)。

Item オブジェクトは、以下の追加APIメンバーも提供します:

copy()
deepcopy()

このアイテムの deepcopy() を返す。

fields

読み込まれたフィールドだけでなく、このアイテムの すべての宣言済みフィールド を含む辞書。 キーはフィールド名で、値は アイテム宣言 で使用される Field オブジェクトです。

例:

from scrapy.item import Item, Field

class CustomItem(Item):
    one_field = Field()
    another_field = Field()
Dataclassオブジェクト

バージョン 2.2 で追加.

dataclass() を使用すると、フィールド名を使用してアイテム・クラスを定義できるため、 アイテム・エクスポーター は、最初にスクレイプされたオブジェクトにすべての値がない場合でも、デフォルトでそれらすべてのフィールドをエクスポートできます。

さらに、 dataclass アイテムは以下も可能にします:

これらは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 アイテムは以下も可能にします:

この型を使用するには、 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フィールドは、 dataclassattrs アイテムに対しても宣言できます。 詳細については、 dataclasses.fieldattr.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() 関数を使用することをお勧めします。

class itemadapter.ItemAdapter(item: Any)[ソース]

データ・コンテナ・オブジェクトと対話するラッパー・クラス。 オブジェクトの型を考慮せずにデータを抽出および設定するための共通のインターフェースを提供します。

itemadapter.is_item(obj: Any)bool[ソース]

指定されたオブジェクトがサポートされている型の1つに属している場合はTrueを返し、そうでない場合はFalseを返します。

ItemAdapter.is_item のエイリアス

アイテム・ローダー

アイテムローダーは、スクレイピングされた アイテム を生成するための便利なメカニズムを提供します。 アイテムは独自の辞書のようなAPIを使用して入力できますが、アイテムローダーは、生の抽出データを割り当てる前に解析するなどの一般的なタスクを自動化することにより、スクレイピングプロセスからアイテムを入力するための、はるかに便利なAPIを提供します。

言い換えると、 アイテム はスクレイピングされたデータの コンテナ を提供し、アイテム・ローダーはそのコンテナに 格納 するメカニズムを提供します。

アイテム・ローダーは、スパイダーまたはソース形式(HTML、XMLなど))によってさまざまなフィールド・パース・ルールを拡張およびオーバーライドするための柔軟で効率的かつ簡単なメカニズムを提供するように設計されています。

注釈

アイテム・ローダーは itemloaders ライブラリの拡張であり、 レスポンス へのサポートを追加して、Scrapyの操作をさらに簡単にします。

アイテムを格納するためにアイテム・ローダーを使う

アイテム・ローダーを使用するには、最初にインスタンス化する必要があります。 あなたは アイテム・オブジェクト を使用して、または使用せずにインスタンス化することができます。使用せずにインスタンス化する場合、アイテム・オブジェクト はアイテム・ローダーの __init__ メソッド内で、 ItemLoader.default_item_class 属性で指定された アイテム を使用して自動的に生成されます。

それから、通常は セレクター を使用して、あなたはアイテム・ローダーへの値の収集を開始します。 同じアイテム・フィールドに複数の値を追加できます。アイテム・ローダーは、適切な処理機能を使用して、それらの値を後で「結合」(join)する方法を知っています。

注釈

収集されたデータはリストとして内部に保存され、同じフィールドに複数の値を追加できます。 ローダーの作成時に item 引数が渡された場合、アイテムの各値は、既に反復可能(iterable)である場合はそのまま保存され、単一の値の場合はリストで包まれます。

以下は、 アイテムの章 で宣言された Product item を使用した、スパイダー 内での典型的なアイテム・ローダーの使用法です:

from scrapy.loader import ItemLoader
from myproject.items import Product

def parse(self, response):
    l = ItemLoader(item=Product(), response=response)
    l.add_xpath('name', '//div[@class="product_name"]')
    l.add_xpath('name', '//div[@class="product_title"]')
    l.add_xpath('price', '//p[@id="price"]')
    l.add_css('stock', 'p#stock]')
    l.add_value('last_updated', 'today') # you can also use literal values
    return l.load_item()

そのコードをざっと見ると、ページ内の2つの異なるXPathロケーションから name フィールドが抽出されていることがわかります:

  1. //div[@class="product_name"]

  2. //div[@class="product_title"]

いいかえると、データは、 add_xpath() メソッドを使用して、2つのXPathロケーションから抽出することで収集されます。 これは後で name フィールドに割り当てられるデータです。

その後、同様の呼び出しが price および stock フィールド(後者は add_css() メソッドでCSSセレクターを使用)に対して行われ、おわりに last_update フィールドは add_value() という別のメソッドを使用して、リテラル値( today )を直接入力します:

すべてのデータが収集されると、最後に、 ItemLoader.load_item() メソッドが呼び出され、実際に返されるのは、以前に add_xpath()add_css()add_value() の呼び出しで収集したデータを格納したアイテムです。

dataclassアイテムの操作

デフォルトでは、 dataclassアイテム では、作成時にすべてのフィールドを渡す必要があります。これは、アイテム・ローダーでdataclassアイテムを使用するときに問題になる可能性があります。アイテム・ローダーでは、事前入力されたアイテムがローダーに渡されない場合、各フィールドはローダーの add_xpath()add_css()add_value() メソッドを使用して段階的に入力されるためです。

これを克服するための1つのアプローチは、 default 引数を指定して field() 関数を使用してアイテムを定義することです。

from dataclasses import dataclass, field
from typing import Optional

@dataclass
class InventoryItem:
    name: Optional[str] = field(default=None)
    price: Optional[float] = field(default=None)
    stock: Optional[int] = field(default=None)

入力プロセッサと出力プロセッサ

アイテムローダーには、各(アイテム)フィールドごとに1つの入力プロセッサと1つの出力プロセッサが含まれます。入力プロセッサは、( add_xpath() または add_css() または add_value() メソッドを介して)受信したデータをすぐに処理し、入力プロセッサの結果が収集されてアイテム・ローダー内に保持されます。すべてのデータを収集した後、 ItemLoader.load_item() メソッドが呼び出されてデータを格納し、データが格納された アイテム・オブジェクト を取得します。その時点で、以前に収集された(および入力プロセッサを使用して処理された)データを使用して、出力プロセッサが呼び出されます。出力プロセッサの結果は、アイテムに割り当てられる最終値です。

(他の任意のフィールドにも同じことが当てはまりますが)とあるフィールドに対して入力プロセッサおよび出力プロセッサがどのように呼び出されるかを例で見てみましょう:

l = ItemLoader(Product(), some_selector)
l.add_xpath('name', xpath1) # (1)
l.add_xpath('name', xpath2) # (2)
l.add_css('name', css) # (3)
l.add_value('name', 'test') # (4)
return l.load_item() # (5)

以下のステップがあります:

  1. xpath1 からのデータが抽出され、 name フィールドの 入力プロセッサ を通過します。 入力プロセッサの結果が収集され、アイテムローダーに保持されます(ただし、アイテムにはまだ割り当てられていません)。

  2. xpath2 からのデータが抽出され、ステップ(1)で使用されたのと同じ 入力プロセッサ を通過します。 入力プロセッサの結果は、(存在する場合、)ステップ(1)で収集されたデータに追加されます。

  3. この場合は、データが css CSSセレクターから抽出され、ステップ(1)とステップ(2)で使用された同じ 入力プロセッサ を通過することを除いて、以前の場合と似ています。 入力プロセッサの結果は、(存在する場合、)ステップ(1)およびステップ(2)で収集されたデータに追加されます。

  4. この場合も以前の場合と似ていますが、XPath式またはCSSセレクターから抽出されるのではなく、収集される値が直接割り当てられる点が異なります。 ただし、値は引き続き入力プロセッサを介して渡されます。 この場合、値は反復可能ではなく(not iterable)、そして、入力プロセッサに常に反復可能要素を受け取るため(always receive iterables)、入力プロセッサに渡す前に単一の要素の反復可能要素に変換されます。

  5. ステップ(1)〜(4)で収集されたデータは、 name フィールドの 出力プロセッサ を介して渡されます。 出力プロセッサの結果は、アイテムの name フィールドに割り当てられた値です。

プロセッサは、パース対象のデータとともに呼び出され、パースされた値を返す、呼び出し可能なオブジェクトにすぎないことに注意してください。 したがって、任意の関数を入力または出力プロセッサとして使用できます。 唯一の要件は、反復可能(iterable)な1つの(そして1つだけの)位置引数を受け入れる必要があることです。

バージョン 2.0 で変更: プロセッサはもはやメソッドである必要はありません。

注釈

入力プロセッサと出力プロセッサは両方とも、イテレータを最初の引数として受け取る必要があります。 これらの関数の出力は何でもかまいません。 入力プロセッサの結果は、(そのフィールドのために)収集された値を含む(ローダー内の)内部リストに追加されます。出力プロセッサの結果は、最終的にアイテムに割り当てられる値です。

もう1つ注意する必要があるのは、入力プロセッサから返される値が内部(リスト)で収集され、出力プロセッサに渡されてフィールドに入力されることです。

なお、 itemloaders には便宜上いくつかの 一般的なプロセッサ が組み込まれています。

アイテム・ローダーの宣言

アイテム・ローダーは、クラス定義構文を使用して宣言されます。 以下に例を示します:

from itemloaders.processors import TakeFirst, MapCompose, Join
from scrapy.loader import ItemLoader

class ProductLoader(ItemLoader):

    default_output_processor = TakeFirst()

    name_in = MapCompose(str.title)
    name_out = Join()

    price_in = MapCompose(str.strip)

    # ...

ご覧のように、入力プロセッサは _in 接尾辞を使用して宣言され、出力プロセッサは _out 接尾辞を使用して宣言されています。 また、 ItemLoader.default_input_processorItemLoader.default_output_processor 属性を使用して、デフォルトの入出力プロセッサを宣言することもできます。

入力プロセッサと出力プロセッサの宣言

前述のとおり、入力プロセッサと出力プロセッサはアイテム・ローダー定義で宣言できます。この方法で入力プロセッサを宣言することは非常に一般的です。 ただし、使用する入力プロセッサと出力プロセッサを指定できる場所がもう1つあります。 アイテム・フィールド メタデータです。以下に例を示します:

import scrapy
from itemloaders.processors import Join, MapCompose, TakeFirst
from w3lib.html import remove_tags

def filter_price(value):
    if value.isdigit():
        return value

class Product(scrapy.Item):
    name = scrapy.Field(
        input_processor=MapCompose(remove_tags),
        output_processor=Join(),
    )
    price = scrapy.Field(
        input_processor=MapCompose(remove_tags, filter_price),
        output_processor=TakeFirst(),
    )
>>> from scrapy.loader import ItemLoader
>>> il = ItemLoader(item=Product())
>>> il.add_value('name', ['Welcome to my', '<strong>website</strong>'])
>>> il.add_value('price', ['&euro;', '<span>1000</span>'])
>>> il.load_item()
{'name': 'Welcome to my website', 'price': '1000'}

入力プロセッサと出力プロセッサの両方の優先順位は次のとおりです:

  1. アイテムローダーのフィールド固有の属性: field_in および field_out (最優先)

  2. フィールド・メタデータ(input_processoroutput_processor キー)

  3. アイテム・ローダー デフォルト: ItemLoader.default_input_processor()ItemLoader.default_output_processor() (最も低い優先度)

アイテムローダーの再利用と拡張 も参照下さい。

アイテム・ローダー・コンテキスト

アイテムローダーコンテキストは、アイテムローダーのすべての入力プロセッサおよび出力プロセッサ間で共有される任意のキー・値ペアの辞書です。アイテム・ローダーの宣言、インスタンス化、または使用時に渡すことができます。これらは、入出力プロセッサの動作を変更するために使用されます。

たとえば、テキスト値を受け取り、そこから長さを抽出する parse_length 関数があるとします:

def parse_length(text, loader_context):
    unit = loader_context.get('unit', 'm')
    # ... length parsing code goes here ...
    return parsed_length

loader_context 引数を受け入れることにより、プロセッサ関数はアイテム・ローダーがアイテム・ローダー・コンテキストを受け取ることができることを明示的に伝えています。そのため、アイテム・ローダーはプロセッサ関数呼び出し時に現在アクティブなコンテキストを渡します。よってプロセッサ関数(この場合 parse_length)は現在アクティブなコンテキストを使用できます。

アイテムローダーのコンテキスト値を変更する方法はいくつかあります:

  1. 現在アクティブなアイテム・ローダー・コンテキスト( context 属性)を変更する:

    loader = ItemLoader(product)
    loader.context['unit'] = 'cm'
    
  2. アイテム・ローダーのインスタンス化時(アイテムローダーの __init __ メソッドのキーワード引数はアイテム・ローダーのコンテキストに格納されます):

    loader = ItemLoader(product, unit='cm')
    
  3. アイテム・ローダーの宣言で、アイテム・ローダー・コンテキストを使用したインスタンス化をサポートする入出力プロセッサ用。 MapCompose はそれらの1つです:

    class ProductLoader(ItemLoader):
        length_out = MapCompose(parse_length, unit='cm')
    

ItemLoaderオブジェクト

class scrapy.loader.ItemLoader(item=None, selector=None, response=None, parent=None, **context)[ソース]

A user-friendly abstraction to populate an item with data by applying field processors to scraped data. When instantiated with a selector or a response it supports data extraction from web pages using selectors.

パラメータ

If no item is given, one is instantiated automatically using the class in default_item_class.

The item, selector, response and remaining keyword arguments are assigned to the Loader context (accessible through the context attribute).

item

The item object being parsed by this Item Loader. This is mostly used as a property so, when attempting to override this value, you may want to check out default_item_class first.

context

The currently active Context of this Item Loader.

default_item_class

An item class (or factory), used to instantiate items when not given in the __init__ method.

default_input_processor

The default input processor to use for those fields which don't specify one.

default_output_processor

The default output processor to use for those fields which don't specify one.

default_selector_class

The class used to construct the selector of this ItemLoader, if only a response is given in the __init__ method. If a selector is given in the __init__ method this attribute is ignored. This attribute is sometimes overridden in subclasses.

selector

The Selector object to extract data from. It's either the selector given in the __init__ method or one created from the response given in the __init__ method using the default_selector_class. This attribute is meant to be read-only.

add_css(field_name, css, *processors, **kw)[ソース]

Similar to ItemLoader.add_value() but receives a CSS selector instead of a value, which is used to extract a list of unicode strings from the selector associated with this ItemLoader.

See get_css() for kwargs.

パラメータ

css (str) -- the CSS selector to extract data from

Examples:

# HTML snippet: <p class="product-name">Color TV</p>
loader.add_css('name', 'p.product-name')
# HTML snippet: <p id="price">the price is $1200</p>
loader.add_css('price', 'p#price', re='the price is (.*)')
add_value(field_name, value, *processors, **kw)[ソース]

Process and then add the given value for the given field.

The value is first passed through get_value() by giving the processors and kwargs, and then passed through the field input processor and its result appended to the data collected for that field. If the field already contains collected data, the new data is added.

The given field_name can be None, in which case values for multiple fields may be added. And the processed value should be a dict with field_name mapped to values.

Examples:

loader.add_value('name', 'Color TV')
loader.add_value('colours', ['white', 'blue'])
loader.add_value('length', '100')
loader.add_value('name', 'name: foo', TakeFirst(), re='name: (.+)')
loader.add_value(None, {'name': 'foo', 'sex': 'male'})
add_xpath(field_name, xpath, *processors, **kw)[ソース]

Similar to ItemLoader.add_value() but receives an XPath instead of a value, which is used to extract a list of strings from the selector associated with this ItemLoader.

See get_xpath() for kwargs.

パラメータ

xpath (str) -- the XPath to extract data from

Examples:

# HTML snippet: <p class="product-name">Color TV</p>
loader.add_xpath('name', '//p[@class="product-name"]')
# HTML snippet: <p id="price">the price is $1200</p>
loader.add_xpath('price', '//p[@id="price"]', re='the price is (.*)')
get_collected_values(field_name)[ソース]

Return the collected values for the given field.

get_css(css, *processors, **kw)[ソース]

Similar to ItemLoader.get_value() but receives a CSS selector instead of a value, which is used to extract a list of unicode strings from the selector associated with this ItemLoader.

パラメータ
  • css (str) -- the CSS selector to extract data from

  • re (str or typing.Pattern) -- a regular expression to use for extracting data from the selected CSS region

Examples:

# HTML snippet: <p class="product-name">Color TV</p>
loader.get_css('p.product-name')
# HTML snippet: <p id="price">the price is $1200</p>
loader.get_css('p#price', TakeFirst(), re='the price is (.*)')
get_output_value(field_name)[ソース]

Return the collected values parsed using the output processor, for the given field. This method doesn't populate or modify the item at all.

get_value(value, *processors, **kw)[ソース]

Process the given value by the given processors and keyword arguments.

Available keyword arguments:

パラメータ

re (str or typing.Pattern) -- a regular expression to use for extracting data from the given value using extract_regex() method, applied before processors

Examples:

>>> from itemloaders import ItemLoader
>>> from itemloaders.processors import TakeFirst
>>> loader = ItemLoader()
>>> loader.get_value('name: foo', TakeFirst(), str.upper, re='name: (.+)')
'FOO'
get_xpath(xpath, *processors, **kw)[ソース]

Similar to ItemLoader.get_value() but receives an XPath instead of a value, which is used to extract a list of unicode strings from the selector associated with this ItemLoader.

パラメータ
  • xpath (str) -- the XPath to extract data from

  • re (str or typing.Pattern) -- a regular expression to use for extracting data from the selected XPath region

Examples:

# HTML snippet: <p class="product-name">Color TV</p>
loader.get_xpath('//p[@class="product-name"]')
# HTML snippet: <p id="price">the price is $1200</p>
loader.get_xpath('//p[@id="price"]', TakeFirst(), re='the price is (.*)')
load_item()[ソース]

Populate the item with the data collected so far, and return it. The data collected is first passed through the output processors to get the final value to assign to each item field.

nested_css(css, **context)[ソース]

Create a nested loader with a css selector. The supplied selector is applied relative to selector associated with this ItemLoader. The nested loader shares the item with the parent ItemLoader so calls to add_xpath(), add_value(), replace_value(), etc. will behave as expected.

nested_xpath(xpath, **context)[ソース]

Create a nested loader with an xpath selector. The supplied selector is applied relative to selector associated with this ItemLoader. The nested loader shares the item with the parent ItemLoader so calls to add_xpath(), add_value(), replace_value(), etc. will behave as expected.

replace_css(field_name, css, *processors, **kw)[ソース]

Similar to add_css() but replaces collected data instead of adding it.

replace_value(field_name, value, *processors, **kw)[ソース]

Similar to add_value() but replaces the collected data with the new value instead of adding it.

replace_xpath(field_name, xpath, *processors, **kw)[ソース]

Similar to add_xpath() but replaces collected data instead of adding it.

入れ子になったローダー

ドキュメントのサブセクションから関連する値をパースする場合、入れ子になったローダーを作成すると便利です。以下のようなページのフッターから詳細を抽出しているとします:

例:

<footer>
    <a class="social" href="https://facebook.com/whatever">Like Us</a>
    <a class="social" href="https://twitter.com/whatever">Follow Us</a>
    <a class="email" href="mailto:whatever@example.com">Email Us</a>
</footer>

入れ子になったローダーがない場合、あなたは抽出する値ごとに完全なxpath(またはcss)を指定する必要があります。

例:

loader = ItemLoader(item=Item())
# load stuff not in the footer
loader.add_xpath('social', '//footer/a[@class = "social"]/@href')
loader.add_xpath('email', '//footer/a[@class = "email"]/@href')
loader.load_item()

代わりに、あなたはフッター・セレクターを使用して入れ子になったローダーを作成し、フッターに関連する値を追加できます。機能は同じですが、あなたはフッター・セレクターの繰り返しを回避できます。

例:

loader = ItemLoader(item=Item())
# load stuff not in the footer
footer_loader = loader.nested_xpath('//footer')
footer_loader.add_xpath('social', 'a[@class = "social"]/@href')
footer_loader.add_xpath('email', 'a[@class = "email"]/@href')
# no need to call footer_loader.load_item()
loader.load_item()

あなたはローダーを任意に入れ子にでき、xpathまたはcssセレクターで動作します。 一般的なガイドラインとして、入れ子になったローダーを使用してコードを単純化します。入れ子にしないと、パーサーが読みにくくなる可能性があります。

アイテムローダーの再利用と拡張

あなたのプロジェクトが大きくなり、ますます多くのスパイダーを取得するにつれて、メンテナンスは根本的な問題になります。特に、各スパイダーの多くの異なるパースルールを処理する必要がある場合、多くの例外があります。また、共通のプロセッサを再利用したい場合も同様です。

アイテムローダーは、柔軟性を失うことなく、パースルールのメンテナンスの負担を軽減するように設計されていると同時に、それらを拡張およびオーバーライドするための便利なメカニズムを提供します。このため、アイテムローダーは、特定のスパイダー(またはスパイダーのグループ)の違いを処理するために、従来のPythonクラスの継承をサポートしています。

たとえば、ある特定のサイトが製品名を3つのダッシュ(たとえば ---Plasma TV--- )で囲んでおり、最終製品名でそれらのダッシュをスクレイピングしたくないと仮定します。

ここで、デフォルトの製品アイテムローダー( ProductLoader )を再利用して拡張することで、これらのダッシュを削除する方法を次に示します:

from itemloaders.processors import MapCompose
from myproject.ItemLoaders import ProductLoader

def strip_dashes(x):
    return x.strip('-')

class SiteSpecificLoader(ProductLoader):
    name_in = MapCompose(strip_dashes, ProductLoader.name_in)

アイテムローダーの拡張が非常に役立つ別のケースは、XMLやHTMLなどの複数のソース形式がある場合です。XMLバージョンでは、 CDATA の出現を削除することができます。方法の例を次に示します:

from itemloaders.processors import MapCompose
from myproject.ItemLoaders import ProductLoader
from myproject.utils.xml import remove_cdata

class XmlProductLoader(ProductLoader):
    name_in = MapCompose(remove_cdata, ProductLoader.name_in)

これは入力プロセッサを拡張する典型的な方法です。

出力プロセッサについては、フィールドメタデータで宣言する方が一般的です。これは、通常、(入力プロセッサのように)特定の各サイトのパースルールではなく、フィールドのみに依存するためです。 入力プロセッサと出力プロセッサの宣言 も参照してください。

アイテムローダーを拡張、継承、およびオーバーライドする方法は他にもたくさんあります。さまざまなアイテムローダーの階層は、さまざまなプロジェクトにより適しています。 Scrapyはメカニズムのみを提供します。 ローダーコレクションの特定の構成を強制することはありません。それはあなたとプロジェクトのニーズ次第です。

Scrapyシェル

Scrapyシェルは、スパイダーを実行することなく、非常に迅速にスクレイピングコードを試行およびデバッグできる対話型シェルです。これは、データ抽出コードのテストに使用することを目的としていますが、通常のPythonシェルでもあるため、実際にはあらゆる種類のコードのテストに使用できます。

シェルは、XPath式またはCSS式をテストし、それらがどのように機能するか、およびスクレイピングしようとしているWebページからどのようなデータを抽出するかを確認するために使用されます。すべての変更をテストするためにスパイダーを実行する必要なく、スパイダーを作成している間に式をインタラクティブにテストできます。

Scrapyシェルに親しむと、スパイダーを開発およびデバッグするための非常に素晴らしいツールであることがわかります。

シェルの構成(configure)

IPython がインストールされている場合、Scrapyシェルは(標準のPythonコンソールの代わりに)それを使用します。 IPython コンソールははるかに強力で、とりわけスマートなオートコンプリートとカラー化された出力を提供します。

特に、( IPython が優れている)Unixシステムで作業している場合は、 IPython をインストールすることを強くお勧めします。 詳細については、 IPython installation guide を参照してください。

Scrapyは bpython もサポートしており、 IPython が利用できない場合はそれを使用しようとします。

Scrapyの設定により、インストールされているかどうかに関係なく、 ipython または bpython または、標準の python シェルのいずれかを使用するように設定できます。 これには SCRAPY_PYTHON_SHELL 環境変数を設定するか、または scrapy.cfg で定義することにより行います。

[settings]
shell = bpython

シェルを起動する

Scrapyシェルを起動するには、次のように shell コマンドを使用します:

scrapy shell <url>

<url> は、あなたがスクレイプしたいURLです。

shell はローカルファイルでも機能します。 これは、Webページのローカルコピーで遊んでみたい場合に便利です。 shell はローカルファイルの次の構文を理解します:

# UNIX-style
scrapy shell ./path/to/file.html
scrapy shell ../other/path/to/file.html
scrapy shell /absolute/path/to/file.html

# File URI
scrapy shell file:///absolute/path/to/file.html

注釈

相対ファイルパスを使用する場合は、明示的に指定し、 ./ (または関連する場合は ../ )を先頭に追加します。 scrapy shell index.html はあなたの予想どおりに機能しません(これは設計によるものであり、バグではありません)。

なぜなら、 shell はファイルURIよりもHTTP URLを優先し、 index.html は構文的に example.com に似ているため、 shellindex.html をドメイン名とみなしてDNSルックアップし、エラーをトリガします:

$ scrapy shell index.html
[ ... scrapy shell starts ... ]
[ ... traceback ... ]
twisted.internet.error.DNSLookupError: DNS lookup failed:
address 'index.html' not found: [Errno -5] No address associated with hostname.

shellindex.html というファイルが現在のディレクトリに存在するかどうかを事前にテストしません。繰り返しますが、明示的に指定してください。

シェルの使用

Scrapyシェルは、全くもってPythonコンソール(または、使用可能な場合は IPython コンソール)です。そして、便利な追加のショートカット機能を提供します。

利用可能なショートカット
  • shelp() - 利用可能なオブジェクトとショートカットのリストを含むヘルプを出力します

  • fetch(url[, redirect=True]) - 指定されたURLから新しいリクエストを取得し、それに応じてすべての関連オブジェクトを更新します。 HTTP 3xxリダイレクトの後に redirect=False を渡さないようにオプションで要求できます

  • fetch(request) - 特定のリクエストから新しいレスポンスを取得し、それに応じてすべての関連オブジェクトを更新します。

  • view(response) - 検査のために、指定されたレスポンスをローカルWebブラウザーで開きます。 これにより、外部リンク(画像やスタイルシートなど)が正しく表示されるように、 <base> tag がレスポンス・ボディに追加されます。 ただし、これによりコンピューターに一時ファイルが作成され、自動的には削除されないことに注意してください。

利用可能なScrapyオブジェクト

Scrapyシェルは、ダウンロードしたページから、 Response オブジェクトや、(HTMLコンテンツとXMLコンテンツの両方のために) Selector オブジェクトなどの便利なオブジェクトを自動的に作成します。

それらのオブジェクトは次のとおりです:

  • crawler - 現在の Crawler オブジェクト。

  • spider - URLを処理することが知られているスパイダー、または現在のURL用にスパイダーが見つからない場合は Spider オブジェクト

  • request - 最後に取得したページの Request オブジェクト。 replace() を使用してこのリクエストを変更するか、 fetch ショートカットを使用して、(シェルを離れずに)新しいリクエストを取得できます。

  • response - 最後に取得したページを含む Response オブジェクト

  • settings - 現在の Scrapy設定

シェル セッション の例

ここで、 https://scrapy.org ページをスクレイピングすることから始めて、 次に、 https://old.reddit.com/ ページのスクレイピングに進む、典型的なシェルセッションの例を以下に示します。 そして最後に、(Reddit)リクエストメソッドをPOSTに変更し、エラーを取得して再フェッチします。セッションを終了するには、Ctrl-D(Unixシステムの場合)、WindowsではCtrl-Zを入力します。

これらのページは静的ではなく、テストするまでに変更されている可能性があるため、ここで抽出したデータは同じではない可能性があることに注意してください。 この例の唯一の目的は、Scrapyシェルの仕組みを理解してもらうことです。

まず、私たちはシェルを起動します:

scrapy shell 'https://scrapy.org' --nolog

注釈

コマンドラインから Scrapy シェルを実行するときは、常に URL を引用符で囲むことを忘れないでください。そうしないと、引数を含む URL (例えば & 文字を含むURL)が機能しません。

Windows では、代わりに二重引用符を使用してください:

scrapy shell "https://scrapy.org" --nolog

次に、シェルは(Scrapyダウンローダーを使用して)URLを取得し、使用可能なオブジェクトと便利なショートカットのリストを出力します(これらの行はすべて [s] 接頭辞で始まることがわかります):

[s] Available Scrapy objects:
[s]   scrapy     scrapy module (contains scrapy.Request, scrapy.Selector, etc)
[s]   crawler    <scrapy.crawler.Crawler object at 0x7f07395dd690>
[s]   item       {}
[s]   request    <GET https://scrapy.org>
[s]   response   <200 https://scrapy.org/>
[s]   settings   <scrapy.settings.Settings object at 0x7f07395dd710>
[s]   spider     <DefaultSpider 'default' at 0x7f0735891690>
[s] Useful shortcuts:
[s]   fetch(url[, redirect=True]) Fetch URL and update local objects (by default, redirects are followed)
[s]   fetch(req)                  Fetch a scrapy.Request and update local objects
[s]   shelp()           Shell help (print this help)
[s]   view(response)    View response in a browser

>>>

その後、オブジェクトで遊んでみましょう:

>>> response.xpath('//title/text()').get()
'Scrapy | A Fast and Powerful Scraping and Web Crawling Framework'
>>> fetch("https://old.reddit.com/")
>>> response.xpath('//title/text()').get()
'reddit: the front page of the internet'
>>> request = request.replace(method="POST")
>>> fetch(request)
>>> response.status
404
>>> from pprint import pprint
>>> pprint(response.headers)
{'Accept-Ranges': ['bytes'],
 'Cache-Control': ['max-age=0, must-revalidate'],
 'Content-Type': ['text/html; charset=UTF-8'],
 'Date': ['Thu, 08 Dec 2016 16:21:19 GMT'],
 'Server': ['snooserv'],
 'Set-Cookie': ['loid=KqNLou0V9SKMX4qb4n; Domain=reddit.com; Max-Age=63071999; Path=/; expires=Sat, 08-Dec-2018 16:21:19 GMT; secure',
                'loidcreated=2016-12-08T16%3A21%3A19.445Z; Domain=reddit.com; Max-Age=63071999; Path=/; expires=Sat, 08-Dec-2018 16:21:19 GMT; secure',
                'loid=vi0ZVe4NkxNWdlH7r7; Domain=reddit.com; Max-Age=63071999; Path=/; expires=Sat, 08-Dec-2018 16:21:19 GMT; secure',
                'loidcreated=2016-12-08T16%3A21%3A19.459Z; Domain=reddit.com; Max-Age=63071999; Path=/; expires=Sat, 08-Dec-2018 16:21:19 GMT; secure'],
 'Vary': ['accept-encoding'],
 'Via': ['1.1 varnish'],
 'X-Cache': ['MISS'],
 'X-Cache-Hits': ['0'],
 'X-Content-Type-Options': ['nosniff'],
 'X-Frame-Options': ['SAMEORIGIN'],
 'X-Moose': ['majestic'],
 'X-Served-By': ['cache-cdg8730-CDG'],
 'X-Timer': ['S1481214079.394283,VS0,VE159'],
 'X-Ua-Compatible': ['IE=edge'],
 'X-Xss-Protection': ['1; mode=block']}

スパイダーからシェルを呼び出してレスポンスを検査する

あなたが期待するレスポンスがそこに到達していることを確認するためだけに、スパイダーの特定のポイントで処理されているレスポンスを検査したい場合があります。

これは scrapy.shell.inspect_response 関数を使用することで実現できます。

スパイダーから呼び出す方法の例を次に示します:

import scrapy


class MySpider(scrapy.Spider):
    name = "myspider"
    start_urls = [
        "http://example.com",
        "http://example.org",
        "http://example.net",
    ]

    def parse(self, response):
        # We want to inspect one specific response.
        if ".org" in response.url:
            from scrapy.shell import inspect_response
            inspect_response(response, self)

        # Rest of parsing code.

スパイダーを実行すると、次のようなものが得られます:

2014-01-23 17:48:31-0400 [scrapy.core.engine] DEBUG: Crawled (200) <GET http://example.com> (referer: None)
2014-01-23 17:48:31-0400 [scrapy.core.engine] DEBUG: Crawled (200) <GET http://example.org> (referer: None)
[s] Available Scrapy objects:
[s]   crawler    <scrapy.crawler.Crawler object at 0x1e16b50>
...

>>> response.url
'http://example.org'

そこから、抽出コードが機能しているかどうかを確認できます:

>>> response.xpath('//h1[@class="fn"]')
[]

Orz。期待したとおりではありません。 したがって、あなたはWebブラウザーでレスポンスを開き、それが期待したレスポンスかどうかを確認できます:

>>> view(response)
True

最後に、Ctrl-D(WindowsではCtrl-Z)を押してシェルを終了し、クロールを再開します:

>>> ^D
2014-01-23 17:50:03-0400 [scrapy.core.engine] DEBUG: Crawled (200) <GET http://example.net> (referer: None)
...

Scrapyエンジンはシェルによってブロックされているため、ここでは fetch ショートカットを使用できないことに注意してください。 ただし、上記のように、シェルを離れた後、スパイダーは停止した場所からクロールを続けます。

アイテム・パイプライン

アイテムがスパイダーによってスクレイプされた後、アイテムはアイテム・パイプラインに送信され、アイテム・パイプラインは順次実行される複数のコンポーネントを介してアイテムを処理します。

各アイテム・パイプライン・コンポーネント(アイテム・パイプラインとも呼ばれる)は、単純なメソッドを実装するPythonクラスです。 それらはアイテムを受け取り、それに対してアクションを実行します。また、そのアイテムがパイプラインで処理を継続されるか、そのアイテムをドロップして処理しなくなくなるかを決定します。

アイテムパイプラインの一般的な用途は次のとおりです:

  • HTMLデータの洗浄(cleansing)

  • スクレイプしたグデータの検証(アイテムに特定のフィールドが含まれていることを確認)

  • 重複のチェック(そして重複分をドロップする)

  • スクレイプされたアイテムをデータベースに保存する

あなた独自のアイテム・パイプラインを書く

各アイテム・パイプライン・コンポーネントは、Pythonクラスであり、次のメソッドを実装する必要があります:

process_item(self, item, spider)

このメソッドは、すべてのアイテム・パイプライン・コンポーネントに対して呼び出されます。

itemアイテム・オブジェクト です。 全アイテム型のサポート 参照。

process_item() は、 アイテム・オブジェクト を返すか、あるいは Deferred を返すか、 あるいは DropItem 例外を発生させるかの、いずれかである必要があります。

ドロップされたアイテムは、それ以降のパイプライン・コンポーネントには処理されません。

パラメータ
  • item (item object) -- スクレイプされたアイテム

  • spider (Spider object) -- アイテムをスクレイプしたスパイダー

さらに、以下のメソッドも実装できます:

open_spider(self, spider)

このメソッドは、スパイダーがオープンされたときに呼び出されます。

パラメータ

spider (Spider object) -- オープンされたスパイダー

close_spider(self, spider)

このメソッドはスパイダーがクローズされたときに呼び出されます。

パラメータ

spider (Spider object) -- クローズされたスパイダー

from_crawler(cls, crawler)

存在する場合、このクラスメソッドは、 Crawler からパイプライ・ンインスタンスを作成するために呼び出されます。パイプラインの新しいインスタンスを返す必要があります。クローラー・オブジェクトは、設定やシグナルなどのすべてのScrapyコアコンポーネントへのアクセスを提供します。 つまり、それはパイプラインがそれらにアクセスし、その機能をScrapyにフックする方法です。

パラメータ

crawler (Crawler object) -- このパイプラインを使用するクローラー

アイテム・パイプライン例

価格の検証と価格のないアイテムのドロップ

VAT(訳注:付加価値税)を含まないアイテムの価格( price_excludes_vat 属性)を調整し、価格を含まないアイテムをドロップする、次の仮想パイプラインを見てみましょう:

from itemadapter import ItemAdapter
from scrapy.exceptions import DropItem
class PricePipeline:

    vat_factor = 1.15

    def process_item(self, item, spider):
        adapter = ItemAdapter(item)
        if adapter.get('price'):
            if adapter.get('price_excludes_vat'):
                adapter['price'] = adapter['price'] * self.vat_factor
            return item
        else:
            raise DropItem(f"Missing price in {item}")
JSONファイルにアイテムを書き込む

次のパイプラインは、(すべてのスパイダーからの)すべてのスクレイプされたアイテムを、JSON形式でシリアル化された行ごとに1つのアイテムを含む単一の items.jl ファイルに保存します:

import json

from itemadapter import ItemAdapter

class JsonWriterPipeline:

    def open_spider(self, spider):
        self.file = open('items.jl', 'w')

    def close_spider(self, spider):
        self.file.close()

    def process_item(self, item, spider):
        line = json.dumps(ItemAdapter(item).asdict()) + "\n"
        self.file.write(line)
        return item

注釈

JsonWriterPipelineの目的は、アイテム・パイプラインの記述方法を紹介することだけです。すべてのスクレイプ・アイテムをJSONファイルに保存する場合は、 フィード・エクスポート を使用する必要があります。

MongoDBにアイテムを書き込む

この例では、私たちは pymongo を使用してMongoDB にアイテムを書き込みます。MongoDBアドレスとデータベース名は、Scrapy設定で指定します。MongoDBコレクションは、アイテム・クラスに基づいて名前が付けられます。

この例の主なポイントは、 from_crawler() メソッドの使用方法と、リソースを適切にクリーンアップする方法を示すことです:

import pymongo
from itemadapter import ItemAdapter

class MongoPipeline:

    collection_name = 'scrapy_items'

    def __init__(self, mongo_uri, mongo_db):
        self.mongo_uri = mongo_uri
        self.mongo_db = mongo_db

    @classmethod
    def from_crawler(cls, crawler):
        return cls(
            mongo_uri=crawler.settings.get('MONGO_URI'),
            mongo_db=crawler.settings.get('MONGO_DATABASE', 'items')
        )

    def open_spider(self, spider):
        self.client = pymongo.MongoClient(self.mongo_uri)
        self.db = self.client[self.mongo_db]

    def close_spider(self, spider):
        self.client.close()

    def process_item(self, item, spider):
        self.db[self.collection_name].insert_one(ItemAdapter(item).asdict())
        return item
アイテムのスクリーンショットをとる

この例は、 process_item() メソッドで コルーチン構文 を使用する方法を示しています。

このアイテム・パイプラインは、ローカルで実行されている Splash のインスタンスにリクエストを送信して、アイテムのURLのスクリーンショットをレンダリングします。リクエストのレスポンスがダウンロードされた後、アイテム・パイプラインはスクリーンショットをファイルに保存し、ファイル名をアイテムに追加します。

import hashlib
from urllib.parse import quote

import scrapy
from itemadapter import ItemAdapter

class ScreenshotPipeline:
    """Pipeline that uses Splash to render screenshot of
    every Scrapy item."""

    SPLASH_URL = "http://localhost:8050/render.png?url={}"

    async def process_item(self, item, spider):
        adapter = ItemAdapter(item)
        encoded_item_url = quote(adapter["url"])
        screenshot_url = self.SPLASH_URL.format(encoded_item_url)
        request = scrapy.Request(screenshot_url)
        response = await spider.crawler.engine.download(request, spider)

        if response.status != 200:
            # Error happened, return item.
            return item

        # Save screenshot to file, filename will be hash of url.
        url = adapter["url"]
        url_hash = hashlib.md5(url.encode("utf8")).hexdigest()
        filename = f"{url_hash}.png"
        with open(filename, "wb") as f:
            f.write(response.body)

        # Store filename in item.
        adapter["screenshot_filename"] = filename
        return item
重複フィルター

重複するアイテムを探し、すでに処理されたアイテムをドロップするフィルター。アイテムには一意のIDがありますが、スパイダーは同じIDの複数のアイテムを返します:

from itemadapter import ItemAdapter
from scrapy.exceptions import DropItem

class DuplicatesPipeline:

    def __init__(self):
        self.ids_seen = set()

    def process_item(self, item, spider):
        adapter = ItemAdapter(item)
        if adapter['id'] in self.ids_seen:
            raise DropItem(f"Duplicate item found: {item!r}")
        else:
            self.ids_seen.add(adapter['id'])
            return item

アイテム・パイプライン・コンポーネントのアクティブ化

アイテム・パイプライン・コンポーネントをアクティブにするには、次の例のように、そのクラスを ITEM_PIPELINES 設定に追加する必要があります:

ITEM_PIPELINES = {
    'myproject.pipelines.PricePipeline': 300,
    'myproject.pipelines.JsonWriterPipeline': 800,
}

あなたがこの設定でクラスに割り当てる整数値は、それらが実行される順序を決定します。項目は、低い値のクラスから高い値のクラスへと通過します。 これらの数値は0〜1000の範囲で定義するのが慣例です。

フィード・エクスポート

スクレーパーを実装するときに最も頻繁に必要な機能の1つは、スクレイピングデータを適切に保存できることです。これは、他のシステムで使用されるスクレイピングデータ(一般に「エクスポートフィード」)を含む「エクスポートファイル」を生成することを意味します。

Scrapyはこの機能をすぐに使えるフィード・エクスポートで提供します。これにより、複数のシリアル化形式とストレージバックエンドを使用して、スクレイプされたアイテムを含むフィードを生成できます。

シリアル化形式

スクレイピングされたデータをシリアル化するために、フィードのエクスポートは アイテム・エクスポーター を使用します。 これらの形式はすぐに使用できます:

しかし、あなたは、 FEED_EXPORTERS 設定を通してサポートされているフォーマットを拡張することもできます。

JSON
  • FEEDS 設定の format キーの値: json

  • 使用されるエクスポーター: JsonItemExporter

  • JSONを大きなフィードで使用している場合は、 注意 :ref: この警告<json-with-large-data> を参照してください。

JSON lines
CSV
  • FEEDS 設定の format キーの値: csv

  • 使用されるエクスポーター: CsvItemExporter

  • エクスポートする列とその順序を指定するには、 FEED_EXPORT_FIELDS を使用します。 他のフィードエクスポーターもこのオプションを使用できますが、他の多くのエクスポート形式とは異なり、CSVは固定ヘッダーを使用するため、CSVでは重要です。

XML
Pickle
Marshal

ストレージ

フィード・エクスポートを使用する場合は、1つまたは複数の URIs を使用してフィードを保存する場所を定義します( FEEDS 設定を使用)。 フィードのエクスポートは、URIスキームで定義された複数のストレージ・バックエンド・タイプをサポートします。

すぐに使用できるストレージバックエンドは次のとおりです:

必要な外部ライブラリが利用できない場合、一部のストレージバックエンドは利用できません。 たとえば、S3バックエンドは botocore ライブラリがインストールされている場合にのみ使用できます。

ストレージURIパラメーター

ストレージURIには、フィードの作成時に置換されるパラメーターを含めることもできます。これらのパラメーターは次のとおりです:

  • %(time)s - フィードの作成時にタイムスタンプに置き換えられます

  • %(name)s - スパイダー名に置き換えられます

他の名前付きパラメーターは、同じ名前のスパイダー属性に置き換えられます。 たとえば、フィードが作成された瞬間に %(site_id)sspider.site_id 属性に置き換えられます。

以下に例を示します:

  • スパイダーごとに1つのディレクトリを使用してFTPに保存します:

    • ftp://user:password@ftp.example.com/scraping/feeds/%(name)s/%(time)s.json

  • スパイダーごとに1つのディレクトリを使用してS3に保存します:

    • s3://mybucket/scraping/feeds/%(name)s/%(time)s.json

ストレージ・バックエンド

ローカル・ファイルシステム

フィードはローカルファイルシステムに保存されます。

  • URIスキーム: file

  • URI例: file:///tmp/export.csv

  • 必要な外部ライブラリ: なし

ローカルファイルシステムストレージ(のみ)の場合、 /tmp/export.csv のように絶対パスを指定する場合、スキームを省略できます。 ただし、これはUnixシステムでのみ機能します。

FTP

フィードはFTPサーバーに保存されます。

  • URIスキーム: ftp

  • URI例: ftp://user:pass@ftp.example.com/path/to/export.csv

  • 必要な外部ライブラリ: なし

FTPは、2つの異なる接続モードをサポートしています。アクティブまたはパッシブ(active or passive)です。Scrapyはデフォルトでパッシブ接続モードを使用します。 代わりにアクティブな接続モードを使用するには、 FEED_STORAGE_FTP_ACTIVE 設定を True に設定します。

このストレージ・バックエンドは 遅延ファイル配送 を使います。

S3

フィードは Amazon S3 に保存されます。

  • URIスキーム: s3

  • URI例:

    • s3://mybucket/path/to/export.csv

    • s3://aws_key:aws_secret@mybucket/path/to/export.csv

  • 必要な外部ライブラリ: botocore >= 1.4.87

AWS認証情報は、URIでユーザー/パスワードとして渡すことができます。または、以下の設定を介して渡すことができます:

あなたは、この設定を使用して、エクスポートされたフィードのカスタムACLを定義することもできます:

このストレージ・バックエンドは 遅延ファイル配送 を使います。

Googleクラウド・ストレージ(GCS)

バージョン 2.3 で追加.

フィードは Google Cloud Storage に保存されます。

  • URIスキーム: gs

  • URI例:

    • gs://mybucket/path/to/export.csv

  • 必要な外部ライブラリ: google-cloud-storage

認証の詳細については Google Cloud documentation を参照してください。

Project IDAccess Control List (ACL) は、以下の設定で設定できます:

このストレージ・バックエンドは 遅延ファイル配送 を使います。

標準出力

フィードは、Scrapyプロセスの標準出力に書き込まれます。

  • URIスキーム: stdout

  • URI例: stdout:

  • 必要な外部ライブラリ: なし

遅延ファイル配送(Delayed file delivery)

先に記したように、説明したストレージ・バックエンドの一部は遅延ファイル配信(delayed file delivery)を使用します。

これらのストレージ・バックエンドは、アイテムがスクレイプされるため、フィードURIにアイテムをアップロードしません。 代わりに、Scrapyはアイテムを一時的なローカル・ファイルに書き込み、すべてのファイルの内容が書き込まれた後(つまり、クロールの最後)にのみ、そのファイルがフィードURIにアップロードされます。

これらのストレージ・バックエンドのいずれかを使用するときにアイテムの配信を早く開始したい場合は、 FEED_EXPORT_BATCH_ITEM_COUNT を使用して、ファイルごとに指定された最大アイテム数で出力アイテムを複数のファイルに分割します。そうすれば、ファイルが最大アイテム数に達するとすぐに、そのファイルがフィードURIに配信され、クロールが終了する前にアイテムの配信を開始できるようになります。

設定

これらは、フィードのエクスポートの構成(configuration)に使用される設定です:

FEEDS

バージョン 2.1 で追加.

デフォルト: {}

すべてのキーがフィードURI(または pathlib.Path オブジェクト)であり、各値が特定のフィードの構成パラメータを含むネストされた辞書である辞書。

この設定は、フィード・エクスポート機能を有効にするために必要です。

サポートされているURIスキームについては、 ストレージ・バックエンド を参照してください。

例えば:

{
    'items.json': {
        'format': 'json',
        'encoding': 'utf8',
        'store_empty': False,
        'fields': None,
        'indent': 4,
        'item_export_kwargs': {
           'export_empty_fields': True,
        },
    },
    '/home/user/documents/items.xml': {
        'format': 'xml',
        'fields': ['name', 'price'],
        'encoding': 'latin1',
        'indent': 8,
    },
    pathlib.Path('items.csv'): {
        'format': 'csv',
        'fields': ['price', 'name'],
    },
}

以下は、受け入れられたキーと、そのキーが特定のフィード定義に提供されていない場合にフォールバック値として使用される設定のリストです:

FEED_EXPORT_ENCODING

デフォルト: None

フィードに使用されるエンコード。

設定されていないか None (デフォルト)に設定されている場合、歴史的な理由で、安全な数値エンコーディング( \uXXXX シーケンス)を使用するJSON出力を除く、すべてでUTF-8を使用します。

JSONにもUTF-8が必要な場合は utf-8 を使用します。

FEED_EXPORT_FIELDS

デフォルト: None

エクスポートするフィールドのリスト。オプション。 例: FEED_EXPORT_FIELDS = ["foo", "bar", "baz"]

FEED_EXPORT_FIELDSオプションを使用して、エクスポートするフィールドとその順序を定義します。

FEED_EXPORT_FIELDSが空またはNone (デフォルト)の場合、Scrapyは、あなたのスパイダーによって生成された item objects で定義されたフィールドを使用します。

エクスポーターがフィールドの固定セットを必要とする場合( CSV エクスポート形式の場合)、FEED_EXPORT_FIELDSが空またはNoneの場合、Scrapyはエクスポートされたデータからフィールド名を推測しようとします。今のところは、最初のアイテムのフィールド名を使用しています。

FEED_EXPORT_INDENT

デフォルト: 0

各レベルで出力をインデントするために使用されるスペースの量。 FEED_EXPORT_INDENT が負でない整数の場合、配列要素とオブジェクトメンバーはそのインデントレベルできれいに印刷されます。インデントレベル 0 (デフォルト)、または負の場合、各アイテムは新しい行に配置されます。 None は、最もコンパクトな表現を選択します。

現在、 JsonItemExporterXmlItemExporter のみ実装されています。つまり、 .json または .xml にエクスポートする場合です。

FEED_STORE_EMPTY

デフォルト: False

空のフィード(つまり、アイテムのないフィード)をエクスポートするかどうか。

FEED_STORAGES

デフォルト: {}

プロジェクトでサポートされている追加のフィードストレージバックエンドを含む辞書。 キーはURIスキームであり、値はストレージクラスへのパスです。

FEED_STORAGE_FTP_ACTIVE

デフォルト: False

フィードをFTPサーバーにエクスポートするときにアクティブ接続モードを使用するか( True )、代わりにパッシブ接続モードを使用するか( False 、デフォルト)。

FTP接続モードについては、アクティブFTPとパッシブFTPの違いは何ですか?(What is the difference between active and passive FTP?)を参照してください。

FEED_STORAGE_S3_ACL

デフォルト: '' (空文字列)

プロジェクトによってAmazon S3にエクスポートされたフィードのカスタムACLを含む文字列。

利用可能な値の完全なリストについては、Amazon S3ドキュメントの Canned ACL 節にアクセスしてください。

FEED_STORAGES_BASE

デフォルト:

{
    '': 'scrapy.extensions.feedexport.FileFeedStorage',
    'file': 'scrapy.extensions.feedexport.FileFeedStorage',
    'stdout': 'scrapy.extensions.feedexport.StdoutFeedStorage',
    's3': 'scrapy.extensions.feedexport.S3FeedStorage',
    'ftp': 'scrapy.extensions.feedexport.FTPFeedStorage',
}

Scrapyがサポートする組み込みのフィードストレージバックエンドを含む辞書。 FEED_STORAGES でURIスキームに None を割り当てることで、これらのバックエンドを無効にできます。 たとえば、組み込みのFTPストレージバックエンドを無効にするには、以下を(置換なしで) `` settings.py`` に配置します:

FEED_STORAGES = {
    'ftp': None,
}
FEED_EXPORTERS

デフォルト: {}

プロジェクトでサポートされている追加のエクスポーターを含む辞書。 キーはシリアル化形式で、値は アイテム・エクスポーター クラスへのパスです。

FEED_EXPORTERS_BASE

デフォルト:

{
    'json': 'scrapy.exporters.JsonItemExporter',
    'jsonlines': 'scrapy.exporters.JsonLinesItemExporter',
    'jl': 'scrapy.exporters.JsonLinesItemExporter',
    'csv': 'scrapy.exporters.CsvItemExporter',
    'xml': 'scrapy.exporters.XmlItemExporter',
    'marshal': 'scrapy.exporters.MarshalItemExporter',
    'pickle': 'scrapy.exporters.PickleItemExporter',
}

Scrapyでサポートされている組み込みのフィードエクスポーターを含む辞書。 FEED_EXPORTERS のシリアル化形式に None を割り当てることで、これらのエクスポーターを無効にできます。 たとえば、組み込みのCSVエクスポーターを無効にするには、以下を(置換なしで)、 settings.py に配置します:

FEED_EXPORTERS = {
    'csv': None,
}
FEED_EXPORT_BATCH_ITEM_COUNT

バージョン 2.3.0 で追加.

デフォルト: 0

0 より大きい整数が割り当てられている場合、Scrapyは複数の出力ファイルを生成し、各出力ファイルに最大指定した数のアイテムを保存します。

複数の出力ファイルを生成する場合は、フィードURIで以下のプレース・ホルダーの少なくとも1つを使用して、さまざまな出力ファイル名をどのように生成するかを示す必要があります。

  • %(batch_time)s - フィードの作成時にタイムスタンプに置き換えられます(例: 2020-03-28T14-45-08.237134 )

  • %(batch_id)d - そのバッチの1から始まるシーケンス番号に置き換えられます。

    数値形式を変更するには printfスタイルの文字列書式 を使います。例えばバッチIDをゼロ詰めの5桁の数値にするには %(batch_id)05d とします(3 なら 00003 となり、 123 なら 00123 となる)。

たとえば、設定に以下が含まれている場合:

FEED_EXPORT_BATCH_ITEM_COUNT = 100

そして、あなたの crawl (クロール)コマンドラインは:

scrapy crawl spidername -o "dirname/%(batch_id)d-filename%(batch_time)s.json"

上記のコマンドラインは、以下のようなディレクトリ・ツリーを生成できます:

->projectname
-->dirname
--->1-filename2020-03-28T14-45-08.237134.json
--->2-filename2020-03-28T14-45-09.148903.json
--->3-filename2020-03-28T14-45-10.046092.json

ここで、最初と2番目のファイルに正確に100個のアイテムが含まれている場合。最後のファイルには100個またはそれ以下の数のアイテムが含まれています。

FEED_URI_PARAMS

デフォルト: None

フィードURIに printfスタイル文字列書式 のパラメーターを設定する関数のインポート・パスを持つ文字列。

関数の識別は以下のようにしなければなりません:

scrapy.extensions.feedexport.uri_params(params, spider)

printfスタイル文字列書式 をフィードURIに適用したkey-valueペアの辞書(dict)を返す。

パラメータ
  • params (dict) --

    デフォルトのkey-valueペア達

    具体的には:

    • batch_id: ファイルバッチのID。 FEED_EXPORT_BATCH_ITEM_COUNT 参照。

      FEED_EXPORT_BATCH_ITEM_COUNT0 の場合 batch_id は常に 1

      バージョン 2.3.0 で追加.

    • batch_time: UTCの日付と時間。ISO書式ですが :- で置き換えられています。

      FEED_EXPORT_BATCH_ITEM_COUNT 参照。

      バージョン 2.3.0 で追加.

    • time: batch_time のマイクロ秒単位を 0 にセットしたもの。

  • spider (scrapy.spiders.Spider) -- フィード・アイテムのソース・スパイダー

例えば、ソース・スパイダーの name を フィードURIに含めるには:

  1. あなたのプロジェクトの何処かで以下の関数を定義します:

    # myproject/utils.py
    def uri_params(params, spider):
        return {**params, 'spider_name': spider.name}
    
  2. あなたの設定でその関数を FEED_URI_PARAMS に指定します:

    # myproject/settings.py
    FEED_URI_PARAMS = 'myproject.utils.uri_params'
    
  3. あなたのフィードURIで %(spider_name)s を使います:

    scrapy crawl <spider_name> -o "%(spider_name)s.jl"
    

リクエストとレスポンス

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

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

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

Requestオブジェクト

class scrapy.http.Request(*args, **kwargs)[ソース]

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

パラメータ
  • url (str) -- このリクエストのURL。URLが不正な場合、 ValueError 例外が発生する。

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

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

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

  • body (bytes or str) -- リクエスト・ボディ。 文字列が渡されると、渡された encoding (デフォルトは utf-8 )を使用してバイトとしてエンコードされます。 body が指定されていない場合、空のバイト・オブジェクトが格納されます。この引数のタイプに関係なく、格納される最終値はバイト・オブジェクトになります(文字列や None ではありません)。

  • headers (dict) --

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

    注意

    Cookie ヘッダーを介して設定されたクッキーは、 CookiesMiddleware では考慮されません。リクエストにクッキーを設定する必要がある場合、 Request.cookies パラメータを使用します。 これは、現在改善に取り組んでいる既知の制限です。

  • 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 に設定します。

    手動で定義したクッキーを送信し、クッキーの保存を無視するリクエストの例:

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

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

    注意

    Cookie ヘッダーを介して設定されたクッキーは、 CookiesMiddleware では考慮されません。リクエストにクッキーを設定する必要がある場合、 Request.cookies パラメータを使用します。 これは、現在改善に取り組んでいる既知の制限です。

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

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

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

  • errback (collections.abc.Callable) --

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

    バージョン 2.0 で変更: errback パラメータが指定されている場合、callback パラメータは不要になりました。

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

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

url

このリクエストのURLを含む文字列。 この属性にはエスケープされたURLが含まれているため、 __init__ メソッドで渡されたURLとは異なる可能性があることに注意してください。

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

method

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

headers

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

body

バイト(bytes)としてのリクエスト・ボディ。

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

meta

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

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

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

cb_kwargs

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

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

リクエストの処理に失敗した場合、リクエストのエラーバック(errback)で failure.request.cb_kwargs としてこの辞書にアクセスできます。 詳細については、errback関数内で追加データにアクセスする を参照してください。

copy()[ソース]

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

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

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

classmethod from_curl(curl_command, ignore_unknown_options=True, **kwargs)[ソース]

cURL コマンドを含む文字列からリクエストオブジェクトを作成します。 HTTPメソッドとURLとヘッダーとクッキーとボディを設定します。 Request クラスと同じ引数を受け入れ、優先度を取得し、cURLコマンドに含まれる同じ引数の値をオーバーライドします。

認識されないオプションはデフォルトで無視されます。不明なオプションを見つけるときにエラーを発生させるには、 ignore_unknown_options=False を渡してこのメソッドを呼び出します。

注意

JSONRequest または XmlRpcRequest のような Request のサブクラスから from_curl() を使用し、DefaultHeadersMiddleware または UserAgentMiddleware または HttpCompressionMiddleware のような ダウンローダー・ミドルウェアスパイダー・ミドルウェア を有効にすることで、Request オブジェクトを変更できます。

cURL コマンドを Scrapy リクエストに変換するには、 curl2scrapy を使用できます。

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

リクエストのコールバックは、そのリクエストのレスポンスがダウンロードされるときに呼び出される関数です。コールバック関数は、ダウンロードされた 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)は、処理中に例外が発生したときに呼び出される関数です。

最初のパラメータとして 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)
errback関数内で追加データにアクセスする

リクエストの処理に失敗した場合は、コールバック関数の引数にアクセスして、errback内の引数に基づいてさらなる処理ができるようにすることをお勧めします。以下の例は、 Failure.request.cb_kwargs を使用してこれを実現する方法を示しています:

def parse(self, response):
    request = scrapy.Request('http://www.example.com/index.html',
                             callback=self.parse_page2,
                             errback=self.errback_page2,
                             cb_kwargs=dict(main_url=response.url))
    yield request

def parse_page2(self, response, main_url):
    pass

def errback_page2(self, failure):
    yield dict(
        main_url=failure.request.cb_kwargs['main_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 設定よりも優先されます。

レスポンスのダウンロードの停止

bytes_received または headers_received シグナルのハンドラーから StopDownload 例外を発生させると、そのレスポンスのダウンロードを停止させます。以下の例を参照してください:

import scrapy


class StopSpider(scrapy.Spider):
    name = "stop"
    start_urls = ["https://docs.scrapy.org/en/latest/"]

    @classmethod
    def from_crawler(cls, crawler):
        spider = super().from_crawler(crawler)
        crawler.signals.connect(spider.on_bytes_received, signal=scrapy.signals.bytes_received)
        return spider

    def parse(self, response):
        # 'last_chars' show that the full response was not downloaded
        yield {"len": len(response.text), "last_chars": response.text[-40:]}

    def on_bytes_received(self, data, request, spider):
        raise scrapy.exceptions.StopDownload(fail=False)

これにより、以下の出力が生成されます:

2020-05-19 17:26:12 [scrapy.core.engine] INFO: Spider opened
2020-05-19 17:26:12 [scrapy.extensions.logstats] INFO: Crawled 0 pages (at 0 pages/min), scraped 0 items (at 0 items/min)
2020-05-19 17:26:13 [scrapy.core.downloader.handlers.http11] DEBUG: Download stopped for <GET https://docs.scrapy.org/en/latest/> from signal handler StopSpider.on_bytes_received
2020-05-19 17:26:13 [scrapy.core.engine] DEBUG: Crawled (200) <GET https://docs.scrapy.org/en/latest/> (referer: None) ['download_stopped']
2020-05-19 17:26:13 [scrapy.core.scraper] DEBUG: Scraped from <200 https://docs.scrapy.org/en/latest/>
{'len': 279, 'last_chars': 'dth, initial-scale=1.0">\n  \n  <title>Scr'}
2020-05-19 17:26:13 [scrapy.core.engine] INFO: Closing spider (finished)

デフォルトでは、結果のレスポンスは対応するエラーバック(errback)によって処理されます。 代わりにコールバックを呼び出すには、この例のように、fail=FalseStopDownload 例外に渡します。

Requestのサブクラス

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

FormRequestオブジェクト

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

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

FormRequest クラスは、新しいキーワード・パラメータを __init__ メソッドに追加します。残りの引数は Request クラスと同じであり、ここでは説明しません。

パラメータ

formdata (dict or collections.abc.Iterable) -- これは、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 (str) -- 指定した場合、name属性をこの値に設定したフォームが使用されます。

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

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

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

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

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

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

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

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

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つの新しいキーワード・パラメータを __init__ メソッドに追加します。残りの引数は Request クラスと同じであり、ここでは説明しません。

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

パラメータ
  • data (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(*args, **kwargs)[ソース]

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

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

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

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

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

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

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

  • certificate (twisted.internet.ssl.Certificate) -- サーバーのSSL証明書を表すオブジェクト。

  • ip_address (ipaddress.IPv4Address or ipaddress.IPv6Address) -- レスポンスの送信元のサーバーのIPアドレス。

  • protocol (str) -- レスポンスのダウンロードに使用されたプロトコル。 例: "HTTP/1.0", "HTTP/1.1", "h2"

バージョン 2.0.0 で追加: certificate パラメータ。

バージョン 2.1.0 で追加: ip_address パラメータ。

バージョン 2.5.0 で追加: protocol パラメータ。

url

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

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

status

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

headers

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

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

バイト(bytes)としてのレスポンス・ボディ

ボディを文字列として使用する場合は、 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 属性

cb_kwargs

バージョン 2.0 で追加.

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

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

参考

Request.cb_kwargs 属性

flags

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

certificate

バージョン 2.0.0 で追加.

サーバーのSSL証明書を表す twisted.internet.ssl.Certificate オブジェクト。

https のレスポンスに対してのみ入力され、それ以外の場合は None が入力されます。

ip_address

バージョン 2.1.0 で追加.

レスポンスの送信元のサーバーのIPアドレス。

この属性は現在、HTTP 1.1 ダウンロードハンドラ、つまり http(s) のレスポンスによってのみ入力されます。 他のハンドラの場合、 ip_address は常に None です。

protocol

バージョン 2.5.0 で追加.

レスポンスのダウンロードに使用されたプロトコル。 例: "HTTP/1.0", "HTTP/1.1"

この属性は現在、HTTPダウンロードハンドラ、つまり http(s) レスポンスによってのみ入力されます。 他のハンドラの場合、 protocol は常に None です。

copy()[ソース]

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

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

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

urljoin(url)[ソース]

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

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

urllib.parse.urljoin(response.url, url)
follow(url, callback=None, method='GET', headers=None, body=None, cookies=None, meta=None, encoding='utf-8', priority=0, dont_filter=False, errback=None, cb_kwargs=None, flags=None)scrapy.http.request.Request[ソース]

リンク url をたどるための Request インスタンスを返します。 Request.__init__ メソッドと同じ引数を受け入れますが、 url は絶対URLだけでなく、相対URLまたは scrapy.link.Link オブジェクトでもかまいません。

TextResponse は、絶対URLと相対URLとLinkオブジェクトに加えてセレクターをサポートする follow() メソッドを提供します。

バージョン 2.0 で追加: flags パラメータ。

follow_all(urls, callback=None, method='GET', headers=None, body=None, cookies=None, meta=None, encoding='utf-8', priority=0, dont_filter=False, errback=None, cb_kwargs=None, flags=None)Generator[scrapy.http.request.Request, None, None][ソース]

バージョン 2.0 で追加.

urls 内のすべてのリンクをたどるために、反復可能(iterable)な Request インスタンスを返します。 Request.__init__ メソッドと同じ引数を受け入れますが、 urls の要素は、絶対URLだけでなく、相対URLまたは Link オブジェクトにすることができます。

TextResponse は、絶対URLと相対URLとLinkオブジェクトに加えてセレクターをサポートする follow_all() メソッドを提供します。

Responseのサブクラス

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

TextResponseオブジェクト
class scrapy.http.TextResponse(url[, encoding[, ...]])[ソース]

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

TextResponse オブジェクトは、基本の Response オブジェクトに加えて、新しい __init__ メソッド引数をサポートします。 残りの機能は Response クラスの場合と同じであり、ここでは説明しません。

パラメータ

encoding (str) -- このレスポンスに使用するエンコーディングを含む文字列です。文字列をボディとして TextResponse オブジェクトを作成すると、このエンコーディングを使用してエンコードされたバイトに変換されます。 encodingNone (デフォルト)の場合、レスポンス・ヘッダーとボディの中でエンコーディングを探します。

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

text

文字列としてのスポンス・ボディ

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

注釈

str(response.body) は、レスポンス・ボディを文字列に変換する正しい方法ではありません:

>>> str(b'body')
"b'body'"
encoding

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

  1. __init__ メソッドの 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')
follow(url, callback=None, method='GET', headers=None, body=None, cookies=None, meta=None, encoding=None, priority=0, dont_filter=False, errback=None, cb_kwargs=None, flags=None)scrapy.http.request.Request[ソース]

リンク url をたどるには Request インスタンスを返します。 Request.__init__ メソッドと同じ引数を受け入れますが、 url は絶対URLだけでなく、以下も受け入れます。

  • 相対URL

  • Link オブジェクト。例: リンク抽出器(link extractors) の結果

  • <link> または <a> 要素の Selector オブジェクト。例えば response.css('a.my_link')[0]

  • 属性 Selector (SelectorListではありません)。 例: response.css('a::attr(href)')[0] または response.xpath('//img/@src')[0]

使用例については リクエストを作成するためのショートカット を参照して下さい。

follow_all(urls=None, callback=None, method='GET', headers=None, body=None, cookies=None, meta=None, encoding=None, priority=0, dont_filter=False, errback=None, cb_kwargs=None, flags=None, css=None, xpath=None)Generator[scrapy.http.request.Request, None, None][ソース]

urls 内のすべてのリンクをたどるための Request インスタンスを生成するジェネレータ。 Request__init__ メソッドと同じ引数を受け入れますが、各 urls 要素は絶対 URL である必要はなく、以下のいずれも指定できます:

  • 相対URL

  • Link オブジェクト。例: リンク抽出器(link extractors) の結果

  • <link> または <a> 要素の Selector オブジェクト。例えば response.css('a.my_link')[0]

  • 属性 Selector (SelectorListではありません)。 例: response.css('a::attr(href)')[0] または response.xpath('//img/@src')[0]

さらに、 css および xpath 引数は、 follow_all メソッド内でリンク抽出を実行するために受け入れられます( urls および css および xpath のうちの1つだけが受け入れられます)。

SelectorListurls パラメータの引数として渡す場合、または css または xpath パラメータを使用する場合、このメソッドはリンクを取得できないセレクターのリクエストを生成しないことに注意してください。 (例えば、href 属性のないアンカータグ)

json()[ソース]

バージョン 2.2 で追加.

JSON ドキュメントを Python オブジェクトに逆シリアライズ(deserialize)します。

逆シリアライズ(deserialize)された JSON ドキュメントから Python オブジェクトを返します。 結果は、最初の呼び出し後にキャッシュされます。

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 参照。

設定

Scrapy設定を使用すると、コア、拡張機能、パイプライン、スパイダー自体を含むすべてのScrapyコンポーネントの動作をカスタマイズできます。

設定のインフラストラクチャは、コードが構成値を取得するために使用できるキーと値のマッピングのグローバル名前空間を提供します。設定は、以下で説明するさまざまなメカニズムを使用して設定できます。

設定は、(多くの場合)現在アクティブなScrapyプロジェクトを選択するためのメカニズムでもあります。

利用可能な組み込み設定のリストについては、 組み込みの設定リファレンス を参照してください。

設定の指定

あなたがScrapyを使用するときは、あなたは使用している設定を伝える必要があります。これを行うには、環境変数 SCRAPY_SETTINGS_MODULE を使用します。

SCRAPY_SETTINGS_MODULE の値は、Pythonパス構文である必要があります。例えば myproject.settings です。設定モジュールはPythonの インポート検索パス にある必要があることに注意してください。

設定の入力

設定は、それぞれ異なる優先順位を持つさまざまなメカニズムを使用して入力できます。 優先順位の降順でそれらのリストを示します:

  1. コマンド・ライン・オプション(最優先)

  2. スパイダーごとの設定

  3. プロジェクト設定モジュール

  4. コマンドごとのデフォルト設定

  5. デフォルトのグローバル設定(最も優先度が低い)

これらの設定ソースの入力は内部的に処理されますが、API呼び出しを使用して手動で処理することができます。 参考として APIの設定 トピックを参照してください。

これらのメカニズムについては、以下で詳しく説明します。

1. コマンド・ライン・オプション

コマンドラインで提供される引数は、他のオプションより優先され、最も優先される引数です。 ` -s`` (または --set )コマンドラインオプションを使用して、1つ(または複数)の設定を明示的にオーバーライドできます。

例:

scrapy crawl myspider -s LOG_FILE=scrapy.log
2. スパイダーごとの設定

スパイダー( スパイダー 参照)は、プロジェクト設定を優先して上書きする独自の設定を定義できます。 そのためには custom_settings 属性を設定します:

class MySpider(scrapy.Spider):
    name = 'myspider'

    custom_settings = {
        'SOME_SETTING': 'some value',
    }
3. プロジェクト設定モジュール

プロジェクト設定モジュールは、Scrapyプロジェクトの標準構成ファイルであり、ほとんどのカスタム設定がそこに入力されます。 標準のScrapyプロジェクトの場合、これは、プロジェクト用に作成された settings.py ファイルの設定を追加または変更することを意味します。

4. コマンドごとのデフォルト設定

Scrapyツール コマンドには、グローバルなデフォルト設定を上書きする独自のデフォルト設定を含めることができます。これらのカスタム・コマンド設定は、コマンド・クラスの default_settings 属性で指定されます。

5. デフォルトのグローバル設定

グローバルなデフォルトは scrapy.settings.default_settings モジュールにあり、 組み込みの設定リファレンス で文書化されています。

パス達やクラス達のインポート

バージョン 2.4.0 で追加.

設定がクラスや関数など、Scrapyによってインポートされる呼び出し可能なオブジェクトを参照する場合、そのオブジェクトを指定する2つの異なる方法があります:

  • そのオブジェクトのインポート・パス(path)を含む文字列として

  • オブジェクト自体として

例:

from mybot.pipelines.validate import ValidateMyItem
ITEM_PIPELINES = {
    # passing the classname...
    ValidateMyItem: 300,
    # ...equals passing the class path
    'mybot.pipelines.validate.ValidateMyItem': 300,
}

注釈

呼び出し不可能なオブジェクトの受け渡しはサポートされていません。

設定にアクセスする方法

スパイダーでは、設定は self.settings から利用できます:

class MySpider(scrapy.Spider):
    name = 'myspider'
    start_urls = ['http://example.com']

    def parse(self, response):
        print(f"Existing settings: {self.settings.attributes.keys()}")

注釈

settings 属性は、スパイダーが初期化された後にベースSpiderクラスで設定されます。初期化の前に設定を使用する場合(たとえば、スパイダーの __init__() メソッドで)、 from_crawler() メソッドをオーバーライドする必要があります。

設定には、拡張機能、ミドルウェア、アイテム・パイプラインの from_crawler メソッドに渡されるクローラーの scrapy.crawler.Crawler.settings 属性からアクセスできます:

class MyExtension:
    def __init__(self, log_is_enabled=False):
        if log_is_enabled:
            print("log is enabled!")

    @classmethod
    def from_crawler(cls, crawler):
        settings = crawler.settings
        return cls(settings.getbool('LOG_ENABLED'))

設定オブジェクトは辞書のように使用できます(例: settings['LOG_ENABLED'] )。ただし、通常、タイプ・エラーを回避するために必要な形式で設定を抽出し、 Settings APIで提供されるメソッドの1つを使用することをお勧めします。

名前を設定する理由

設定名には通常、構成するコンポーネントの接頭辞が付きます。 たとえば、架空のrobots.txt拡張子の適切な設定名は、 ROBOTSTXT_ENABLEDROBOTSTXT_OBEYROBOTSTXT_CACHEDIR などになります。

組み込みの設定リファレンス

以下に、利用可能なすべてのスクレイピー設定のリストをアルファベット順に、デフォルト値と適用範囲とともに示します。

使用可能な場所では、スコープは、特定のコンポーネントに関連付けられている場合、設定が使用されている場所を示します。 その場合、そのコンポーネントのモジュールは通常、拡張機能、ミドルウェア、またはパイプラインが表示されます。 また、設定を有効にするには、コンポーネントを有効にする必要があります。

AWS_ACCESS_KEY_ID

デフォルト: None

S3フィードストレージバックエンド など、 Amazon Web services へのアクセスを必要とするコードで使用されるAWSアクセスキー。

AWS_SECRET_ACCESS_KEY

デフォルト: None

S3フィード・ストレージ・バックエンド など、 Amazon Web services へのアクセスを必要とするコードで使用されるAWSシークレット・キー

AWS_ENDPOINT_URL

デフォルト: None

Minioやs3.scalityなど、S3のようなストレージに使用されるエンドポイントURL。

AWS_USE_SSL

デフォルト: None

S3またはS3のようなストレージとの通信でSSL接続を無効にする場合は、このオプションを使用します。デフォルトではSSLが使用されます。

AWS_VERIFY

デフォルト: None

ScrapyとS3またはS3のようなストレージ間のSSL接続を検証(verify)します。デフォルトでは、SSL検証(verify)が行われます。

AWS_REGION_NAME

デフォルト: None

AWSクライアントに関連付けられているリージョンの名前。

ASYNCIO_EVENT_LOOP

デフォルト: None

指定された asyncio イベント・ループ・クラスのインポート・パス。

asyncioリアクターが有効になっている場合(TWISTED_REACTOR 参照)、この設定を使用してasyncioイベント・ループを指定することができます。設定を目的のasyncioイベント・ループ・クラスのインポート・パスに設定します。設定が None に設定されている場合、デフォルトのasyncioイベント・ループを使用します。。

install_reactor() 関数を使用して非同期リアクターを手動でインストールする場合、 event_loop_path パラメータを使用して、使用するイベント・ループ・クラスのインポート・パスを指定できます。

イベント・ループ・クラスは asyncio.AbstractEventLoop を継承する必要があることに注意してください。

注意

以下をご了承ください:デフォルト以外のイベントループ (ASYNCIO_EVENT_LOOP で定義するか、 install_reactor() でインストール) を使用する場合、Scrapy は asyncio.set_event_loop() を呼び出します。これにより、指定されたイベント・ループが現在のOSスレッドの現在のループとして設定されます。

BOT_NAME

デフォルト: 'scrapybot'

このScrapyプロジェクトによって実装されるボット(bot)の名前(プロジェクト名とも呼ばれます)。この名前はロギングにも使用されます。

startproject コマンドでプロジェクトを作成すると、プロジェクト名が自動的に入力されます。

CONCURRENT_ITEMS

デフォルト: 100

item パイプライン で並行して処理する(レスポンスごとの)同時アイテムの最大数。

CONCURRENT_REQUESTS

デフォルト: 16

Scrapyダウンローダーが実行する並列(すなわち同時)リクエストの最大数。

CONCURRENT_REQUESTS_PER_DOMAIN

デフォルト: 8

任意の単一ドメインに対して実行される並列(すなわち同時)リクエストの最大数。

AutoThrottle拡張機能 と、その AUTOTHROTTLE_TARGET_CONCURRENCY オプションを参照して下さい。

CONCURRENT_REQUESTS_PER_IP

デフォルト: 0

単一のIPに対して実行される並行(すなわち同時)リクエストの最大数。 ゼロ以外の場合、 CONCURRENT_REQUESTS_PER_DOMAIN 設定は無視され、代わりにこの設定が使用されます。 つまり、並列実行制限はドメインごとではなくIPごとに適用されます。

この設定は、 DOWNLOAD_DELAYAutoThrottle拡張機能 にも影響します。 CONCURRENT_REQUESTS_PER_IP がゼロ以外の場合、ダウンロード遅延はドメインごとではなくIPごとに適用されます。

DEFAULT_ITEM_CLASS

デフォルト: 'scrapy.item.Item'

Scrapyシェル 内のアイテムのインスタンス化に使用されるデフォルト・クラス。

DEFAULT_REQUEST_HEADERS

デフォルト:

{
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
    'Accept-Language': 'en',
}

Scrapy HTTPリクエストに使用されるデフォルトのヘッダー。それらは DefaultHeadersMiddleware に取り込まれます。

注意

Cookie ヘッダーを介して設定されたクッキーは、 CookiesMiddleware では考慮されません。 リクエストにクッキーを設定する必要がある場合は、 Request.cookies パラメータを使用します。 これは、現在改善に取り組んでいる既知の制限です。

DEPTH_LIMIT

デフォルト: 0

スコープ: scrapy.spidermiddlewares.depth.DepthMiddleware

任意のサイトでクロールできる最大深度。 ゼロの場合、制限は課されません。

DEPTH_PRIORITY

デフォルト: 0

スコープ: scrapy.spidermiddlewares.depth.DepthMiddleware

深さに基づいて Requestpriority を調整するために使用される整数。

リクエストの優先度は次のように調整されます:

request.priority = request.priority - ( depth * DEPTH_PRIORITY )

深さが増加すると、 DEPTH_PRIORITY の正の値はリクエストの優先度(BFO)を下げ、負の値はリクエストの優先度(DFO)を上げます。 Scrapyは幅(breadth)優先または深さ(depth)優先でクロールしますか? も参照してください。

注釈

この設定は、他の優先度設定 REDIRECT_PRIORITY_ADJUSTRETRY_PRIORITY_ADJUST と比較して、 逆の方法で 優先度を調整します。

DEPTH_STATS_VERBOSE

デフォルト: False

スコープ: scrapy.spidermiddlewares.depth.DepthMiddleware

詳細な統計情報を収集するかどうか。これが有効になっている場合、各深さのリクエスト数が統計に収集されます。

DNSCACHE_ENABLED

デフォルト: True

DNSイン・メモリ・キャッシュを有効にするかどうか。

DNSCACHE_SIZE

デフォルト: 10000

DNSイン・メモリ・キャッシュ・サイズ。

DNS_RESOLVER

バージョン 2.0 で追加.

デフォルト: 'scrapy.resolver.CachingThreadedResolver'

DNS名を解決するために使用されるクラス。デフォルトの scrapy.resolver.CachingThreadedResolverDNS_TIMEOUT 設定によるDNSリクエストのタイムアウトの指定をサポートしていますが、IPv4 アドレスでのみ機能します。Scrapyは代替のリゾルバ scrapy.resolver.CachingHostnameResolver を提供します。これは IPv4/IPv6 アドレスをサポートしますが DNS_TIMEOUT 設定を考慮しません。

DNS_TIMEOUT

デフォルト: 60

DNSクエリの処理のタイムアウト(秒)。float値がサポートされています。

DOWNLOADER

デフォルト: 'scrapy.core.downloader.Downloader'

クロールに使用するダウンローダー。

DOWNLOADER_HTTPCLIENTFACTORY

デフォルト: 'scrapy.core.downloader.webclient.ScrapyHTTPClientFactory'

( HTTP10DownloadHandler の場合、) HTTP/1.0接続に使用する Twisted protocol.ClientFactory クラスを定義します。

注釈

HTTP/1.0 は最近ではめったに使用されないため、 本当に HTTP/1.0 を使用しかつ、 'scrapy.core.downloader.handlers.http.HTTP10DownloadHandler' に応じて http(s) スキームの DOWNLOAD_HANDLERS をオーバーライドしたい場合を除き、この設定は無視しても問題ありません。

DOWNLOADER_CLIENTCONTEXTFACTORY

デフォルト: 'scrapy.core.downloader.contextfactory.ScrapyClientContextFactory'

使用するContextFactoryへのクラスパスを表します。

ここで、ContextFactoryはSSL/TLSコンテキストのTwisted用語であり、使用するTLS/SSLプロトコルのバージョン、証明書の検証(verification)を行うか、クライアント側の認証を有効にするかなどを定義します。

注釈

Scrapyデフォルト・コンテキスト・ファクトリは リモート・サーバー証明書の検証を実行しません 。これは通常、Webスクレイピングに適しています。

リモート・サーバー証明書の検証を有効にする必要がある場合、Scrapyには設定可能な別のコンテキスト・ファクトリ・クラス 'scrapy.core.downloader.contextfactory.BrowserLikeContextFactory' があり、プラットフォームの証明書を使用してリモート・エンドポイントを検証します。

カスタムContextFactoryを使用する場合、その __init__ メソッドが method パラメーター(これは OpenSSL.SSL メソッド・マッピング DOWNLOADER_CLIENT_TLS_METHOD です)と tls_verbose_logging'' パラメーター( ``bool ) と tls_ciphers パラメーター( DOWNLOADER_CLIENT_TLS_CIPHERS 参照)を受け入れる事を確認して下さい。

DOWNLOADER_CLIENT_TLS_CIPHERS

デフォルト: 'DEFAULT'

この設定を使用して、デフォルトの HTTP/1.1 ダウンローダーが使用するTLS/SSL暗号cipher)をカスタマイズします。

設定にはOpenSSL暗号リスト形式(OpenSSL cipher list format)の文字列が含まれている必要があります。これらの暗号はクライアント暗号として使用されます。 特定のHTTPS Webサイトにアクセスするには、この設定の変更が必要になる場合があります。たとえば、弱いDHパラメーターを持つWebサイトに 'DEFAULT:!DH' を使用しするか、または、Webサイトが要求しない場合は DEFAULT 含まれない特定の暗号を有効にする必要があります。

DOWNLOADER_CLIENT_TLS_METHOD

デフォルト: 'TLS'

この設定を使用して、デフォルトの HTTP/1.1 ダウンローダーが使用するTLS/SSLメソッドをカスタマイズします。

この設定は、次の文字列値のいずれかでなければなりません:

  • 'TLS': これはOpenSSLの TLS_method() (別名 SSLv23_method() )にマップします。これにより、プラットフォームでサポートされる最高のものからプロトコル・ネゴシエーションが可能になります。 これがデフォルトかつ推奨です

  • 'TLSv1.0': この値は、HTTPS接続がTLSバージョン1.0を使用するように強制します。Scrapy<1.1 の動作が必要な場合はこれを設定します

  • 'TLSv1.1': TLS バージョン 1.1 の使用を強制します

  • 'TLSv1.2': TLS バージョン 1.2 の使用を強制します

  • 'SSLv3': SSL バージョン3の使用を強制します ( 非推奨 )

DOWNLOADER_CLIENT_TLS_VERBOSE_LOGGING

デフォルト: False

これを True に設定すると、HTTPS接続を確立した後、TLS接続パラメーターに関するDEBUGレベルのメッセージが有効になります。記録される情報の種類は、OpenSSLおよびpyOpenSSLのバージョンによって異なります。

この設定は、デフォルトの DOWNLOADER_CLIENTCONTEXTFACTORY にのみ使用されます。

DOWNLOADER_MIDDLEWARES

デフォルト:: {}

プロジェクトで有効になっているダウンローダー・ミドルウェアとその順序を含む辞書。詳細については、 ダウンローダーミドルウェアをアクティブにする を参照してください。

DOWNLOADER_MIDDLEWARES_BASE

デフォルト:

{
    'scrapy.downloadermiddlewares.robotstxt.RobotsTxtMiddleware': 100,
    'scrapy.downloadermiddlewares.httpauth.HttpAuthMiddleware': 300,
    'scrapy.downloadermiddlewares.downloadtimeout.DownloadTimeoutMiddleware': 350,
    'scrapy.downloadermiddlewares.defaultheaders.DefaultHeadersMiddleware': 400,
    'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware': 500,
    'scrapy.downloadermiddlewares.retry.RetryMiddleware': 550,
    'scrapy.downloadermiddlewares.ajaxcrawl.AjaxCrawlMiddleware': 560,
    'scrapy.downloadermiddlewares.redirect.MetaRefreshMiddleware': 580,
    'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware': 590,
    'scrapy.downloadermiddlewares.redirect.RedirectMiddleware': 600,
    'scrapy.downloadermiddlewares.cookies.CookiesMiddleware': 700,
    'scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware': 750,
    'scrapy.downloadermiddlewares.stats.DownloaderStats': 850,
    'scrapy.downloadermiddlewares.httpcache.HttpCacheMiddleware': 900,
}

Scrapyでデフォルトで有効になっているダウンローダー・ミドルウェアを含む辞書。 低次はエンジンに近く、高次はダウンローダーに近いです。プロジェクト内でこの設定を変更しないでください。代わりに DOWNLOADER_MIDDLEWARES を変更してください。詳細については、 ダウンローダーミドルウェアをアクティブにする を参照してください。

DOWNLOADER_STATS

デフォルト: True

ダウンローダー統計収集を有効にするかどうか。

DOWNLOAD_DELAY

デフォルト: 0

ダウンローダーが同じWebサイトから連続したページをダウンロードするまで待機する時間(秒)。 これを使用してクロール速度を調整し、サーバーへの過度のヒットを回避できます。10進数がサポートされています。 例:

DOWNLOAD_DELAY = 0.25    # 250 ms of delay

この設定は、 RANDOMIZE_DOWNLOAD_DELAY 設定(デフォルトで有効)の影響も受けます。デフォルトでは、Scrapyはリクエスト間で一定の時間を待機する訳ではなく、(0.5 * DOWNLOAD_DELAY ) から ( 1.5 * DOWNLOAD_DELAY )の間のランダムな間隔を使用します。

CONCURRENT_REQUESTS_PER_IP がゼロ以外の場合、遅延はドメインごとではなくIPアドレスごとに適用されます。

あなたは download_delay スパイダー属性を設定することで、スパイダーごとにこの設定を変更することもできます。

DOWNLOAD_HANDLERS

デフォルト: {}

プロジェクトで有効にされたリクエスト・ダウンローダー・ハンドラーを含む辞書。 形式の例については、 DOWNLOAD_HANDLERS_BASE を参照してください。

DOWNLOAD_HANDLERS_BASE

デフォルト:

{
    'file': 'scrapy.core.downloader.handlers.file.FileDownloadHandler',
    'http': 'scrapy.core.downloader.handlers.http.HTTPDownloadHandler',
    'https': 'scrapy.core.downloader.handlers.http.HTTPDownloadHandler',
    's3': 'scrapy.core.downloader.handlers.s3.S3DownloadHandler',
    'ftp': 'scrapy.core.downloader.handlers.ftp.FTPDownloadHandler',
}

Scrapyでデフォルトで有効になっているリクエスト・ダウンロード・ハンドラーを含む辞書。 プロジェクトのこの設定を変更するのではなく、代わりに DOWNLOAD_HANDLERS を変更してください。

DOWNLOAD_HANDLERS でURIスキームに None を割り当てることで、これらのダウンロード・ハンドラーを無効にできます。たとえば、組み込みFTPハンドラーを(置換なしで)無効にするには、これを settings.py に配置します:

DOWNLOAD_HANDLERS = {
    'ftp': None,
}

デフォルトの HTTPS ハンドラーは HTTP/1.1 を使用します。 HTTP/2 アップデートを使用するには、以下のように DOWNLOAD_HANDLERS を使用します:

DOWNLOAD_HANDLERS = {
    'https': 'scrapy.core.downloader.handlers.http2.H2DownloadHandler',
}

警告

Scrapy での HTTP/2 サポートは実験的であり、実稼働環境ではまだ推奨されていません。 将来の Scrapy バージョンでは、非推奨期間や警告なしに関連する変更が導入される可能性があります。

注釈

Scrapyの現在の HTTP/2 実装の既知の制限は以下のとおりです:

  • 主要なブラウザは暗号化されていない HTTP/2 をサポートしていないため、HTTP/2 Cleartext (h2c) はサポートしていません( http2 faq 参照)。

  • デフォルト値の 16384 より大きい最大 frame size を指定する設定はありません。それより大きなフレームを送信するサーバーへの接続は失敗します。

  • server pushes はサポートされていません。無視されます。

  • bytes_receivedheaders_received シグナルはサポートされていません。

DOWNLOAD_TIMEOUT

デフォルト: 180

ダウンローダーがタイムアウトするまで待機する時間(秒)。

注釈

このタイムアウトは、 download_timeout スパイダー属性を使用してスパイダーごとに設定でき、 download_timeout Request.metaキーを使用してリクエストごとに設定できます。

DOWNLOAD_MAXSIZE

デフォルト: 1073741824 (1024MB)

ダウンローダーがダウンロードする最大レスポンス・サイズ(バイト単位)。

無効にしたい場合は0をセットします。

注釈

このサイズは、スパイダー属性 download_maxsize を使用してスパイダーごとに設定し、リクエストごとに download_maxsize Request.metaキーを使用して設定できます。

DOWNLOAD_WARNSIZE

デフォルト: 33554432 (32MB)

ダウンローダーが警告し始めるレスポンス・サイズ(バイト単位)。

無効にしたい場合は0をセットします。

注釈

download_warnsize スパイダー属性を使用してスパイダーごとにこのサイズを設定し、 download_warnsize Request.metaキーを使用してリクエストごとに設定できます。

DOWNLOAD_FAIL_ON_DATALOSS

デフォルト: True

壊れた応答で失敗するかどうか、つまり、宣言された Content-Length がサーバーによって送信されたコンテンツと一致しないか、チャンクされた応答が適切に終了しませんでした。 True の場合、これらのレスポンスは ResponseFailed([_DataLoss]) エラーを発生させます。 False の場合、これらのレスポンスはパス・スルーされ、フラグ dataloss がレスポンスに追加されます。すなわち、response.flagsの 'dataloss'True です。

オプションで、これは download_fail_on_dataloss Request.metaキーを False に使用することで、リクエストごとに設定できます。

注釈

サーバーの設定ミスからネットワークエラー、データ破損まで、いくつかの状況下で、レスポンスの破損、またはデータ損失エラーが発生する場合があります。 部分的なコンテンツや不完全なコンテンツが含まれている可能性があることを考慮して、壊れたレスポンスを処理することが理にかなっているかどうかを判断するのはユーザーの責任です。本設定が True に設定されていて、かつ RETRY_ENABLEDTrue に設定されている場合、 ResponseFailed([_DataLoss]) の失敗は通常どおり再試行されます。

警告

この設定は H2DownloadHandler ダウンロードハンドラでは無視されます (DOWNLOAD_HANDLERS を参照)。 データ損失エラーの場合、対応する HTTP/2 接続が破損し、同じ接続を使用する他のリクエストに影響を与える可能性があります。 したがって、その接続を使用していたすべてのリクエストに対して、常に ResponseFailed([InvalidBodyLengthError]) 失敗が発生します。

DUPEFILTER_CLASS

デフォルト: 'scrapy.dupefilters.RFPDupeFilter'

重複したリクエストを検出およびフィルタリングするために使用されるクラス。

デフォルト( RFPDupeFilter )は scrapy.utils.request.request_fingerprint 関数を使用してリクエストのフィンガー・プリントに基づいてフィルターします。重複のチェック方法を変更するには、 RFPDupeFilter をサブクラス化し、その request_fingerprint メソッドをオーバーライドします。このメソッドは、scrapy Request オブジェクトを受け入れ、そのフィンガー・プリント(文字列)を返す必要があります。

DUPEFILTER_CLASS'scrapy.dupefilters.BaseDupeFilter' に設定することで、重複したリクエストのフィルタリングを無効にできます。ただし、クロール・ループに入る可能性があるため、これには十分注意してください。通常、フィルタリングしない特定の Requestdont_filter パラメーターを True に設定することをお勧めします。

DUPEFILTER_DEBUG

デフォルト: False

デフォルトでは、 RFPDupeFilter は最初の重複リクエストのみを記録します。 DUPEFILTER_DEBUGTrue に設定すると、重複するすべてのリクエストがログに記録されます。

EDITOR

デフォルト: vi (Unixシステムの場合)、またはIDLEエディター(Windowsの場合)

edit コマンドでスパイダーを編集するために使用するエディター。さらに、 EDITOR 環境変数が設定されている場合、 edit コマンドはデフォルト設定よりもそれを優先します。

EXTENSIONS

デフォルト:: {}

プロジェクトで有効になっている拡張機能とその順序を含む辞書。

EXTENSIONS_BASE

デフォルト:

{
    'scrapy.extensions.corestats.CoreStats': 0,
    'scrapy.extensions.telnet.TelnetConsole': 0,
    'scrapy.extensions.memusage.MemoryUsage': 0,
    'scrapy.extensions.memdebug.MemoryDebugger': 0,
    'scrapy.extensions.closespider.CloseSpider': 0,
    'scrapy.extensions.feedexport.FeedExporter': 0,
    'scrapy.extensions.logstats.LogStats': 0,
    'scrapy.extensions.spiderstate.SpiderState': 0,
    'scrapy.extensions.throttle.AutoThrottle': 0,
}

Scrapyでデフォルトで使用可能な拡張機能とその順序を含む辞書。この設定には、すべての安定した組み込み拡張機能が含まれています。それらのいくつかは設定によって有効にする必要があることに留意してください。

詳細については、 拡張機能ユーザーガイド および 利用可能な拡張機能のリスト を参照してください。

FEED_TEMPDIR

Feed Temp dirでは、 FTPフィード・ストレージAmazon S3 でアップロードする前に、クローラーの一時ファイルを保存するカスタム・フォルダーを設定できます。

FEED_STORAGE_GCS_ACL

アイテムを Google Cloud Storage に保存するときに使用されるアクセス制御リスト (ACL)。 この値の設定方法の詳細については、 Google Cloud documentationJSON API コラムを参照してください。

FTP_PASSIVE_MODE

デフォルト: True

FTP転送を開始するときにパッシブモードを使用するかどうか。

FTP_PASSWORD

デフォルト: "guest"

Request メタに "ftp_password" がない場合にFTP接続に使用するパスワード。

注釈

RFC 1635 を意訳すると、匿名FTPにはパスワード "guest" または自分の電子メールアドレスを使用するのが一般的ですが、一部のFTPサーバーは、ユーザーの電子メールアドレスを明示的に要求し、 "guest" パスワードでのログインを許可しません。

FTP_USER

デフォルト: "anonymous"

Request メタに "ftp_user" がない場合にFTP接続に使用するユーザー名。

GCS_PROJECT_ID

デフォルト: None

Google Cloud Storage にデータを保存するときに使用されるプロジェクトID。

ITEM_PIPELINES

デフォルト: {}

使用するアイテム・パイプラインとその順序を含む辞書。 順序の値は任意ですが、0〜1000の範囲で定義するのが一般的です。 低いオーダーは高いオーダーの前に処理されます。

例:

ITEM_PIPELINES = {
    'mybot.pipelines.validate.ValidateMyItem': 300,
    'mybot.pipelines.validate.StoreMyItem': 800,
}
ITEM_PIPELINES_BASE

デフォルト: {}

Scrapyでデフォルトで有効になっているパイプラインを含む辞書。プロジェクトでこの設定を変更することは決してせず、代わりに ITEM_PIPELINES を変更してください。

LOG_ENABLED

デフォルト: True

ロギングを有効にするかどうか。

LOG_ENCODING

デフォルト: 'utf-8'

ロギングに使用するエンコード。

LOG_FILE

デフォルト: None

ログ出力に使用するファイル名。 None の場合、標準エラーが使用されます。

LOG_FORMAT

デフォルト: '%(asctime)s [%(name)s] %(levelname)s: %(message)s'

ログ・メッセージをフォーマットするための文字列。 利用可能なプレース・ホルダーの全リストについては、 Python logging documentation を参照してください。

LOG_DATEFORMAT

デフォルト: '%Y-%m-%d %H:%M:%S'

日付/時刻をフォーマットするための文字列、 LOG_FORMAT%(asctime)s プレース・ホルダーの展開。 利用可能なディレクティブのリストについては、 Python datetime documentation を参照してください。

LOG_LEVEL

デフォルト: 'DEBUG'

記録する最小レベル。 利用可能なレベルは、CRITICAL、ERROR、WARNING、INFO、DEBUG です。詳細については、ロギング(logging) を参照してください。

LOG_STDOUT

デフォルト: False

True の場合、処理のすべての標準出力(およびエラー)がログにリダイレクトされます。 たとえば、 print('hello') の場合、Scrapyログに表示されます。

LOG_SHORT_NAMES

デフォルト: False

True の場合、ログにはルート・パスのみが含まれます。 False に設定されている場合、ログ出力を担当するコンポーネントが表示されます

LOGSTATS_INTERVAL

デフォルト: 60.0

LogStats による統計の各ログ出力間の間隔(秒単位)。

MEMDEBUG_ENABLED

デフォルト: False

メモリデバッグを有効にするかどうか。

MEMDEBUG_NOTIFY

デフォルト: []

メモリ・デバッグが有効になっている場合、この設定が空でない場合、指定されたアドレスにメモリレポートが送信されます。そうでない場合、レポートはログに書き込まれます。

例:

MEMDEBUG_NOTIFY = ['user@example.com']
MEMUSAGE_ENABLED

デフォルト: True

スコープ: scrapy.extensions.memusage

メモリ使用量拡張機能を有効にするかどうか。 この拡張機能は、プロセスが使用するピークメモリを追跡します(統計に書き込みます)。また、オプションで、メモリ制限を超えたときにScrapyプロセスをシャットダウンし( MEMUSAGE_LIMIT_MB を参照)、それが発生したときに電子メールで通知することができます( MEMUSAGE_NOTIFY_MAIL を参照)。

メモリ使用量の拡張機能 参照。

MEMUSAGE_LIMIT_MB

デフォルト: 0

スコープ: scrapy.extensions.memusage

(MEMUSAGE_ENABLEDがTrueの場合、)Scrapyをシャットダウンする前に許可するメモリの最大量(メガバイト単位)。ゼロの場合、チェックは実行されません。

メモリ使用量の拡張機能 参照。

MEMUSAGE_CHECK_INTERVAL_SECONDS

デフォルト: 60.0

スコープ: scrapy.extensions.memusage

メモリ使用量拡張 は、現在のメモリ使用量と、 MEMUSAGE_LIMIT_MB および MEMUSAGE_WARNING_MB で設定された制限を一定の時間間隔でチェックします。

これにより、これらの間隔の長さが秒単位で設定されます。

メモリ使用量の拡張機能 参照。

MEMUSAGE_NOTIFY_MAIL

デフォルト: False

スコープ: scrapy.extensions.memusage

メモリ制限に達した場合に通知する電子メールのリスト。

例:

MEMUSAGE_NOTIFY_MAIL = ['user@example.com']

メモリ使用量の拡張機能 参照。

MEMUSAGE_WARNING_MB

デフォルト: 0

スコープ: scrapy.extensions.memusage

通知する警告メールを送信する前に許可するメモリの最大量(メガバイト単位)。ゼロの場合、警告は生成されません。

NEWSPIDER_MODULE

デフォルト: ''

genspider コマンドを使用して新しいスパイダーを作成するモジュール。

例:

NEWSPIDER_MODULE = 'mybot.spiders_dev'
RANDOMIZE_DOWNLOAD_DELAY

デフォルト: True

有効にすると、Scrapyはランダムな時間(0.5 * DOWNLOAD_DELAY)から(1.5 * DOWNLOAD_DELAY)の間待機し、同じWebサイトからリクエストを取得します。

このランダム化により、リクエストを分析し、リクエスト間の時間の統計的に有意な類似性を探しているサイトによってクローラーが検出される(そしてその後ブロックされる)機会が減少します。

ランダム化ポリシーは、 wget--random-wait オプションで使用されるものと同じです。

DOWNLOAD_DELAY がゼロ(デフォルト)の場合、このオプションは効果がありません。

REACTOR_THREADPOOL_MAXSIZE

デフォルト: 10

Twistedリアクター・スレッド・プール・サイズの最大制限。 これは、さまざまなScrapyコンポーネントで使用される一般的な多目的スレッド・プールです。スレッドDNSリゾルバー、BlockingFeedStorage、S3FilesStoreなどがあります。ブロッキングIOが不十分な問題が発生している場合は、この値を増やします。

REDIRECT_PRIORITY_ADJUST

デフォルト: +2

スコープ: scrapy.downloadermiddlewares.redirect.RedirectMiddleware

元のリクエストに対するリダイレクト・リクエストの優先度を調整する:

  • 正の優先度調整(デフォルト)は、より高い優先度を意味します

  • 負の優先度調整は、より低い優先度を意味します。

ROBOTSTXT_OBEY

デフォルト: False

スコープ: scrapy.downloadermiddlewares.robotstxt

有効にすると、Scrapyはrobots.txtポリシーを尊重します。 詳細については、 RobotsTxtMiddleware を参照してください。

注釈

歴史的な理由からデフォルト値は False ですが、このオプションは scrapy startproject コマンドによって生成されたsettings.pyファイルでデフォルトで有効になっています。

ROBOTSTXT_PARSER

デフォルト: 'scrapy.robotstxt.ProtegoRobotParser'

robots.txt ファイルの解析に使用するパーサー・バックエンド。詳細については、 RobotsTxtMiddleware を参照してください。

ROBOTSTXT_USER_AGENT

デフォルト: None

robots.txtファイルでの照合に使用するユーザー・エージェント文字列。 None の場合、リクエストで送信するUser-Agentヘッダーまたは USER_AGENT 設定は、(この順序で、)robots.txtファイルで使用するユーザー・エージェントを決定するために使用されます。

SCHEDULER

デフォルト: 'scrapy.core.scheduler.Scheduler'

クロールに使用するスケジューラー。

SCHEDULER_DEBUG

デフォルト: False

True に設定すると、リクエスト・スケジューラに関するデバッグ情報が記録されます。 現在、リクエストをディスクにシリアル化できない場合にログに記録されます(1回のみ)。 統計カウンター(scheduler/unserializable)は、これが発生した回数を追跡します。

ログのエントリの例:

1956-01-31 00:00:00+0800 [scrapy.core.scheduler] ERROR: Unable to serialize request:
<GET http://example.com> - reason: cannot serialize <Request at 0x9a7c7ec>
(type Request)> - no more unserializable requests will be logged
(see 'scheduler/unserializable' stats counter)
SCHEDULER_DISK_QUEUE

デフォルト: 'scrapy.squeues.PickleLifoDiskQueue'

スケジューラが使用するディスク・キューのタイプ。 他の利用可能なタイプは、 scrapy.squeues.PickleFifoDiskQueuescrapy.squeues.MarshalFifoDiskQueuescrapy.squeues.MarshalLifoDiskQueue です。

SCHEDULER_MEMORY_QUEUE

デフォルト: 'scrapy.squeues.LifoMemoryQueue'

スケジューラが使用するメモリ内キューのタイプ。その他の利用可能なタイプは、 scrapy.squeues.FifoMemoryQueue です。

SCHEDULER_PRIORITY_QUEUE

デフォルト: 'scrapy.pqueues.ScrapyPriorityQueue'

スケジューラが使用する優先度キューのタイプ。 別の利用可能なタイプは scrapy.pqueues.DownloaderAwarePriorityQueue です。 多数の異なるドメインを並行してクロールする場合、scrapy.pqueues.DownloaderAwarePriorityQueuescrapy.pqueues.ScrapyPriorityQueue よりも適切に機能します。しかし、現在 scrapy.pqueues.DownloaderAwarePriorityQueueCONCURRENT_REQUESTS_PER_IP と一緒には機能しません。

SCRAPER_SLOT_MAX_ACTIVE_SIZE

バージョン 2.0 で追加.

デフォルト: 5_000_000

処理中のレスポンス・データのソフトリミット値(バイト単位)。

処理中のすべてのレスポンスのサイズの合計がこの値を超えている間、Scrapy は新しいリクエストを処理しません。

SPIDER_CONTRACTS

デフォルト:: {}

プロジェクトで有効にされたスパイダー規約(contract)を含む辞書。スパイダーのテストに使用されます。 詳細については、 スパイダー規約(contract) を参照してください。

SPIDER_CONTRACTS_BASE

デフォルト:

{
    'scrapy.contracts.default.UrlContract' : 1,
    'scrapy.contracts.default.ReturnsContract': 2,
    'scrapy.contracts.default.ScrapesContract': 3,
}

Scrapyでデフォルトで有効になっているScrapy規約を含む辞書。プロジェクトでこの設定を変更することは決してせず、代わりに SPIDER_CONTRACTS を変更してください。詳細については、 スパイダー規約(contract) を参照してください。

SPIDER_CONTRACTS でクラス・パスに None を割り当てることで、これらの規約を無効にできます。たとえば、組み込みの ScrapesContract を無効にするには、これを settings.py に配置します:

SPIDER_CONTRACTS = {
    'scrapy.contracts.default.ScrapesContract': None,
}
SPIDER_LOADER_CLASS

デフォルト: 'scrapy.spiderloader.SpiderLoader'

SpiderLoader API を実装する必要があるスパイダーのロードに使用されるクラス。

SPIDER_LOADER_WARN_ONLY

デフォルト: False

デフォルトでは、Scrapyが SPIDER_MODULES からスパイダー・クラスをインポートしようとすると、 ImportError 例外があると大声で怒られます。けれども、 SPIDER_LOADER_WARN_ONLY = True を設定することで、この例外を黙らせて単純な警告に変えることができます。

注釈

いくつかの scrapyコマンド は、実際にはスパイダー・クラスをロードする必要がないため、この設定を True に設定して実行します(つまり、警告のみを発行し、失敗しません): scrapy runspiderscrapy settingsscrapy startprojectscrapy version

SPIDER_MIDDLEWARES

デフォルト:: {}

プロジェクトで有効になっているスパイダー・ミドルウェアとその順序を含む辞書。 詳細については、 スパイダー・ミドルウェアをアクティブにする を参照してください。

SPIDER_MIDDLEWARES_BASE

デフォルト:

{
    'scrapy.spidermiddlewares.httperror.HttpErrorMiddleware': 50,
    'scrapy.spidermiddlewares.offsite.OffsiteMiddleware': 500,
    'scrapy.spidermiddlewares.referer.RefererMiddleware': 700,
    'scrapy.spidermiddlewares.urllength.UrlLengthMiddleware': 800,
    'scrapy.spidermiddlewares.depth.DepthMiddleware': 900,
}

Scrapyでデフォルトで有効になっているスパイダー・ミドルウェアとその順序を含む辞書。 低次はエンジンに近く、高次はスパイダーに近い。 詳細については、 スパイダー・ミドルウェアをアクティブにする を参照してください。

SPIDER_MODULES

デフォルト: []

Scrapyがスパイダーを探すモジュールのリスト。

例:

SPIDER_MODULES = ['mybot.spiders_prod', 'mybot.spiders_dev']
STATS_CLASS

デフォルト: 'scrapy.statscollectors.MemoryStatsCollector'

統計収集器API を実装する必要がある統計情報の収集に使用するクラス。

STATS_DUMP

デフォルト: True

スパイダーが終了したら Scrapy stats を(Scrapyログに)ダンプします。

詳細は 統計をとる 参照。

STATSMAILER_RCPTS

デフォルト: [] (空リスト)

スパイダーがスクレイピングを完了した後、スクレイピーの統計を送信します。 詳細については、 StatsMailer を参照してください。

TELNETCONSOLE_ENABLED

デフォルト: True

telnetコンソール を有効にするかどうかを指定するブール値(当該拡張機能も有効になっている場合)。

TEMPLATES_DIR

デフォルト: Scrapyモジュール内の templates ディレクトリ

startproject コマンドで新しいプロジェクトを作成し、 genspider コマンドで新しいスパイダーを作成するときにテンプレートを探すディレクトリ。

プロジェクト名は、 project サブディレクトリ内のカスタム・ファイルまたはディレクトリの名前と競合してはいけません。

TWISTED_REACTOR

バージョン 2.0 で追加.

デフォルト: None

指定された reactor のインポート・パス。

scrapy CLI プログラムが呼び出されたときや CrawlerProcess クラスを使用するときなど、他のリアクターがまだインストールされていない場合、Scrapy はこのリアクターをインストールします。

CrawlerRunner クラスを使用している場合は、正しいリアクターを手動でインストールする必要もあります。 install_reactor() を使用してそれを行うことができます。

scrapy.utils.reactor.install_reactor(reactor_path, event_loop_path=None)[ソース]

指定されたインポート・パスで reactor をインストールします。 また、asyncio リアクターが有効な場合、指定されたインポート・パスで asyncio イベント・ループをインストールします。

リアクターがすでにインストールされている場合、 install_reactor() は効果がありません。

CrawlerRunner.__init__ は、インストールされているリアクタが TWISTED_REACTOR 設定と一致しない場合、 Exception を発生させます。 したがって、トップレベルの reactor をプロジェクトファイルにインポートし、サードパーティのライブラリをインポートすると、Scrapy は、どのリアクターがインストールされているかをチェックするときに Exception を発生させます。

Scrapyでインストールしたリアクターを使うには:

import scrapy
from twisted.internet import reactor


class QuotesSpider(scrapy.Spider):
    name = 'quotes'

    def __init__(self, *args, **kwargs):
        self.timeout = int(kwargs.pop('timeout', '60'))
        super(QuotesSpider, self).__init__(*args, **kwargs)

    def start_requests(self):
        reactor.callLater(self.timeout, self.stop)

        urls = ['http://quotes.toscrape.com/page/1']
        for url in urls:
            yield scrapy.Request(url=url, callback=self.parse)

    def parse(self, response):
        for quote in response.css('div.quote'):
            yield {'text': quote.css('span.text::text').get()}

    def stop(self):
        self.crawler.engine.close_spider(self, 'timeout')

これは Exception を発生させ、以下のようになります:

import scrapy


class QuotesSpider(scrapy.Spider):
    name = 'quotes'

    def __init__(self, *args, **kwargs):
        self.timeout = int(kwargs.pop('timeout', '60'))
        super(QuotesSpider, self).__init__(*args, **kwargs)

    def start_requests(self):
        from twisted.internet import reactor
        reactor.callLater(self.timeout, self.stop)

        urls = ['http://quotes.toscrape.com/page/1']
        for url in urls:
            yield scrapy.Request(url=url, callback=self.parse)

    def parse(self, response):
        for quote in response.css('div.quote'):
            yield {'text': quote.css('span.text::text').get()}

    def stop(self):
        self.crawler.engine.close_spider(self, 'timeout')

TWISTED_REACTOR 設定のデフォルト値は None です.これは, Scrapy が特定のリアクターをインストールしようとせず, 現在のプラットフォーム用に Twisted によって定義されたデフォルトのリアクターが使用されることを意味します。これは、下位互換性を維持し、デフォルト以外のリアクターを使用することで発生する可能性のある問題を回避するためです。

追加情報については、 Choosing a Reactor and GUI Toolkit Integration を参照してください。

URLLENGTH_LIMIT

デフォルト: 2083

スコープ: spidermiddlewares.urllength

クロールされたURLを許可する最大URL長。 この設定のデフォルト値の詳細については、 https://boutell.com/newfaq/misc/urllength.html を参照してください。

USER_AGENT

デフォルト: "Scrapy/VERSION (+https://scrapy.org)"

オーバーライドされない限り、クロール時に使用するデフォルトのUser-Agent。このユーザー・エージェントは、 ROBOTSTXT_USER_AGENT 設定が None であり、リクエストに指定されたUser-Agentヘッダーが指定されていない場合、 RobotsTxtMiddleware によっても使用されます。

他の場所で文書化された設定:

以下の設定は他の場所で文書化されています。それぞれの特定の場合をチェックして、それらを有効にして使用する方法を確認してください。

例外(Exceptions)

組み込み例外リファレンス

Scrapyに含まれるすべての例外とその使用法のリストを次に示します。

CloseSpider
exception scrapy.exceptions.CloseSpider(reason='cancelled')[ソース]

この例外は、スパイダーのクローズまたは停止を要求するスパイダーコールバックから発生する可能性があります。サポートされている引数は以下です:

パラメータ

reason (str) -- クローズの理由

例えば:

def parse_page(self, response):
    if 'Bandwidth exceeded' in response.body:
        raise CloseSpider('bandwidth_exceeded')
DontCloseSpider
exception scrapy.exceptions.DontCloseSpider[ソース]

この例外は、spider_idle シグナルハンドラーで発生させて、スパイダーが閉じないようにすることができます。

DropItem
exception scrapy.exceptions.DropItem[ソース]

アイテムの処理を停止するためにアイテム・パイプライン・ステージによって発生させる必要がある例外。 詳細については アイテム・パイプライン を参照してください。

IgnoreRequest
exception scrapy.exceptions.IgnoreRequest[ソース]

この例外は、スケジューラまたはダウンローダー・ミドルウェアによって発生し、要求を無視する必要があることを示します。

NotConfigured
exception scrapy.exceptions.NotConfigured[ソース]

一部のコンポーネントは、この例外を発生させて、無効のままにすることを示すことができます。以下のコンポーネントが含まれます:

  • 拡張機能

  • アイテム・パイプライン

  • ダウンローダー・ミドルウェア

  • スパイダー・ミドルウェア

コンポーネントの __init__ メソッドで例外を発生させる必要があります。

NotSupported
exception scrapy.exceptions.NotSupported[ソース]

この例外は、サポートされていない機能を示すために発生します。

StopDownload

バージョン 2.2 で追加.

exception scrapy.exceptions.StopDownload(fail=True)[ソース]

bytes_receivedheaders_received シグナル・ハンドラーから発生(raise)し、レスポンスのためにこれ以上バイト・データをダウンロードしないことを示します。

fail 二値論理(boolean) パラメータは、結果のレスポンスを処理するメソッドを制御します:

  • (デフォルト) fail=True の場合、リクエスト・エラーバック(errback)が呼び出されます。 レスポンス・オブジェクトは、 StopDownload 例外の response 属性として使用できます。これは、受信した Failurevalue 属性として保存されます。これは、 def errback(self, failure) として定義されたエラーバック(errback)では、 failure.value.response を介してレスポンスにアクセスできることを意味します。

  • fail=False の場合、代わりにリクエスト・コールバックが呼び出されます。

いずれ場合でも、レスポンスのボディが切り捨てられる可能性があります。ボディには、例外が発生するシグナル・ハンドラーで受信されたバイト・データを含め、例外が発生するまでに受信されたすべてのバイト・データが含まれます。 また、レスポンス・オブジェクトでは、その Response.flags 属性に "download_stopped" がセットされます。

注釈

fail はキーワード専用引数です。例えば StopDownload(False)StopDownload(True)TypeError を引き起こします。

追加情報と例については、 bytes_receivedheaders_received シグナルの文書と、 レスポンスのダウンロードの停止 トピックを参照してください。

コマンドラインツール

Scrapyプロジェクトの管理に使用するコマンドライン・ツールについて学習します。

スパイダー

Webサイトをクロールするルールを作成します。

セレクター

XPathを使用してWebページからデータを抽出します。

Scrapyシェル

対話環境で抽出コードをテストします。

アイテム

あなたがスクレイピングしたいと欲するデータを定義します。

アイテム・ローダー

抽出したデータをあなたのアイテムに入れます。

アイテム・パイプライン

スクレイピングしたデータを後処理して保存します。

フィード・エクスポート

さまざまな形式を使用して、さまざまストレージに、スクレイピングされたデータを出力します。

リクエストとレスポンス

HTTPリクエストとレスポンスを表すために使用されるクラスを理解します。

リンク抽出器(link extractors)

ページからたどるリンクを抽出する便利なクラス。

設定

Scrapyをどのように設定するか学びます。 available settings 参照。

例外(Exceptions)

Scrapyで利用可能な全ての例外とその意味

組み込み済サービス群

ロギング(logging)

注釈

scrapy.log は、Python標準ロギングの明示的な呼び出しを支援する機能とともに非推奨になりました。 新しいロギングシステムの詳細については、以下をご覧ください。

Scrapyは、イベント・ロギングに logging を使用します。 始めるための簡単な例をいくつか紹介しますが、より高度なユース・ケースについては、Pythonの組み込みロギング・システムのドキュメントを徹底的に読むことを強くお勧めします。

ロギングはそのままで機能し、 ロギング設定 にリストされているScrapy設定である程度設定できます。

Scrapyは scrapy.utils.log.configure_logging() を呼び出していくつかの妥当なデフォルトを設定し、コマンドを実行するときに ロギング設定 でそれらの設定を処理するため、スクリプトからScrapyを実行する で説明されているスクリプトからScrapyを実行している場合は、手動で呼び出すことをお勧めします。

ログ・レベル

Pythonの組み込みロギングは、特定のログメッセージの重大度を示す5つの異なるレベルを定義します。 以下は標準のもので、降順でリストされています:

  1. logging.CRITICAL - 致命的なエラーの場合(最高の重要度)

  2. logging.ERROR - 通常のエラーの場合

  3. logging.WARNING - 警告メッセージの場合

  4. logging.INFO - 情報メッセージ用

  5. logging.DEBUG - デバッグメッセージ用(最も低い重要度)

メッセージをログ出しする方法

logging.WARNING レベルを使用してメッセージをログ出しする方法の簡単な例を次に示します:

import logging
logging.warning("This is a warning")

標準の5つのレベルのいずれかでログメッセージを発行するためのショートカットがあり、引数として指定されたレベルを取る一般的な logging.log メソッドもあります。必要に応じて、さっきの例を次のように書き換えることができます:

import logging
logging.log(logging.WARNING, "This is a warning")

さらに、あなたはメッセージをカプセル化するためのさまざまなロガーを作成できます。(たとえば、一般的な方法は、モジュールごとに異なるロガーを作成することです)。 これらのロガーは独立して構成でき、階層構造が可能です。

前の例では、舞台裏でルート・ロガーを使用します。これは、特に指定がない限り、すべてのメッセージが伝播されるトップ・レベル・ロガーです。 logging ヘルパーの使用は、ルート・ロガーを明示的に取得するための単なるショートカットであるため、これは最後のコード片と同等です。

import logging
logger = logging.getLogger()
logger.warning("This is a warning")

logging.getLogger 関数で名前を取得するだけで、異なるロガーを使用できます:

import logging
logger = logging.getLogger('mycustomlogger')
logger.warning("This is a warning")

最後に、 __name__ 変数を使用して、作業中のモジュールのカスタム・ロガーを確保できます。これには、現在のモジュールのパスが入力されます:

import logging
logger = logging.getLogger(__name__)
logger.warning("This is a warning")

参考

モジュール・ロギング HowTo

基本ロギング・チュートリアル(https://docs.python.org/2/howto/logging.html)

モジュール・ロギング、 Loggers

ロガーに関する詳細なドキュメント(https://docs.python.org/2/library/logging.html#logger-objects)

スパイダーからのロギング

Scrapyは、各スパイダー・インスタンス内で logger を提供します。

import scrapy

class MySpider(scrapy.Spider):

    name = 'myspider'
    start_urls = ['https://scrapy.org']

    def parse(self, response):
        self.logger.info('Parse function called on %s', response.url)

そのロガーはスパイダーの名前を使用して作成されますが、任意のカスタムPythonロガーを使用できます。 例えば以下です:

import logging
import scrapy

logger = logging.getLogger('mycustomlogger')

class MySpider(scrapy.Spider):

    name = 'myspider'
    start_urls = ['https://scrapy.org']

    def parse(self, response):
        logger.info('Parse function called on %s', response.url)

ロギング構成(configuration)

ロガー自身は、ロガーを介して送信されたメッセージの表示方法を管理しません。 このタスクでは、さまざまなハンドラーを任意のロガー・インスタンスにアタッチして、それらのメッセージを標準出力、ファイル、電子メールなどの適切な宛先にリダイレクトします。

デフォルトでは、Scrapyは以下の設定に基づいて、ルート・ロガーのハンドラーを設定および構成します。

ロギング設定

これらの設定は、ロギングの構成(configuration)に使用できます:

最初のいくつかの設定は、ログメッセージの宛先を定義します。 LOG_FILE が設定されている場合、ルート・ロガーを介して送信されたメッセージは LOG_ENCODING エンコーディングで LOG_FILE という名前のファイルにリダイレクトされます。設定が解除され、 LOG_ENABLEDTrue の場合、ログメッセージは標準エラーに表示されます。 そして、 LOG_ENABLEDFalse の場合、目に見えるログ出力はありません。

LOG_LEVEL は表示する重大度の最小レベルを決定し、指定より重大度の低いメッセージは除外されます。 ログ・レベル にリストされている可能なレベルを範囲としています。

LOG_FORMATLOG_DATEFORMAT は、すべてのメッセージのレイアウトとして使用されるフォーマット文字列を指定します。これらの文字列には、 それぞれ、 ロギングのログ・レコード属性文書 や、 日時のstrftimeおよびstrptimeディレクティブ にリストされているプレース・ホルダーを含めることができます。

LOG_SHORT_NAMES が設定されている場合、ログはログを印刷するScrapyコンポーネントを表示しません。 デフォルトでは設定されていないため、ログにはそのログ出力の原因となるScrapyコンポーネントが含まれています。

コマンド・ライン・オプション

すべてのコマンドで使用できるコマンドライン引数があり、これを使用してロギングに関するScrapy設定の一部をオーバーライドできます。

  • --logfile FILE

    LOG_FILE をオーバーライドする

  • --loglevel/-L LEVEL

    LOG_LEVEL をオーバーライドする

  • --nolog

    LOG_ENABLEDFalse に設定

参考

モジュール logging.handlers

利用可能なハンドラーに関する詳細なドキュメント

カスタム・ログ書式

LogFormatter クラスを拡張し、 LOG_FORMATTER が新しいクラスを指すようにすることで、さまざまなアクションに対してカスタム・ログ形式を設定できます。

class scrapy.logformatter.LogFormatter[ソース]

さまざまなアクションのログメッセージを生成するためのクラス。

すべてのメソッドは、パラメーター levelmsgargs をリストする辞書を返さなければなりません。これらは、 logging.log を呼び出すときにログ・メッセージを作成するために使用されます。

メソッド出力の辞書キー:

  • level はそのアクションのログ・レベルです。 python logging library のログレベルを使用できます。それは logging.DEBUGlogging.INFOlogging.WARNINGlogging.ERRORlogging.CRITICAL です。

  • msg は異なるフォーマットのプレース・ホルダーを含むことができる文字列でなければなりません。 提供された args でフォーマットされたこの文字列は、そのアクションの長いメッセージになります。

  • args は、 msg のフォーマット・プレース・ホルダーを持つタプルまたは辞書である必要があります。最終的なログメッセージは msg % args として処理されます。

各アクションのログ方法をカスタマイズしたい場合、または完全に省略したい場合、ユーザーは独自の LogFormatter クラスを定義できます。 アクションのロギングを省略するには、メソッドは None を返す必要があります。

アイテムがパイプラインからドロップされたときにログ・メッセージの重大度を下げるためにカスタム・ログ・フォーマッタを作成する方法の例を次に示します:

class PoliteLogFormatter(logformatter.LogFormatter):
    def dropped(self, item, exception, response, spider):
        return {
            'level': logging.INFO, # lowering the level from logging.WARNING
            'msg': "Dropped: %(exception)s" + os.linesep + "%(item)s",
            'args': {
                'exception': exception,
                'item': item,
            }
        }
crawled(request, response, spider)[ソース]

クローラーがWebページを見つけたときにメッセージをログ出力します。

download_error(failure, request, spider, errmsg=None)[ソース]

スパイダーからのダウンロード・エラー・メッセージをログに記録します(通常はエンジンから送信されます)。

バージョン 2.0 で追加.

dropped(item, exception, response, spider)[ソース]

アイテムがアイテム・パイプラインを通過中にドロップされたときにメッセージをrログ出力します。

item_error(item, exception, response, spider)[ソース]

アイテムがアイテム・パイプラインを通過しているときにアイテムがエラーを引き起こしたときメッセージをログに記録します。

バージョン 2.0 で追加.

scraped(item, response, spider)[ソース]

アイテムがスパイダーによってスクレイプされたときにメッセージをログ出力します。

spider_error(failure, request, response, spider)[ソース]

スパイダーからのエラーメッセージをログに記録します。

バージョン 2.0 で追加.

高度なカスタマイズ

Scrapyはstdlibロギング・モジュールを使用するため、stdlibロギングのすべての機能を使用してロギングをカスタマイズできます。

たとえば、多くの「HTTP 404」や「HTTP 500」のレスポンスを返すWebサイトをスクレイピングしていて、このようなすべてのメッセージを非表示にしたいとします:

2016-12-16 22:00:06 [scrapy.spidermiddlewares.httperror] INFO: Ignoring
response <500 http://quotes.toscrape.com/page/1-34/>: HTTP status code
is not handled or not allowed

最初に注意することはロガー名です。角括弧内に書きます。 [scrapy.spidermiddlewares.httperror] 。単に [scrapy] を取得した場合、 LOG_SHORT_NAMES はおそらくTrueに設定されています。Falseに設定して、クロールを再実行します。

次に、メッセージにINFOレベルがあることがわかります。非表示にするには、INFOよりも高い scrapy.spidermiddlewares.httperror のログ・レベルを設定する必要があります。 INFOの次のレベルはWARNINGです。 スパイダー __init__ メソッド内でその設定を行うことができます:

import logging
import scrapy


class MySpider(scrapy.Spider):
    # ...
    def __init__(self, *args, **kwargs):
        logger = logging.getLogger('scrapy.spidermiddlewares.httperror')
        logger.setLevel(logging.WARNING)
        super().__init__(*args, **kwargs)

あなたがこのスパイダーを再度実行すると、 scrapy.spidermiddlewares.httperror ロガーからのINFOメッセージはなくなります。

LogRecord データでログ・レコードをフィルタリングすることもできます。 たとえば、文字列の部分(substring)または正規表現を使用して、メッセージの内容でログ・レコードをフィルタリングできます。 logging.Filter サブ・クラスを作成し、正規表現パターンを装備して不要なメッセージを除外します:

import logging
import re

class ContentFilter(logging.Filter):
    def filter(self, record):
        match = re.search(r'\d{3} [Ee]rror, retrying', record.message)
        if match:
            return False

Scrapyによって作成されたルート・ハンドラーにプロジェクト・レベルのフィルターをアタッチできます。これは、プロジェクトのさまざまな部分(ミドルウェア、スパイダーなど)のすべてのロガーをフィルタ処理するための便利な方法です:

import logging
import scrapy

class MySpider(scrapy.Spider):
    # ...
    def __init__(self, *args, **kwargs):
        for handler in logging.root.handlers:
            handler.addFilter(ContentFilter())

または、特定のロガーを選択して、他のロガーに影響を与えずに非表示にすることもできます:

import logging
import scrapy

class MySpider(scrapy.Spider):
    # ...
    def __init__(self, *args, **kwargs):
        logger = logging.getLogger('my_logger')
        logger.addFilter(ContentFilter())

scrapy.utils.logモジュール

scrapy.utils.log.configure_logging(settings=None, install_root_handler=True)[ソース]

Scrapyのロギングのデフォルトを初期化します。

パラメータ
  • settings (dict, Settings object or None) -- ルートロガーのハンドラーの作成と設定に使用される設定(デフォルト: None)。

  • install_root_handler (bool) -- ルート・ロギング・ハンドラーをインストールするかどうか(デフォルト: True)

この関数は以下のとおり動作します:

  • Pythonの標準ログを介したルーティング警告とtwistedのロギング

  • ScrapyおよびTwistedロガーにそれぞれDEBUGおよびERRORレベルを割り当てます

  • LOG_STDOUT設定がTrueの場合、ログは標準出力に出力されます。

install_root_handler がTrue(デフォルト)の場合、この関数は与えられた設定( ロギング設定 参照)に従ってルート・ロガーのハンドラーも作成します。 settings 引数を使用してデフォルトのオプションを上書きできます。 settings が空またはNoneの場合、デフォルトが使用されます。

configure_logging はScrapyコマンドまたは CrawlerProcess を使用すると自動的に呼び出されますが、 CrawlerRunner を使用してカスタム・スクリプトを実行する場合は明示的に呼び出す必要があります。その場合、その使用は必須ではありませんが、推奨されます。

カスタム・スクリプトを実行するときのもう1つのオプションは、ログを手動で構成することです。 これを行う時は、 logging.basicConfig() を使用して基本的なルート・ハンドラーを設定できます。

CrawlerProcess は自動的に configure_logging を呼び出すため、 CrawlerRunner と一緒に logging.basicConfig() のみを使用することをお勧めします。

以下は、INFO のメッセージをファイルにリダイレクトする方法の例です:

import logging

logging.basicConfig(
    filename='log.txt',
    format='%(levelname)s: %(message)s',
    level=logging.INFO
)

この方法でScrapyを使用する方法の詳細については、 スクリプトからScrapyを実行する を参照してください。

統計をとる

Scrapyは、値が多くの場合カウンターである、キー/値の形式で統計を収集するための便利な機能を提供します。この機能は統計収集器(Stats Collector)と呼ばれ、以下の 一般的な統計収集器を使う 節の例にあるように、 クローラーAPIstats 属性を通じてアクセスできます。

ただし、統計収集器(Stats Collector)は常に使用可能なため、統計収集が有効かどうかに関係なく、モジュールにいつでもインポートして、APIを使用(新しい統計キーをインクリメントまたは設定)できます。無効にしても、APIは機能しますが、何も収集しません。これは、統計収集器の使用を簡素化することを目的としています。スパイダー、Scrapy拡張機能、または統計収集器を使用しているコードの統計を取るために、1行以上のコードを費やす必要はありません。

統計収集器(Stats Collector)のもう1つの特色は、(有効な場合)とても効率的で、無効な場合は極めて効率的(ほとんど気付かない)だということです。

統計収集器は、開いているスパイダーごとに統計テーブルを保持します。このテーブルは、スパイダーを開くと自動的に開き、スパイダーを閉じると閉じます。

一般的な統計収集器を使う

stats 属性を介して統計収集器(stats collector)にアクセスします。統計にアクセスする拡張機能の例を次に示します:

class ExtensionThatAccessStats:

    def __init__(self, stats):
        self.stats = stats

    @classmethod
    def from_crawler(cls, crawler):
        return cls(crawler.stats)

統計値設定:

stats.set_value('hostname', socket.gethostname())

統計値加算:

stats.inc_value('custom_count')

以前より大きい場合のみ統計値設定:

stats.max_value('max_items_scraped', value)

以前より小さい場合のみ統計値設定:

stats.min_value('min_free_memory_percent', value)

統計値取得:

>>> stats.get_value('custom_count')
1

全統計取得:

>>> stats.get_stats()
{'custom_count': 1, 'start_time': datetime.datetime(2009, 7, 14, 21, 47, 28, 977139)}

利用可能な統計収集器

基本的な StatsCollector に加えて、基本的な統計収集器を拡張するScrapyで利用可能な他の統計収集器があります。 STATS_CLASS 設定を使用して、使用する統計収集器を選択できます。 使用されるデフォルトの統計収集器は MemoryStatsCollector です。

MemoryStatsCollector
class scrapy.statscollectors.MemoryStatsCollector[ソース]

スパイダーが閉じられた後、(各スパイダーの)最後のスクレイピング実行の統計をメモリに保持する単純な統計収集器。 統計は、 spider_stats 属性を介してアクセスできます。これは、スパイダー・ドメイン名をキーとする辞書です。

これは、Scrapyで使用されるデフォルトの統計収集器です。

spider_stats

各スパイダーの最後のスクレイピング実行の統計を含む(スパイダー名をキーとする)辞書の辞書

DummyStatsCollector
class scrapy.statscollectors.DummyStatsCollector[ソース]

(何もしないので)非常に効率的ですが、何もしない統計収集器。この統計収集器は、 STATS_CLASS 設定を介して設定でき、パフォーマンスを改善するために統計収集を無効にします。 ただし、統計収集のパフォーマンス・ペナルティは、通常、ページの解析などの他のScrapyワーク・ロードと比較してわずかです。

電子メールの送信

Pythonは smtplib ライブラリを介して電子メールを比較的簡単に送信できますが、Scrapyは電子メールを送信するための独自の機能を提供します。これは非常に使いやすく、クローラーの非ブロッキングIOの干渉を避けるため、 Twisted non-blocking IO を使用して実装されています。また、添付ファイルを送信するためのシンプルなAPIを提供し、いくつかの 電子メール設定 で非常に簡単に構成(configure)できます。

簡単な例

メール送信者をインスタンス化する方法は2つあります。 あなたは標準の __init__ メソッドを使用してインスタンス化する事ができます:

from scrapy.mail import MailSender
mailer = MailSender()

または、 電子メール設定 を尊重するScrapy設定オブジェクトを渡してインスタンス化できます。

mailer = MailSender.from_settings(settings)

そして、以下を使用して(添付ファイルなしで)電子メールを送信する方法があります:

mailer.send(to=["someone@example.com"], subject="Some subject", body="Some body", cc=["another@example.com"])

MailSenderクラス・リファレンス

MailSenderは、フレームワークの残りの部分と同様に、 Twisted non-blocking IO を使用するため、Scrapyから電子メールを送信するのに適したクラスです。

class scrapy.mail.MailSender(smtphost=None, mailfrom=None, smtpuser=None, smtppass=None, smtpport=None)[ソース]
パラメータ
  • smtphost (str or bytes) -- 電子メールの送信に使用するSMTPホスト。省略すると、 MAIL_HOST 設定が使用されます。

  • mailfrom (str) -- メールの送信に使用されるアドレス( From: ヘッダー内)。 省略すると、 MAIL_FROM 設定が使用されます。

  • smtpuser -- SMTPユーザー。省略すると、 MAIL_USER 設定が使用されます。指定しない場合、SMTP認証は実行されません。

  • smtppass (str or bytes) -- 認証用のSMTPパスワード

  • smtpport (int) -- 接続のためのSMTPポート番号

  • smtptls (bool) -- SMTP STARTTLSの使用を強制する

  • smtpssl (bool) -- 安全なSSL接続の使用を強制する

classmethod from_settings(settings)[ソース]

これらのScrapy電子メール設定 を尊重するScrapy設定オブジェクトを使用してインスタンス化します。

パラメータ

settings (scrapy.settings.Settings object) -- 電子メールの受信者

send(to, subject, body, cc=None, attachs=(), mimetype='text/plain', charset=None)[ソース]

指定された受信者にメールを送信します。

パラメータ
  • to (str or list) -- 文字列または文字列のリストとしての電子メール受信者

  • subject (str) -- 電子メールの件名

  • cc (str or list) -- 文字列または文字列のリストとしての電子メールのCC(カーボン・コピー宛先)

  • body (str) -- 電子メール本文

  • attachs (collections.abc.Iterable) -- タプル (attach_name, mimetype, file_object) の反復可能オブジェクト(iterable)。 ここで、 attach_name は、電子メールの添付ファイルに表示される名前の文字列で、 mimetype は添付ファイルのMIMEタイプであり、 file_object は添付ファイルの内容を含む読み取り可能なファイルオブジェクトです

  • mimetype (str) -- 電子メールのMIMEタイプ

  • charset (str) -- 電子メールのコンテンツに使用する文字エンコード

電子メール設定

これらの設定は、 MailSender クラスのデフォルトの __init__ メソッド値を定義し、コードを記述せずにプロジェクトで電子メール通知を構成するために使用できます( MailSender を使用するコードとこれらの拡張機能の場合)。

MAIL_FROM

デフォルト: 'scrapy@localhost'

電子メールの送信に使用する送信者の電子メール( From: ヘッダー)。

MAIL_HOST

デフォルト: 'localhost'

電子メールの送信に使用するSMTPホスト。

MAIL_PORT

デフォルト: 25

電子メールの送信に使用するSMTPポート。

MAIL_USER

デフォルト: None

SMTP認証に使用するユーザー。無効にすると、SMTP認証は実行されません。

MAIL_PASS

デフォルト: None

MAIL_USER とともに、SMTP認証に使用するパスワード。

MAIL_TLS

デフォルト: False

STARTTLSを使用を強制します。STARTTLSは、既存の安全でない接続を取得し、SSL/TLSを使用して安全な接続にアップグレードする方法です。

MAIL_SSL

デフォルト: False

SSL暗号化接続を使用した接続を強制する

Telnetコンソール

Scrapyには、Scrapy実行中のプロセスを検査および制御するための組み込みのtelnetコンソールが付属しています。telnetコンソールは、Scrapyプロセス内で実行される通常のpythonシェルであるため、文字通り何でもできます。

telnetコンソールは 組み込みのScrapy拡張機能 であり、デフォルトで有効になっていますが、必要に応じて無効にすることもできます。拡張機能自体の詳細については、 Telnetコンソール拡張機能 を参照してください。

警告

telnetはトランスポート層セキュリティを提供しないため、パブリック・ネットワーク経由でtelnetコンソールを使用することは安全ではありません。 ユーザー名/パスワード認証を使用しても、それは変わりません。

意図している使用方法は、実行中のScrapyスパイダーにローカル(スパイダー・プロセスとtelnetクライアントが同じマシン上にある)または安全な接続(VPN、SSHトンネル)に接続することです。安全でない接続ではtelnetコンソールを使用しないようにするか、 TELNETCONSOLE_ENABLED オプションを使用して完全に無効にしてください。

telnetコンソールにアクセスする方法

telnetコンソールは TELNETCONSOLE_PORT 設定で定義されたTCPポートでリッスンします。デフォルトは 6023 です。コンソールにアクセスするには次のように入力する必要があります:

telnet localhost 6023
Trying localhost...
Connected to localhost.
Escape character is '^]'.
Username:
Password:
>>>

デフォルトでは、ユーザー名は scrapy であり、パスワードは自動生成されます。自動生成されたパスワードは、以下の例のようにScrapyログで確認できます:

2018-10-16 14:35:21 [scrapy.extensions.telnet] INFO: Telnet Password: 16f92501e8a59326

デフォルトのユーザー名とパスワードは、設定 TELNET_CONSOLE_USERNAMETELNETCONSOLE_PASSWORD で上書きできます。

警告

telnetは安全なトランスポートを使用していないため、ユーザー名とパスワードは限定的な保護しか提供しません。デフォルトでは、ユーザー名とパスワードが設定されていてもトラフィックは暗号化されません。

Windows、およびほとんどのLinuxディストリビューションにデフォルトでインストールされるtelnetプログラムが必要です。

telnetコンソールで使用可能な変数

telnetコンソールは、Scrapyプロセス内で実行される通常のPythonシェルのように、新しいモジュールのインポートなど、あらゆる操作を行うことができます。

けれども、Telnetコンソールには、便宜上いくつかのデフォルト変数が定義されています:

ショートカット

説明

crawler

Scrapyクローラー( scrapy.crawler.Crawler オブジェクト)

engine

Crawler.engine 属性

spider

現在アクティブなスパイダー

slot

エンジン・スロット(engine slot)

extensions

拡張機能マネージャー(Crawler.extensions 属性)

stats

統計収集器(stats collector)(Crawler.stats 属性)

settings

Scrapy設定オブジェクト(Crawler.settings 属性)

est

Scrapyエンジンのステータスレポートを出力

prefs

メモリ・デバッグ用( メモリ・リークのデバッグ 参照)

p

pprint.pprint() 関数へのショートカット

hpy

メモリ・デバッグ用( メモリ・リークのデバッグ 参照)

Telnetコンソール使用例

telnetコンソールで実行できるタスクの例を次に示します:

Scrapyエンジンのステータスを表示

あなたはScrapyエンジンの est() メソッドを使用して、telnetコンソールを使用してその状態をすばやく表示できます。

telnet localhost 6023
>>> est()
Execution engine status

time()-engine.start_time                        : 8.62972998619
engine.has_capacity()                           : False
len(engine.downloader.active)                   : 16
engine.scraper.is_idle()                        : False
engine.spider.name                              : followall
engine.spider_is_idle(engine.spider)            : False
engine.slot.closing                             : False
len(engine.slot.inprogress)                     : 16
len(engine.slot.scheduler.dqs or [])            : 0
len(engine.slot.scheduler.mqs)                  : 92
len(engine.scraper.slot.queue)                  : 0
len(engine.scraper.slot.active)                 : 0
engine.scraper.slot.active_size                 : 0
engine.scraper.slot.itemproc_size               : 0
engine.scraper.slot.needs_backout()             : False
Scrapyエンジンを一時停止、再開、停止する

一時停止するためには:

telnet localhost 6023
>>> engine.pause()
>>>

(一時停止したのを)再開するためには:

telnet localhost 6023
>>> engine.unpause()
>>>

停止(再開不可)するためには:

telnet localhost 6023
>>> engine.stop()
Connection closed by foreign host.

Telnetコンソール・シグナル

scrapy.extensions.telnet.update_telnet_vars(telnet_vars)

telnetコンソールが開く直前に送信されます。この信号に接続して、telnetローカル名前空間で使用できる変数を追加、削除、または更新できます。そのためには、ハンドラーの telnet_vars 辞書を更新する必要があります。

パラメータ

telnet_vars (dict) -- telnet変数の辞書

Telnet設定

これらは、Telnetコンソールの振る舞いを制御する設定です:

TELNETCONSOLE_PORT

デフォルト: [6023, 6073]

telnetコンソールに使用するポート範囲。 None または 0 に設定すると、動的に割り当てられたポートが使用されます。

TELNETCONSOLE_HOST

デフォルト: '127.0.0.1'

telnetコンソールがリッスンするネットワーク・インターフェイス

TELNETCONSOLE_USERNAME

デフォルト: 'scrapy'

telnetコンソールに使用されるユーザー名

TELNETCONSOLE_PASSWORD

デフォルト: None

telnetコンソールに使用されるパスワード。デフォルトの動作では自動生成されます

Webサービス

webserviceは別のプロジェクトに移動しました。

以下でホストされています:

ロギング(logging)

ScrapyでPython組み込みのログ機能を使う方法を習います。

統計をとる

あなたのスクレイピング・クローラーの統計を収集します。

電子メールの送信

特定のイベントが発生したときに電子メールを送信します。

Telnetコンソール

組み込みのPythonコンソールを使って、実行している最中のクローラーを詳しく調べます。

Webサービス

Webサービスを使用してクローラーを監視および制御します。

特定の問題の解決

F.A.Q.(よくある質問と回答)

ScrapyはBeautifulSoupやlxmlと比較してどうですか?

BeautifulSouplxml は、HTMLとXMLを解析するためのライブラリです。 Scrapyは、Webサイトをクロールし、そこからデータを抽出するWebスパイダーを作成するためのアプリケーションフレームワークです。

Scrapyはデータを抽出するための組み込みメカニズムを提供します( セレクター とよばれます)が、より快適に作業できる場合は、代わりに BeautifulSoup (または lxml )を簡単に使用できます。結局のところ、それらは任意のPythonコードからインポートして使用できるライブラリを利用しているだけです。

いいかえると、 BeautifulSoup (または lxml )とScrapyを比較することは、 jinja2Django を比較するようなものです。

ScrapyでBeautifulSoupを使用できますか?

はい、できます。 上記 のように、 BeautifulSoup はScrapyコールバックでHTMLレスポンスをパースするために使用できます。 レスポンスのボディを BeautifulSoup オブジェクトに送り、必要なデータを抽出するだけです。

HTMLパーサーとして lxml を使用して、BeautifulSoup API を使用するスパイダーの例を次に示します:

from bs4 import BeautifulSoup
import scrapy


class ExampleSpider(scrapy.Spider):
    name = "example"
    allowed_domains = ["example.com"]
    start_urls = (
        'http://www.example.com/',
    )

    def parse(self, response):
        # use lxml to get decent HTML parsing speed
        soup = BeautifulSoup(response.text, 'lxml')
        yield {
            "url": response.url,
            "title": soup.h1.string
        }

注釈

BeautifulSoup はいくつかのHTML/XMLパーサーをサポートしています。利用可能なものについてはBeautifulSoupの公式ドキュメント(BeautifulSoup's official documentation) を参照してください。

ScrapyはDjangoからhogehogeを盗んだ?

たぶん。だけど、私たちはそういう言い方はしないな。 Django は素晴らしいオープンソースプロジェクトであり、従うべき例であると考えているため、Scrapyの着想を得るのに利用したんだよ。

車輪の再発明する必要はないという信念です。この信念は、オープンソースおよびフリーソフトウェアの基礎の1つであることに加えて、ソフトウェアだけでなく、ドキュメント、手順、ポリシーなどにも適用されます。したがって、各問題を自分で進めるのではなく、それらのプロジェクトからアイデアをコピーすることを選択します それが既に各問題を適切に解決しているので、私たちは解決する必要がある実際の問題に焦点を当てる事ができます。

私たちはScrapyが他のプロジェクトのインスピレーションとして役立つことを誇りに思います。 じゃんじゃん盗め!

ScrapyはHTTPプロキシ経由で動作しますか?

はい。 HTTPプロキシのサポートは、HTTPプロキシ・ダウンローダー・ミドルウェアを通じて提供されます(Scrapy 0.8以降)。 HttpProxyMiddleware を参照してください。

異なるページの属性を持つアイテムをスクレイピングするにはどうすればよいですか?

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

Scrapyがクラッシュします。「ImportError: No module named win32api」

あなたは「このツイストバグ」(this Twisted bug)のため、 pywin32 をインストールする必要があります。

スパイダーでユーザーログインをシミュレートするにはどうすればよいですか?

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

Scrapyは幅(breadth)優先または深さ(depth)優先でクロールしますか?

デフォルトでは、Scrapyは保留中のリクエストを保存するために LIFO キューを使用します。これは基本的に、DFO順序(DFO order)でクロールすることを意味します。 ほとんどの場合、この順序の方が便利です。

あなたが本当にBFO順(BFO order)でクロールしたい場合は、次の設定を行うことで実行できます:

DEPTH_PRIORITY = 1
SCHEDULER_DISK_QUEUE = 'scrapy.squeues.PickleFifoDiskQueue'
SCHEDULER_MEMORY_QUEUE = 'scrapy.squeues.FifoMemoryQueue'

保留中のリクエストが CONCURRENT_REQUESTS または CONCURRENT_REQUESTS_PER_DOMAIN または CONCURRENT_REQUESTS_PER_IP の設定値を下回っている間、これらのリクエストは同時に送信されます。その結果、クロールの最初のいくつかのリクエストが目的の順序に従うことはほとんどありません。 これらの設定を 1 に下げると、目的の順序が強制されますが、クロール全体が大幅に遅くなります。

Scrapyクローラーにメモリリークがあります。 何か私にできる事がありますか?

メモリ・リークのデバッグ 参照。

また、Pythonには Scrapyではリークしてないのにリークしてるorz で説明されている組み込みのメモリリークの問題があります。

Scrapyが消費するメモリを減らすにはどうすればよいですか?

1つ前の質問を見て下さい。

多くの許可されたドメインによるメモリエラーを防ぐにはどうすればよいですか?

allowed_domains の長いリスト(たとえば5万以上)を持つスパイダーがある場合は、デフォルトの OffsiteMiddleware スパイダーミドルウェアを カスタム スパイダー ミドルウェア に置き換えることを検討してください。 必要なメモリが少なくて済みます。 例:

  • ドメイン名が十分に類似している場合は、 allowed_domains の文字列を複雑な正規表現に結合する代わりに、あなた独自の正規表現を使用してください。

  • meet the installation requirements (インストール要件を満たす)ことができる場合は、Pythonの re の代わりに pyre2 を使用して、URLフィルタリングの正規表現をコンパイルします。 issue 1908 を参照してください。

StackOverflow の他の提案も参照してください。

注釈

詳細は scrapy.spidermiddlewares.offsite.OffsiteMiddleware を参照して下さい。

SPIDER_MIDDLEWARES = {
    'scrapy.spidermiddlewares.offsite.OffsiteMiddleware': None,
    'myproject.middlewares.CustomOffsiteMiddleware': 500,
}

スパイダーは基本HTTP認証を使用できますか?

はい。 HttpAuthMiddleware 参照。

Scrapyが母国語ではなく英語でページをダウンロードするのはなぜですか?

DEFAULT_REQUEST_HEADERS 設定をオーバーライドして、デフォルトの Accept-Language リクエスト・ヘッダーを変更してみてください。

Scrapyプロジェクトの例はどこにありますか?

参照。

プロジェクトを作成せずにスパイダーを実行できますか?

はい。 runspider コマンドを使用できます。たとえば、 my_spider.py ファイルにスパイダーが記述されている場合は、次のコマンドで実行できます:

scrapy runspider my_spider.py

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

"Filtered offsite request"(フィルターされたオフサイト要求)メッセージが表示されます。 どうすれば修正できますか?

これらのメッセージ(DEBUGレベルでログに記録される)は、必ずしも問題があることを意味するわけではないため、修正する必要はありません。

これらのメッセージは、オフサイト・スパイダー・ミドルウェアによって送出されます。オフサイト・スパイダー・ミドルウェアは、スパイダーの対象外のドメインへのリクエストをフィルター処理することを目的とするスパイダー・ミドルウェア(デフォルトで有効)です。

詳細は OffsiteMiddleware を参照して下さい。

大規模なエクスポートにJSONを使用できますか?

出力の大きさに依存します。 JsonItemExporter 文書の 警告 を参照してください。

シグナルハンドラーから(Twisted)遅延(deferred)を返すことができますか?

ハンドラーからの遅延(deferred)を返すことをサポートするシグナルもあれば、サポートしないシグナルもあります。 組み込みシグナル・リファレンス を参照して、どれがどれか確認してください。

レスポンス・ステータス・コード999の意味は何ですか?

999は、リクエストを抑制するためにYahooサイトで使用されるカスタム・レスポンス・ステータス・コードです。スパイダーで 2 (またはそれ以上)のダウンロード遅延を使用して、クロール速度を遅くしてみてください:

class MySpider(CrawlSpider):

    name = 'myspider'

    download_delay = 2

    # [ ... rest of the spider code ... ]

または、 DOWNLOAD_DELAY 設定でプロジェクトのグローバル・ダウンロード遅延を設定します。

スパイダーから pdb.set_trace() を呼び出してデバッグできますか?

はい。ただし、スパイダーによって処理されているレスポンスをすばやく分析(および変更)できるScrapyシェルを使用することもできます。これは、通常の pdb.set_trace() よりも非常に便利です。

詳細は スパイダーからシェルを呼び出してレスポンスを検査する を参照して下さい。

スクレイピングしたすべてのアイテムをJSON/CSV/XMLファイルにダンプする最も簡単な方法は?

JSONファイルにダンプするには:

scrapy crawl myspider -O items.json

CSVファイルにダンプするには:

scrapy crawl myspider -O items.csv

XMLファイルにダンプするには:

scrapy crawl myspider -O items.xml

詳細は フィード・エクスポート を参照して下さい。

いくつかのフォームで使用されているこの巨大な __VIEWSTATE パラメーターは何ですか?

__VIEWSTATE パラメーターは、ASP.NET/VB.NETで構築されたサイトで使用されます。動作の詳細については、 this page を参照してください。また、これらのサイトの1つをスクレイピングする example spider もあります。

大きなXML/CSVデータ・フィードを解析する最良の方法は何ですか?

XPathセレクターを使用して大きなフィードを解析すると、フィード全体のDOMをメモリに構築する必要があるため問題が発生する可能性があります。これは非常に遅く、大量のメモリを消費する可能性があります。

メモリ内のフィード全体を一度に解析することを避けるために、 scrapy.utils.iterators モジュールの関数 xmlitercsviter を使用できます。 実際、これはフィード・スパイダー( スパイダー 参照)が内部で使用しているものです。

Scrapyはクッキーを自動的に管理しますか?

はい、Scrapyはサーバーから送信されたクッキーを受信して追跡し、通常のWebブラウザーが行うように、後続のリクエストでそれらを送り返します。

詳細は リクエストとレスポンスCookiesMiddleware を参照下さい。

Scrapyとの間で送受信されているCookieを確認するにはどうすればよいですか?

COOKIES_DEBUG 設定を有効にします。

スパイダーに自分自身を止めるように指示するにはどうすればよいですか?

コールバックから CloseSpider 例外を発生させます。 詳細については、 CloseSpider を参照してください。

Scrapyボットがバン(BAN)されるのを防ぐにはどうすればよいですか?

バン(拒否)されるのを避ける 参照。

スパイダーを設定するには、スパイダーの引数または設定を使用する必要がありますか?

スパイダー引数設定 の両方を使用して、スパイダーを設定できます。どちらか一方を使用することを義務付ける厳密なルールはありませんが、設定は一度設定するとあまり変化しないパラメーターに適しています。一方、スパイダーの引数はスパイダーの実行ごとに頻繁に変更されることを意図しており、スパイダーを実行するには(たとえば、スパイダーの開始URLを設定するためなど、)どうせ必要になります。

例で説明するために、データをスクレイピングするためにサイトにログインする必要があるスパイダーがあり、(毎回異なる)サイトの特定のセクションからのみデータをスクレイピングしたいとします。 その場合、ログインする資格情報は設定になり、スクレイピングするセクションのURLはスパイダー引数になります。

XMLドキュメントをスクレイピングしていますが、XPathセレクターはアイテムを返しません

名前空間を削除する必要がある場合があります。 名前空間(namespace)の削除 参照。

アイテム・パイプラインでアイテムを複数のアイテムに分割する方法は?

アイテム・パイプライン は、入力アイテムごとに複数のアイテムを生成できません。 代わりに スパイダー・ミドルウェア を作成し、この目的で process_spider_output() メソッドを使用します。例えば以下です:

from copy import deepcopy

from itemadapter import is_item, ItemAdapter

class MultiplyItemsMiddleware:

    def process_spider_output(self, response, result, spider):
        for item in result:
            if is_item(item):
                adapter = ItemAdapter(item)
                for _ in range(adapter['multiply_by']):
                    yield deepcopy(item)

ScrapyはIPv6アドレスをサポートしますか?

はい、 DNS_RESOLVERscrapy.resolver.CachingHostnameResolver に設定します。 そうすることで、DNS要求に特定のタイムアウトを設定する機能が失われることに注意してください( DNS_TIMEOUT 設定の値は無視されます)。

<class 'ValueError'>: filedescriptor out of range in select() 例外はどのように扱えばいいですか?

この問題は、デフォルトのTwistedリアクターが twisted.internet.selectreactor.SelectReactor であるmacOSでブロード・クロールを実行すると発生することが報告されています( has been reported )。TWISTED_REACTOR 設定を使用すると、別のリアクターに切り替えることができます。

与えられたレスポンスのダウンロードをキャンセルするにはどうすればよいですか?

状況によっては、与えられたレスポンスのダウンロードを停止すると便利な場合があります。たとえば、レスポンスのヘッダーまたはボディの最初のバイトを調べることで、レスポンスの完全な内容が必要かどうかを判断できる場合があります。その場合、 bytes_received または headers_received シグナルにハンドラーをアタッチし、 そして StopDownload 例外を発生させることで、リソースを節約できます。 追加情報と例については、 レスポンスのダウンロードの停止 トピックを参照してください。

スパイダーのデバッグ

この文書では、スパイダーをデバッグするための最も一般的な手法について説明します。 以下のScrapyスパイダーについて考えます:

import scrapy
from myproject.items import MyItem

class MySpider(scrapy.Spider):
    name = 'myspider'
    start_urls = (
        'http://example.com/page1',
        'http://example.com/page2',
        )

    def parse(self, response):
        # <processing code not shown>
        # collect `item_urls`
        for item_url in item_urls:
            yield scrapy.Request(item_url, self.parse_item)

    def parse_item(self, response):
        # <processing code not shown>
        item = MyItem()
        # populate `item` fields
        # and extract item_details_url
        yield scrapy.Request(item_details_url, self.parse_details, cb_kwargs={'item': item})

    def parse_details(self, response, item):
        # populate more `item` fields
        return item

基本的に、これは2ページのアイテム(start_urls)をパースする単純なスパイダーです。アイテムには追加情報のある詳細ページもあるため、 Requestcb_kwargs` 機能を使用して、部分的に入力されたアイテムを渡します。

parseコマンド

スパイダーの出力を確認する最も基本的な方法は、 parse コマンドを使用することです。メソッド・レベルでスパイダーのさまざまな部分の動作を確認できます。柔軟で使いやすいという利点がありますが、メソッド内のコードをデバッグすることはできません。

特定のURLからスクレイピングされたアイテムを表示するには:

$ scrapy parse --spider=myspider -c parse_item -d 2 <item_url>
[ ... scrapy log lines crawling example.com spider ... ]

>>> STATUS DEPTH LEVEL 2 <<<
# Scraped Items  ------------------------------------------------------------
[{'url': <item_url>}]

# Requests  -----------------------------------------------------------------
[]

--verbose または -v オプションを使用すると、各深度レベルでステータスを確認できます:

$ scrapy parse --spider=myspider -c parse_item -d 2 -v <item_url>
[ ... scrapy log lines crawling example.com spider ... ]

>>> DEPTH LEVEL: 1 <<<
# Scraped Items  ------------------------------------------------------------
[]

# Requests  -----------------------------------------------------------------
[<GET item_details_url>]


>>> DEPTH LEVEL: 2 <<<
# Scraped Items  ------------------------------------------------------------
[{'url': <item_url>}]

# Requests  -----------------------------------------------------------------
[]

単一のstart_urlからスクレイプされたアイテムのチェックも、以下を使用して簡単に実現できます:

$ scrapy parse --spider=myspider -d 3 'http://example.com/page1'

Scrapyシェル

parse コマンドはスパイダーの動作を確認するのに非常に役立ちますが、受信したレスポンスと出力を表示する以外の、コールバック内で何が起こるかを確認することにはほとんど役に立ちません。 では、 parse_details が時々アイテムを受け取らない状況をデバッグするには?

shell は、そういうあなたにピッタリのツールです( スパイダーからシェルを呼び出してレスポンスを検査する 参照):

from scrapy.shell import inspect_response

def parse_details(self, response, item=None):
    if item:
        # populate more `item` fields
        return item
    else:
        inspect_response(response, self)

スパイダーからシェルを呼び出してレスポンスを検査する も参照。

ブラウザを開く

あなたが特定のレスポンスがブラウザでどのように見えるかを確認したいだけの場合は、 open_in_browser 関数を使用できます。使用方法の例を次に示します:

from scrapy.utils.response import open_in_browser

def parse_details(self, response):
    if "item name" not in response.body:
        open_in_browser(response)

open_in_browser は、その時点でScrapyが受け取ったレスポンスでブラウザーを開き、画像とスタイルが適切に表示されるように base tag を調整します。

ロギング

ロギングは、スパイダーの実行に関する情報を取得するためのもう1つの便利なオプションです。それほど便利ではありませんが、ログが再び必要になった場合に、将来のすべての実行でログを使用できるという利点があります:

def parse_details(self, response, item=None):
    if item:
        # populate more `item` fields
        return item
    else:
        self.logger.warning('No item received for %s', response.url)

詳細については ロギング(logging) 節をチェックして下さい。

スパイダー規約(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 例外が送出されます。

class scrapy.exceptions.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

よくある例

このセクションでは、Scrapyを使用する際によくある例について説明します。 これらはいくつもトピックに渡るものであり、他の特定のトピックにはあまり該当しません。

スクリプトからScrapyを実行する

あなたは scrapy crawl を介してScrapyを実行する一般的な方法の代わりに、 API を使用してスクリプトからScrapyを実行できます。

ScrapyはTwisted非同期ネットワークライブラリの上に構築されているため、Twistedリアクター内で実行する必要があることに注意してください。

あなたがスパイダーを実行するために使用できる最初のユーティリティは scrapy.crawler.CrawlerProcess です。 このクラスは、Twistedリアクターを開始し、ロギングを構成し、シャットダウン・ハンドラーを設定します。 このクラスは、すべてのScrapyコマンドで使用されるクラスです。

単一のスパイダーを実行する方法を示す例を以下に示します。

import scrapy
from scrapy.crawler import CrawlerProcess

class MySpider(scrapy.Spider):
    # Your spider definition
    ...

process = CrawlerProcess(settings={
    "FEEDS": {
        "items.json": {"format": "json"},
    },
})

process.crawl(MySpider)
process.start() # the script will block here until the crawling is finished

CrawlerProcessの辞書内の設定を定義します。 CrawlerProcess の文書を確認して、使用方法の詳細を把握してください。

あなたがScrapyプロジェクト内にいる場合は、プロジェクト内にこれらのコンポーネントをインポートするために使用できる追加のヘルパーがいくつかあります。名前を CrawlerProcess に渡してスパイダーを自動的にインポートし、 get_project_settings を使用してプロジェクト設定で Settings インスタンスを取得できます。

以下は、例として testspiders プロジェクトを使用して、それを行う方法の実際の例です。

from scrapy.crawler import CrawlerProcess
from scrapy.utils.project import get_project_settings

process = CrawlerProcess(get_project_settings())

# 'followall' is the name of one of the spiders of the project.
process.crawl('followall', domain='scrapy.org')
process.start() # the script will block here until the crawling is finished

クロール・プロセスをより詳細に制御する別のScrapyユーティリティがあります。それは scrapy.crawler.CrawlerRunner です。このクラスは、複数のクローラーを実行するための単純なヘルパーをカプセル化する薄いラッパーですが、既存のリアクターを開始したり、それに干渉したりすることはありません。

このクラスを使用すると、スパイダーをスケジュールした後にリアクターを明示的に実行する必要があります。アプリケーションがすでにTwistedを使用しており、同じリアクターでScrapyを実行する場合は、 CrawlerProcess の代わりに CrawlerRunner を使用することをお勧めします。

スパイダーが終了した後、自分でTwistedリアクターをシャットダウンする必要があることに注意してください。これは、 CrawlerRunner.crawl メソッドによって返される遅延オブジェクトにコールバックを追加することで実現できます。

以下に使用例と、 MySpider の実行が終了した後に手動でリアクターを停止するコールバックを示します。

from twisted.internet import reactor
import scrapy
from scrapy.crawler import CrawlerRunner
from scrapy.utils.log import configure_logging

class MySpider(scrapy.Spider):
    # Your spider definition
    ...

configure_logging({'LOG_FORMAT': '%(levelname)s: %(message)s'})
runner = CrawlerRunner()

d = runner.crawl(MySpider)
d.addBoth(lambda _: reactor.stop())
reactor.run() # the script will block here until the crawling is finished

同じプロセスで複数のスパイダーを実行する

デフォルトでは、あなたが scrapy crawl を実行すると、Scrapyはプロセスごとに1つのスパイダーを実行します。ただし、Scrapyは、内部API を使用して、プロセスごとに複数のスパイダーを実行することをサポートしています。

複数のスパイダーを同時に実行する例を次に示します:

import scrapy
from scrapy.crawler import CrawlerProcess

class MySpider1(scrapy.Spider):
    # Your first spider definition
    ...

class MySpider2(scrapy.Spider):
    # Your second spider definition
    ...

process = CrawlerProcess()
process.crawl(MySpider1)
process.crawl(MySpider2)
process.start() # the script will block here until all crawling jobs are finished

CrawlerRunner を使用した同じ例:

import scrapy
from twisted.internet import reactor
from scrapy.crawler import CrawlerRunner
from scrapy.utils.log import configure_logging

class MySpider1(scrapy.Spider):
    # Your first spider definition
    ...

class MySpider2(scrapy.Spider):
    # Your second spider definition
    ...

configure_logging()
runner = CrawlerRunner()
runner.crawl(MySpider1)
runner.crawl(MySpider2)
d = runner.join()
d.addBoth(lambda _: reactor.stop())

reactor.run() # the script will block here until all crawling jobs are finished

同じ例ですが、遅延オブジェクトを連鎖させてスパイダーを順番に実行します:

from twisted.internet import reactor, defer
from scrapy.crawler import CrawlerRunner
from scrapy.utils.log import configure_logging

class MySpider1(scrapy.Spider):
    # Your first spider definition
    ...

class MySpider2(scrapy.Spider):
    # Your second spider definition
    ...

configure_logging()
runner = CrawlerRunner()

@defer.inlineCallbacks
def crawl():
    yield runner.crawl(MySpider1)
    yield runner.crawl(MySpider2)
    reactor.stop()

crawl()
reactor.run() # the script will block here until the last crawl call is finished

分散クロール

Scrapyは、分散(マルチサーバー)方式でクロールを実行するための組み込み機能を提供しません。ただし、クロールを配布する方法はいくつかあり、それらは配布方法によって異なります。

多数のスパイダーがある場合、負荷を分散する明白な方法は、多くのScrapydインスタンスをセットアップし、それらの間でスパイダー実行を分散することです。

代わりに、多くのマシンで単一の(大きな)スパイダーを実行したい場合、通常行うことは、クロールするURLをパーティション分割して、各スパイダーに送信します。 具体例を次に示します:

最初に、クロールするURLのリストを準備し、それらを個別のファイル/URLに入れます:

http://somedomain.com/urls-to-crawl/spider1/part1.list
http://somedomain.com/urls-to-crawl/spider1/part2.list
http://somedomain.com/urls-to-crawl/spider1/part3.list

次に、3つの異なるScrapydサーバーで実行されるスパイダーを起動します。スパイダーはクロールするパーティションの番号を含む(スパイダー)引数 part を受け取ります:

curl http://scrapy1.mycompany.com:6800/schedule.json -d project=myproject -d spider=spider1 -d part=1
curl http://scrapy2.mycompany.com:6800/schedule.json -d project=myproject -d spider=spider1 -d part=2
curl http://scrapy3.mycompany.com:6800/schedule.json -d project=myproject -d spider=spider1 -d part=3

バン(拒否)されるのを避ける

一部のWebサイトでは、高度なレベルのさまざまなボットによるクロールを防止するための特定の手段を実装しています。これらの対策を回避することは難しい場合があり、特別なインフラストラクチャが必要になる場合があります。疑問がある場合は、(有償の)商用サポート(commercial support)に連絡することを検討してください。

これらの種類のサイトを扱う際に留意するべきいくつかのヒントは以下にあります:

  • ブラウザから取得したよく使われているユーザーエージェントのプールを使ってユーザーエージェントをローテーションします(googleでそれらのリストを取得します)

  • クッキーを無効にします( COOKIES_ENABLED 参照)

  • ダウンロード遅延(2以上)を使用します。 DOWNLOAD_DELAY 設定を参照してください。

  • 可能であれば、サイトに直接アクセスするのではなく、Googleキャッシュ(Google cache)を使用してページを取得します

  • ローテートIPのプールを使用します。 たとえば、無料のTorプロジェクト(Tor project) または ProxyMesh のような有料サービスです。オープンソースの代替手段は、 scrapoxy です。これは、独自のプロキシをアタッチできるスーパープロキシです。

  • 内部的に禁止を回避する高度に分散されたダウンローダーを使用することで、クリーンなページのパースに集中できます。そのようなダウンローダーの一例は Zyte Smart Proxy Manager です

それでもボットが禁止されるのを防ぐことができない場合は、(有償の)商用サポート(commercial support)に連絡することを検討してください。

広範なクロール

Scrapyのデフォルトは、特定のサイトをクロールするために最適化されています。 多くの場合、これらのサイトは単一のScrapyスパイダーで処理されますが、これは必要または必須ではありません(たとえば、スロー(throw)される特定のサイトを処理する汎用スパイダーがあります)。

この「フォーカスクロール」に加えて、多数の(潜在的に無制限の)ドメインをカバーする別の一般的なタイプのクロールがあり、ドメインが完全にクロールされたときまたは、実行するリクエストがなくなったときに停止するのではなく、時間またはその他の任意の制約によってのみ制限されます。これらは広範なクロール(broad crawls)と呼ばれ、検索エンジンで採用されている典型的なクローラーです。

これらは、広範なクロールでよく見られる一般的なプロパティです:

  • 特定のサイトセットではなく、多くのドメイン(多くの場合、無制限)をクロールします。

  • ドメインをクロールする必要はありません。実行するのは非現実的(または不可能)であるため、代わりにクロールを時間またはクロールされるページ数で制限します。

  • (多くの抽出ルールを持つ非常に複雑なスパイダーとは対照的に、)多くの場合、データは別の段階で後処理されることが多いため、ロジックが単純です。

  • 多くのドメインを並列してクロールします。これにより、特定のサイトの制約によって制限されないため、クロール速度が向上します(各サイトはポライトネスを尊重するためにゆっくりクロールされますが、多くのサイトが並行してクロールされます)

前述のように、Scrapyのデフォルト設定は、広範なクロールではなく、集中的なクロール用に最適化されています。ただし、非同期アーキテクチャのため、Scrapyは高速で広範なクロールを実行するのに非常に適しています。ここでは、Scrapyを使用して幅広いクロールを行う際に留意する必要があるいくつかの事項を要約し、効率的な幅広いクロールを実現するために調整するScrapy設定の具体的な提案を行います。

正しい SCHEDULER_PRIORITY_QUEUE の使用

Scrapyのデフォルトのスケジューラ優先度キューは 'scrapy.pqueues.ScrapyPriorityQueue' です。 単一ドメインクロール中に最適に機能します。多くの異なるドメインを並行してクロールするとうまく機能しません

推奨される優先度キューを適用するには:

SCHEDULER_PRIORITY_QUEUE = 'scrapy.pqueues.DownloaderAwarePriorityQueue'

並行性を高める

同時実行性は、並行して処理されるリクエストの数です。グローバル制限( CONCURRENT_REQUESTS )と、ドメイン( CONCURRENT_REQUESTS_PER_DOMAIN )またはIP( CONCURRENT_REQUESTS_PER_IP )ごとに設定できる追加の制限があります。

注釈

スケジューラの優先度キューの 広範なクロールにお勧めのキューCONCURRENT_REQUESTS_PER_IP をサポートしていません。

Scrapyのデフォルトのグローバル同時実行制限は、多くの異なるドメインを並行してクロールするのには適していないため、増やすことをお勧めします。どれだけ増やすかは、クローラーが使用できるCPUとメモリの量によって異なります。

良い出発点は 100 です:

CONCURRENT_REQUESTS = 100

しかし、それを見つけるための最良の方法は、いくつかの試行を行い、ScrapyプロセスがCPUの限界に達する同時性を特定することです。最適なパフォーマンスを得るには、CPU使用率が80〜90%の同時実行性を選択する必要があります。

並行性を高めると、メモリ使用量も増えます。メモリ使用量が懸念される場合は、それに応じてグローバル同時実行制限を下げる必要があります。

Twisted IOスレッド・プールの最大サイズを増やす

現在、Scrapyは、スレッド・プールの使用をブロックする方法でDNS解決を行います。 同時実行レベルが高いと、クロールが遅くなったり、DNSリゾルバーのタイムアウトに失敗したりすることさえあります。可能な解決策はDNSクエリを処理するスレッドの数を増やす事です。そうすれば、DNSキューはより速く処理され、接続の確立とクロール全体が高速化されます。

スレッド・プールの最大サイズを増やすには:

REACTOR_THREADPOOL_MAXSIZE = 20

あなた独自のDNSをセットアップする

複数のクロール・プロセスと単一の中央DNSがある場合、DNSサーバーに対するDoS攻撃のように動作し、ネットワーク全体の速度を低下させたり、マシンをブロックすることさえあります。この設定を回避するには、ローカルキャッシュを備えた独自のDNSサーバーと、OpenDNSやVerizonなどの大規模なDNSのアップ・ストリームを使用します。

ログレベルを下げる

広範なクロールを行う場合、多くの場合、取得するクロール・レートと検出されたエラーのみに関心があります。 これらの統計は、 INFO ログ・レベルを使用しているときにScrapyによって報告されます。 CPU資源(およびログ・ストレージ要件)を節約するために、本番環境で大規模な広範なクロールを実行するときに DEBUG ログ・レベルを使用しないでください。(広範囲の)クローラーの開発時では DEBUG レベルを使用しても問題ありません。

ログレベルを設定するには:

LOG_LEVEL = 'INFO'

クッキーを無効にする

本当に 必要がない限り、クッキーを無効にします。クッキーは、広範なクロールを実行するときに必要ない場合が多く(検索エンジンク・ローラーはそれらを無視します)、CPUサイクルを節約し、Scrapyクローラーのメモリ・フット・プリントを削減することでパフォーマンスを向上させます。

クッキーを無効にするには:

COOKIES_ENABLED = False

再試行を無効にする

失敗したHTTPリクエストを再試行すると、特にサイトが原因でレスポンスが非常に遅い(または失敗する)場合、クロールが大幅に遅くなる可能性があります。そのため、タイム・アウト・エラーが何度も再試行され、不必要にクローラー容量が他のドメインで再利用できなくなります。

再試行を無効にするには:

RETRY_ENABLED = False

ダウンロードのタイムアウトを短縮

非常に遅い接続からクロールする場合を除き(広範なクロールの場合はそうではありません)、ダウンロード・タイムアウトを減らして、スタックしたリクエストを迅速に破棄し、次のリクエストを処理するための容量を解放します。

ダウンロードのタイムアウトを短縮するには:

DOWNLOAD_TIMEOUT = 15

リダイレクトを無効にする

リダイレクトの追跡に興味がない限り、リダイレクトを無効にすることを検討してください。広範なクロールを実行する場合、リダイレクトを保存し、後のクロールでサイトを再訪するときにリダイレクトを解決するのが一般的です。これは、クロール・バッチごとにリクエストの数を一定に保つのにも役立ちます。そうしないと、リダイレクト・ループが原因で、クローラーが特定のドメインで多くのリソースを占有する可能性があります。

リダイレクトを無効にするには:

REDIRECT_ENABLED = False

「Ajaxクロール可能なページ」のクロールを有効にします

一部のページ(2013年の経験データに基づいて最大1%)は、自身をajaxクロール可能(ajax crawlable)と宣言しています。 これは、通常AJAX経由でのみ利用可能なコンテンツのプレーンHTMLバージョンを提供することを意味します。ページは2つの方法でそれを示すことができます:

  1. URLで #! を使用する - これがデフォルトの方法です;

  2. 特殊なメタ・タグを使用する - この方法は、"main"、"index"ウェブサイトページで使用されます。

Scrapyは (1) を自動的に処理します。そして、 (2) を処理するには、 AjaxCrawlMiddleware を有効にします:

AJAXCRAWL_ENABLED = True

広範なクロールを行う場合、多くの「インデックス」Webページをクロールするのが一般的です。 AjaxCrawlMiddlewareは、それらを正しくクロールするのに役立ちます。 パフォーマンスのオーバーヘッドがあるため、デフォルトではオフになっています。また、集中的なクロール(focused crawls)を有効にすることはあまり意味がありません。

BFO順でクロールする

ScrapyクロールのデフォルトはDFO順.

ただし、広範なクロールでは、ページのクロールはページの処理よりも高速になる傾向があります。その結果、未処理の初期リクエストは最終的な深さに達するまでメモリ内に留まり、メモリ使用量が大幅に増加する可能性があります。

メモリを節約するために、代わりに、 BFO順でクロール する。

メモリリークに気を配る

BFOの順序でのクロール および 並行処理の低下 に加えて、広範なクロールのメモリ使用量が多い場合、 あなたは メモリリークのデバッグ をするべきです。

指定のTwistedリアクターをインストールする

クロールがシステムの機能を超えている場合は、 TWISTED_REACTOR 設定を使用して、指定のTwistedリアクターをインストールしてみてください。

Webブラウザの開発ツールを使ってスクレイピングする

ここでは、ブラウザの開発ツールを使用してスクレイピング・プロセスを簡単にする方法に関する一般的なガイドを示します。 今日、ほとんどすべてのブラウザには Developer Tools が組み込まれています。このガイドではFirefoxを使用しますが、概念は他のブラウザにも適用できます。

このガイドでは、 quotes.toscrape.com をスクレイピングすることにより、ブラウザーの開発ツールから使用する基本的なツールを紹介します。

ライブ・ブラウザDOMの検査に関する注意事項

開発ツールはライブ・ブラウザDOMで動作するため、ページ・ソースの検査時に実際に表示されるのは元のHTMLではなく、ブラウザのクリーンアップを適用してJavascriptコードを実行した後の変更されたHTMLです。特に、Firefoxは <tbody> 要素をテーブルに追加することで知られています。一方、Scrapyは元のページのHTMLを変更しないため、XPath式で <tbody> を使用すると、データを抽出できません。

したがって、あなたは次のことに注意してください:

  • Scrapyで使用されるXPathを探すDOMの検査中にJavaScriptを無効にします(開発ツールの設定で「JavaScriptを無効化」をクリックします)

  • フルパスのXPath式を使用せず、(idclasswidth などのような)属性または contains(@href, 'image') のような識別機能に基づいた相対的で賢いパスを使用してください。

  • あなたが何をしているのか本当に理解していない限り、あなたのXPath式に <tbody> 要素を含めないでください。

ウェブサイトの検査

開発ツールの最も便利な機能はインスペクター(Inspector)機能です。これにより、Webページの基になるHTMLコードを検査できます。インスペクターをデモンストレーションするために、 quotes.toscrape.com -siteを見てみましょう。

このサイトには、特定のタグを含むさまざまな著者からの合計10個の引用と、トップ10のタグがあります。 著者、タグなどに関するメタ情報なしで、このページのすべての引用を抽出したいとしましょう。

ページのソースコード全体を表示する代わりに、引用を右クリックして「要素の検査(Q)」を選択するだけで、インスペクターが開きます。その中に次のようなものが見えるはずです:

Firefox's Inspector-tool

私たちにとって興味深い部分はこれです:

<div class="quote" itemscope="" itemtype="http://schema.org/CreativeWork">
  <span class="text" itemprop="text">(...)</span>
  <span>(...)</span>
  <div class="tags">(...)</div>
</div>

スクリーンショットで強調表示された span タグのすぐ上の最初の div にカーソルを合わせると、Webページの対応するセクションも強調表示されます。 これで私たちはセクションを得ましたが、引用テキストはどこにも見つかりません。

インスペクタの利点は、Webページのセクションとタグを自動的に展開および折りたたむことであり、読みやすさが大幅に向上します。タグの前にある矢印をクリックするか、タグを直接ダブルクリックして、タグを展開したり折りたたんだりできます。span タグを class= "text" で展開すると、クリックした引用テキストが表示されます。 Inspector を使用すると、XPathを選択した要素にコピーできます。試してみましょう。

まず、ターミナルのScrapyシェルで http://quotes.toscrape.com/ を開きます:

$ scrapy shell "http://quotes.toscrape.com/"

それからWebブラウザに戻り span タグで右クリックし、 Copy > XPath を選んで、以下のようにScrapyシェルに貼り付けします:

>>> response.xpath('/html/body/div/div[2]/div[1]/div[1]/span[1]/text()').getall()
['“The world as we have created it is a process of our thinking. It cannot be changed without changing our thinking.”']

最後に text() を追加すると、この基本セレクターで最初の引用を抽出できます。しかし、このXPathはあまり賢くありません。それは、ソースコードの html から始まる望ましいパスをたどるだけです。それでは、このXPathを少し改良できるかどうか見てみましょう:

私たちがインスペクターを再びチェックすると、展開された div タグの下に、それぞれが最初の属性と同じ属性を持つ9つの同一の div タグがあることがわかります。それらのいずれかを展開すると、最初の引用と同じ構造が表示されます。2つの span タグと1つの div タグです。 div タグ内の class="text" で各 span タグを展開し、各引用を見ることができます:

<div class="quote" itemscope="" itemtype="http://schema.org/CreativeWork">
  <span class="text" itemprop="text">
    “The world as we have created it is a process of our thinking. It cannot be changed without changing our thinking.”
  </span>
  <span>(...)</span>
  <div class="tags">(...)</div>
</div>

この知識があれば、私たちのXPathを改良できます。たどるパスの代わりに、 has-class-extension を使用して class="text" を持つすべての span タグを選択するだけです:

>>> response.xpath('//span[has-class("text")]/text()').getall()
['“The world as we have created it is a process of our thinking. It cannot be changed without changing our thinking.”',
'“It is our choices, Harry, that show what we truly are, far more than our abilities.”',
'“There are only two ways to live your life. One is as though nothing is a miracle. The other is as though everything is a miracle.”',
...]

そして、1つの単純で賢いXPathを使用して、ページからすべての引用を抽出できます。 最初のXPathにループを構築して最後の div の数を増やすこともできましたが、これは不必要に複雑であり、単に has-class("text") でXPathを構築することで、すべての引用を1行で抽出できました。

インスペクターには、ソースコードの検索や選択した要素への直接スクロールなど、他の便利な機能がたくさんあります。以下にユースケースを示しましょう:

あなたはページの Next ボタンを見つけたいとします。インスペクターの右上にある検索バーに Next と入力します。2つの結果が得られます。 最初は class="text" を持つ li タグで、2つ目は a タグのテキストです。 a タグを右クリックして、 この要素の位置にスクロール(S) を選択します。ここから リンク抽出器 を簡単に作成して、ページネーションを追跡できます。 このようなシンプルなサイトでは、要素を視覚的に見つける必要はないかもしれませんが、複雑なサイトでは この要素の位置にスクロール(S) 機能は非常に便利です。

検索バーは、CSSセレクターの検索とテストにも使用できることに注意してください。 たとえば、 span.text を検索して、すべての引用テキストを見つけることができます。全文検索の代わりに、これはページ内で class="text" を持つ span タグを正確に検索します。

ネットワーク・ツール

スクレイピング中に、ページの一部が複数のリクエストを介して動的にロードされる動的Webページに遭遇する場合があります。これは非常に難しい場合がありますが、開発ツールの「ネットワーク」ツールはこのタスクを非常に容易にします。ネットワーク・ツールをデモンストレーションするために、ページ quotes.toscrape.com/scroll を見てみましょう。

このページは基本的な quotes.toscrape.com -page に非常に似ていますが、上記の Next ボタンの代わりに、ページを下にスクロールすると自動的に新しい引用を読み込みます。先に進んでさまざまなXPathを直接試すこともできますが、代わりにScrapyシェルから別の非常に便利なコマンドをチェックします:

$ scrapy shell "quotes.toscrape.com/scroll"
(...)
>>> view(response)

ブラウザーウィンドウはWebページで開きますが、1つの重要な違いがあります。引用の代わりに、Loading... という語が付いた緑がかったバーが表示されるだけです。

Response from quotes.toscrape.com/scroll

view(response) コマンドにより、シェルまたは後でスパイダーがサーバーから受信するレスポンスを表示できます。ここでは、タイトル、ログイン・ボタン、フッターを含むいくつかの基本的なテンプレートが読み込まれていますが、引用が欠落しています。これは、引用が quotes.toscrape/scroll とは異なるリクエストからロードされていることを示しています。

「ネットワーク」タブをクリックすると、おそらく2つのエントリしか表示されません。最初に行うことは、「永続ログ」をクリックして永続ログを有効にすることです。このオプションを無効にすると、別のページに移動するたびにログが自動的にクリアされます。ログをクリアするタイミングを制御できるため、このオプションを有効にするのは良い怠慢です。

ここでページをリロードすると、ログに6つの新しいリクエストが表示されます。

Network tab with persistent logs and requests

ここでは、ページのリロード時に行われたすべてのリクエストが表示され、各リクエストとそのレスポンスを検査できます。それでは、私たちの引用がどこから来ているのかを見てみましょう:

最初に scroll という名前のリクエストをクリックします。 開発ツール画面の右側で、リクエストを検査できます。ヘッダー・タブには、URL、メソッド、IPアドレスなどのリクエスト・ヘッダーに関する詳細があります。 他のタブは無視し、レスポンス を直接クリックします。

プレビュー・ペインに表示されるのはレンダリングされたHTMLコードです。これは、シェルで view(response) を呼び出したときに見たものです。 したがって、ログ内のリクエストの typehtml です。 他のリクエストには cssjs などのタイプがありますが、興味深いのは、タイプが jsonquotes?page=1 と呼ばれるリクエストです。

このリクエストをクリックすると、リクエストURLが http://quotes.toscrape.com/api/quotes?page=1 であり、レスポンスが引用を含むJSONオブジェクトであることがわかります。 また、リクエストを右クリックして「新しいタブで開く」(Open in new tab)を開いて、概要を確認することもできます。

JSON-object returned from the quotes.toscrape API

このレスポンスにより、JSONオブジェクトを簡単にパースし、各ページにサイト上のすべての引用を取得するようリクエストすることができます。

import scrapy
import json


class QuoteSpider(scrapy.Spider):
    name = 'quote'
    allowed_domains = ['quotes.toscrape.com']
    page = 1
    start_urls = ['http://quotes.toscrape.com/api/quotes?page=1']

    def parse(self, response):
        data = json.loads(response.text)
        for quote in data["quotes"]:
            yield {"quote": quote["text"]}
        if data["has_next"]:
            self.page += 1
            url = f"http://quotes.toscrape.com/api/quotes?page={self.page}"
            yield scrapy.Request(url=url, callback=self.parse)

このスパイダーはquotes-APIの最初のページから始まります。各レスポンスで、 response.text をパースし、 data に割り当てます。 これにより、Python辞書のようにJSONオブジェクトを操作できます。 quotes を繰り返し処理し、 quote["text"] を出力します。 便利な has_next 要素が true の場合(ブラウザーに quotes.toscrape.com/api/quotes?page=10 または10より大きいページ番号をロードしてみてください)、 page 属性と新しいリクエストを生成( yield )し、インクリメントしたページ番号を url に挿入します。

より複雑なWebサイトでは、リクエストを簡単に再現するのが難しい場合があります。リクエストを機能させるにはヘッダーまたはクッキーを追加する必要があるからです。これらの場合、ネットワーク・ツールで各リクエストを右クリックし、 from_curl() メソッドを使用して同等のリクエストを生成することにより、リクエストを cURL 形式でエクスポートできます。

from scrapy import Request

request = Request.from_curl(
    "curl 'http://quotes.toscrape.com/api/quotes?page=1' -H 'User-Agent: Mozil"
    "la/5.0 (X11; Linux x86_64; rv:67.0) Gecko/20100101 Firefox/67.0' -H 'Acce"
    "pt: */*' -H 'Accept-Language: ca,en-US;q=0.7,en;q=0.3' --compressed -H 'X"
    "-Requested-With: XMLHttpRequest' -H 'Proxy-Authorization: Basic QFRLLTAzM"
    "zEwZTAxLTk5MWUtNDFiNC1iZWRmLTJjNGI4M2ZiNDBmNDpAVEstMDMzMTBlMDEtOTkxZS00MW"
    "I0LWJlZGYtMmM0YjgzZmI0MGY0' -H 'Connection: keep-alive' -H 'Referer: http"
    "://quotes.toscrape.com/scroll' -H 'Cache-Control: max-age=0'")

あるいは、そのリクエストを再作成するために必要な引数を知りたい場合、 curl_to_request_kwargs() 関数を使用して同等の引数を持つ辞書を取得できます:

scrapy.utils.curl.curl_to_request_kwargs(curl_command, ignore_unknown_options=True)[ソース]

cURLコマンド構文をリクエストkwargsに変換します。

パラメータ
  • curl_command (str) -- curlコマンドを含む文字列

  • ignore_unknown_options (bool) -- trueの場合、cURLオプションが不明な場合にのみ警告が発行されます。 それ以外の場合はエラーが発生します(デフォルト:True)。

戻り値

リクエストkwargsのディクショナリ

cURLコマンドをScrapyリクエストに変換するには、 curl2scrapy を使用することもできます。

ご覧のとおり、ネットワーク・ツールでいくつかの検査を行うことで、ページのスクロール機能の動的リクエストを簡単に複製できました。 動的ページのクロールは非常に困難な場合があり、ページは非常に複雑になる可能性がありますが、最終的には正しいリクエストを識別し、それをスパイダーで複製することになります。

動的に読み込まれたコンテンツの選択

一部のWebページは、あなたがそれらのページをWebブラウザーに読み込み後に目的のデータを表示します。 ただし、Scrapyを使用してそれらをダウンロードする場合、 selectors を使用して目的のデータに到達することはできません。

この場合、推奨されるアプローチは データ・ソースを探し、 そこからデータを抽出することです。

データ・ソースを探すのに失敗し、それでもWebブラウザから DOM を介して目的のデータにアクセスできる場合は、 JavaScriptの事前レンダリング を参照してください。

データ・ソースを探す

目的のデータを抽出するには、最初にソースの場所を見つける必要があります。

データが画像やPDFドキュメントなどの非テキストベースの形式である場合、あなたのWebブラウザの ネットワークツール を使用して、対応するリクエストを見つけ、 それを再現します。

Webブラウザーで目的のデータをテキストとして選択できる場合、データは埋め込みJavaScriptコードで定義されるか、テキストベースの形式で外部リソースからロードされます。

その場合、wgrep などのツールを使用して、そのリソースのURLを見つけることができます。

データが元のURL自体からのものであることが判明した場合、 Webページのソースコードを調べて、 データの場所を特定する必要があります。

データが別のURLからのものである場合は、 対応するリクエストを再現する必要があります。

Webページのソースコードの調査

しばしば、(DOM ではなく)Webページのソースコードを調べて、必要なデータがどこにあるかを判断する必要がある場合があります。

Scrapyが見れるWebページのコンテンツをダウンロードするためにScrapyの fetch コマンドを使用しください。:

scrapy fetch --nolog https://example.com > response.html

目的のデータが <script/> 要素内の埋め込みJavaScriptコードにある場合は、 JavaScriptコードのパース を参照してください。

目的のデータが見つからない場合は、まず、Scrapyだけで見つからないのではないことを確認します。curlwget などのHTTPクライアントでもWebページをダウンロードしてみて、取得したレスポンスで情報が見つかるかどうかを確認します。

他のHTTPクライアントで目的のデータがあるレスポンスを受け取った場合、そのHTTPクライアントと同じになるようにあなたのScrapyの Request を変更します。 たとえば、同じユーザーエージェント文字列(USER_AGENT) または同じ headers にします。

目的のデータなしのレスポンスが返される場合は、リクエストをウェブブラウザのリクエストにより近いものにするための手順を実行する必要があります。 リクエストの再現 を参照してください。

リクエストの再現

しばしば、Webブラウザが実行する方法でリクエストを再現する必要がある場合があります。

Webブラウザーの ネットワーク・ツール を使用して、Webブラウザーが目的のリクエストをどのように実行するかを確認し、Scrapyでそのリクエストを再現してください。

同じHTTPメソッドとURLで Request を生成すれば十分かもしれません。ただし、そのリクエストの本文、ヘッダー、フォームパラメーター(FormRequest 参照)を再現する必要がある場合もあります。

すべての主要なブラウザはリクエストを cURL 形式でエクスポートできるため、Scrapyは from_curl() メソッドを組み込んで、cURLコマンドから同等の Request を生成します。 詳細については、ネットワークツール節内の request from curl を参照してください。

あなたが期待するレスポンスを取得したら、あなたは 目的のデータをそこから抽出する事 ができます。

Scrapyでリクエストを再現できます。 けれども、必要なすべてのリクエストを再現することは、開発時には効率的でないように見える場合があります。 もしあなたがそのような場合に遭遇し、そして、クロール速度があなたにとって大きな関心事ではない場合は、代わりに JavaScriptの事前レンダリング を検討することもできます。

予想されるレスポンスが時々は得られるが、常にではない場合、問題はおそらくリクエストではなく、ターゲットサーバーにあります。 ターゲットサーバーはバグがあるか、過負荷であるか、または 禁止 リクエストの一部です。

cURLコマンドをScrapyリクエストに変換するには、 curl2scrapy を使用できます。

さまざまなレスポンス形式の処理

あなたが目的のデータを含むレスポンスを取得した後、そこから目的のデータを抽出する方法は、レスポンスのタイプによって異なります。

  • レスポンスがHTMLまたはXMLの場合、通常どおり セレクター を使用します。

  • 応答がJSONの場合、 json.loads() を使用して、response.text から目的のデータをロードします:

    data = json.loads(response.text)
    

    目的のデータがJSONデータに埋め込まれたHTMLまたはXMLコード内にある場合、そのHTMLまたはXMLコードを Selector にロードして、それから、いつものように セレクター を使います。

    selector = Selector(data['html'])
    
  • 応答がJavaScript、または目的のデータを含む <script/> 要素を持つHTMLの場合、 JavaScriptコードのパース を参照してください。

  • レスポンスがCSSの場合、 正規表現 を使用して response.text から目的のデータを抽出します。

  • レスポンスが画像または画像に基づく別の形式(PDFなど))の場合、レスポンスを レスポンス・ボディ からバイトとして読み取り、OCRソリューションを使用してテキストとして目的のデータを抽出します。

    たとえば、 pytesseract を使用できます。 PDFから表を読むには、 tabula-py がより良い選択かもしれません。

  • レスポンスがSVG、または目的のデータを含む埋め込みSVGを含むHTMLの場合、SVGはXMLに基づいているため、 セレクター を使用して目的のデータを抽出できます。

    そうでない場合は、SVGコードをラスターイメージに変換し、 ラスターイメージ処理 を行う必要があります。

JavaScriptコードのパース

目的のデータがJavaScriptでハードコーディングされている場合、最初にJavaScriptコードを取得する必要があります。:

  • JavaScriptコードがJavaScriptファイルにある場合は、単に response.text から読み取ります。

  • JavaScriptコードがHTMLページの <script/> 要素内にある場合、 セレクター を使用して、その <script/> 要素内のテキストを抽出します。

あなたがJavaScriptコードを含む文字列を取得したら、そこから目的のデータを抽出できます。:

  • 正規表現 を使用してJSON形式で目的のデータを抽出し、 json.loads() でパースできる場合があります。

    たとえば、JavaScriptコードに var data = {"field": "value"}; のような個別の行が含まれている場合、次のようにそのデータを抽出できます:

    >>> pattern = r'\bvar\s+data\s*=\s*(\{.*?\})\s*;\s*\n'
    >>> json_data = response.css('script::text').re_first(pattern)
    >>> json.loads(json_data)
    {'field': 'value'}
    
  • chompjs は、JavaScriptオブジェクトをパースして dict に格納するAPIを提供します。

    たとえば、JavaScriptコードに var data = {field: "value", secondField: "second value"}; が含まれている場合、以下のようにしてそのデータを抽出できます:

    >>> import chompjs
    >>> javascript = response.css('script::text').get()
    >>> data = chompjs.parse_js_object(javascript)
    >>> data
    {'field': 'value', 'secondField': 'second value'}
    
  • それ以外の場合は、js2xml を使用してJavaScriptコードをXML文書に変換し、 セレクター を使用して解析できます。

    たとえば、JavaScriptコードに var data = {field: "value"}; が含まれている場合、以下のようにしてそのデータを抽出できます:

    >>> import js2xml
    >>> import lxml.etree
    >>> from parsel import Selector
    >>> javascript = response.css('script::text').get()
    >>> xml = lxml.etree.tostring(js2xml.parse(javascript), encoding='unicode')
    >>> selector = Selector(text=xml)
    >>> selector.css('var[name="data"]').get()
    '<var name="data"><object><property name="field"><string>value</string></property></object></var>'
    

JavaScriptの事前レンダリング

追加のリクエストからデータを取得するウェブページでは、目的のデータを含むリクエストを再現することをお勧めします。 多くの場合、その努力は、最小のパース時間とネットワーク転送で構造化された完全なデータという結果で報われます。

けれども、特定のリクエストを再現するのが非常に難しい場合があります。 または、Webブラウザーで表示されるWebページのスクリーンショットなど、リクエストで提供できないものが必要な場合があります。

これらの場合、シームレスな統合のために、 Splash JavaScriptレンダリングサービス(https://github.com/scrapinghub/splash)と scrapy-splash (https://github.com/scrapinghub/splash)を使用します。

スプラッシュはHTMLとしてWebページの DOM を返すため、 セレクター でパースできます。 configuration または scripting を介して大きな柔軟性を提供します。

以前に記述されたスクリプトを使用する代わりに、PythonコードからオンザフライでDOMと対話する、または複数のWebブラウザーウィンドウを処理するなど、Splashが提供する以上のものが必要な場合は、 代わりに ヘッドレス ブラウザ を使用する必要があります。

ヘッドレスブラウザ(headless browser)の使用

ヘッドレスブラウザー(headless browser)は、自動化のためのAPIを提供する特別なWebブラウザーです。

Scrapyでヘッドレスブラウザを使用する最も簡単な方法は、シームレスな統合のために scrapy-selenium (https://github.com/clemfromspace/scrapy-selenium)とともに Selenium (https://www.seleniumhq.org/)を使用することです。( scrapy-selenium 0.0.7 README邦訳 https://gist.github.com/kuma35/37d0c6c80af7d5d0e1d01edce30027f1#file-readme-jp-md )

メモリ・リークのデバッグ

Scrapyでは、リクエスト、レスポンス、アイテムなどのオブジェクトの寿命は有限です。それらは作成され、しばらく使用され、最終的に破棄されます。

これらすべてのオブジェクトの中で、Requestはおそらく最も長い寿命を持つものです。それを処理するまでスケジューラのキューで待機しているためです。 詳細については、 アーキテクチャ概観 を参照してください。

これらのScrapyオブジェクトには(かなり長い)寿命があるため、それらを適切に解放せずにメモリに蓄積してしまい、「メモリ・リーク」と呼ばれるものを引き起こすリスクが常にあります。

メモリリークのデバッグを支援するために、Scrapyは trackref というオブジェクト参照を追跡するための組み込みメカニズムを提供します。また、 muppy というサードパーティ・ライブラリを使用すると、より高度なメモリ・デバッグが可能になります(詳細は以下を参照)。両方のメカニズムは、Telnetコンソール から使用する必要があります。

メモリ・リークの一般的な原因

Scrapy開発者がリクエストで参照されるオブジェクトを渡し(たとえば、 cb_kwargs または meta 属性またはリクエスト・コールバック関数の使用)、そして、事実上、それらの参照されたオブジェクトの寿命をリクエストの寿命に合わせます。これは、Scrapyプロジェクトでのメモリ・リークの最も一般的な原因であり、初心者にとってデバッグが非常に難しいものです。

大きなプロジェクトでは、スパイダーは通常、異なる人々によって作成され、それらのスパイダーの一部は漏出(leak)する可能性があり、したがって、同時に実行されると他の(ちゃんと書かれた)スパイダーに次々に影響を与え、クロール・プロセス全体に影響を与えます。

(以前に割り当てられた)リソースを適切に解放していない場合、作成したカスタムミドルウェア、パイプライン、または拡張機能からもリークが発生する可能性があります。たとえば、spider_opened でリソースを割り当てても、 spider_closed でリソースを解放しないと、プロセスごとに複数のスパイダー を実行している場合に問題が発生する可能性があります。

リクエストが多すぎるのか?

デフォルトでは、Scrapyはリクエスト・キューをメモリに保持します。 Request オブジェクトとRequest属性で参照されるすべてのオブジェクト(例 cb_kwargsmeta )。必ずしもリークではありませんが、これには大量のメモリが必要になる場合があります。 永続ジョブ・キュー を有効にすると、メモリ使用量を制御できます。

trackref を使用したメモリ・リークのデバッグ

trackref は、メモリ・リークの最も一般的なケースをデバッグするためにScrapyが提供するモジュールです。基本的に、すべての、生存中の、リクエスト、レスポンス、アイテム、セレクター・オブジェクトへの参照を追跡します。

telnetコンソールに入り、 print_live_refs() のエイリアスである prefs() 関数を使用して、(上記のクラスの)オブジェクトが現在何個生きているかを検査することができます。

telnet localhost 6023

>>> prefs()
Live References

ExampleSpider                       1   oldest: 15s ago
HtmlResponse                       10   oldest: 1s ago
Selector                            2   oldest: 0s ago
FormRequest                       878   oldest: 7s ago

ご覧のとおり、このレポートには各クラスの最も古いオブジェクトの「年齢」も表示されます。プロセスごとに複数のスパイダーを実行している場合、最も古い要求または応答を調べることで、どのスパイダーがリークしているかを把握できます。 get_oldest() 関数を使用して(telnetコンソールから)各クラスの最も古いオブジェクトを取得できます。

どのオブジェクトが追跡されますか?

trackrefs によって追跡されるオブジェクトはすべてこれらのクラス(およびそのすべてのサブクラス)からのものです:

実例

メモリ・リークの仮定ケースの具体例を見てみましょう。 以下のようなスパイダーがあるとします:

return Request(f"http://www.somenastyspider.com/product.php?pid={product_id}",
               callback=self.parse, cb_kwargs={'referer': response})

この例は、レスポンスの寿命をリクエストの寿命と効果的に結び付けるレスポンス参照をリクエスト内に渡しているため、間違いなくメモリ・リークが発生します。

trackref ツールを使用して、原因を(もちろん、事前に知らないものとして)発見する方法を見てみましょう。

クローラーが数分間実行され、メモリー使用量が大幅に増加したことに気付いたら、telnetコンソールに入り、生存中の参照(Live References)を確認できます:

>>> prefs()
Live References

SomenastySpider                     1   oldest: 15s ago
HtmlResponse                     3890   oldest: 265s ago
Selector                            2   oldest: 0s ago
Request                          3878   oldest: 250s ago

レスポンスはリクエストと比較して比較的短い寿命であるはずなので、非常に多くの生存中のレスポンスが存在するという事実(そしてそれらが非常に古いという事実)は間違いなく疑わしいです。レスポンスの数はリクエストの数と似ているため、何らかの形で結び付けられているように見えます。これで、スパイダーのコードを調べて、リークを生成している厄介な当該コード(リクエスト内でレスポンス参照を渡している)を発見できます。

生存中オブジェクトに関する追加情報が役立つ場合があります:

>>> from scrapy.utils.trackref import get_oldest
>>> r = get_oldest('HtmlResponse')
>>> r.url
'http://www.somenastyspider.com/product.php?pid=123'

最も古いオブジェクトを取得する代わりに、すべてのオブジェクトを反復処理する場合は、 scrapy.utils.trackref.iter_all() 関数を使用できます:

>>> from scrapy.utils.trackref import iter_all
>>> [r.url for r in iter_all('HtmlResponse')]
['http://www.somenastyspider.com/product.php?pid=123',
 'http://www.somenastyspider.com/product.php?pid=584',
...]
スパイダーが多すぎるのか?

プロジェクトで並行して実行されるスパイダーが多すぎる場合、 prefs() の出力は読みにくい場合があります。このため、その関数には、特定のクラス(およびそのすべてのサブクラス)を無視するために使用できる ignore 引数があります。たとえば、以下はスパイダーへの生存中参照を表示しません:

>>> from scrapy.spiders import Spider
>>> prefs(ignore=Spider)
scrapy.utils.trackref モジュール

trackref モジュールで利用可能な関数は以下のとおりです。

class scrapy.utils.trackref.object_ref[ソース]

trackref モジュールを使用して生存中のインスタンスを追跡する場合は、このクラスから継承します。

scrapy.utils.trackref.print_live_refs(class_name, ignore=NoneType)[ソース]

クラス名でグループ化された生存中参照のレポートを出力します。

パラメータ

ignore (type or tuple) -- 指定された場合、指定されたクラス(またはクラスのタプル)からのすべてのオブジェクトは無視されます。

scrapy.utils.trackref.get_oldest(class_name)[ソース]

指定されたクラス名で生きている最も古いオブジェクトを返すか、見つからない場合は None を返します。最初に print_live_refs() を使用して、クラス名ごとに追跡されているすべての生存中のオブジェクトのリストを取得します。

scrapy.utils.trackref.iter_all(class_name)[ソース]

指定されたクラス名で生きているすべてのオブジェクトのイテレータを返します。見つからない場合は None を返します。最初に print_live_refs() を使用して、クラス名ごとに追跡されているすべての生存中のオブジェクトのリストを取得します。

muppyを使ってメモリ・リークをデバッグする

trackref は、メモリ・リークを追跡するための非常に便利なメカニズムを提供しますが、メモリリークを引き起こす可能性が高いオブジェクトのみを追跡します。 ただし、他の(多かれ少なかれ不明瞭な)オブジェクトからメモリ・リークが発生する場合があります。そうした場合に trackref を使用してリークを見つけることができない場合でも、muppyライブラリという別の方法があります。

Pympler からmuppyを使用できます。

pip を使用する場合、次のコマンドでmuppyをインストールできます:

pip install Pympler

muppyを使用してヒープ内で使用可能なすべてのPythonオブジェクトを表示する例を次に示します:

>>> from pympler import muppy
>>> all_objects = muppy.get_objects()
>>> len(all_objects)
28667
>>> from pympler import summary
>>> suml = summary.summarize(all_objects)
>>> summary.print_(suml)
                               types |   # objects |   total size
==================================== | =========== | ============
                         <class 'str |        9822 |      1.10 MB
                        <class 'dict |        1658 |    856.62 KB
                        <class 'type |         436 |    443.60 KB
                        <class 'code |        2974 |    419.56 KB
          <class '_io.BufferedWriter |           2 |    256.34 KB
                         <class 'set |         420 |    159.88 KB
          <class '_io.BufferedReader |           1 |    128.17 KB
          <class 'wrapper_descriptor |        1130 |     88.28 KB
                       <class 'tuple |        1304 |     86.57 KB
                     <class 'weakref |        1013 |     79.14 KB
  <class 'builtin_function_or_method |         958 |     67.36 KB
           <class 'method_descriptor |         865 |     60.82 KB
                 <class 'abc.ABCMeta |          62 |     59.96 KB
                        <class 'list |         446 |     58.52 KB
                         <class 'int |        1425 |     43.20 KB

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

Scrapyではリークしてないのにリークしてるorz

Scrapyプロセスのメモリ使用量は増加するだけで、決して減少しないことに気付く場合があります。 残念ながら、Scrapyもプロジェクトもメモリをリークしていなくても、これは起こり得ます。これは、Pythonの(あまりよくない)既知の問題が原因であり、場合によっては解放されたメモリをオペレーティングシステムに返さないことがあります。 この問題の詳細については以下を参照して下さい。

this paper で詳しく説明されている、エヴァン・ジョーンズによって提案された改善点は、Python 2.5に統合されましたが、これは問題を軽減するだけで、完全には修正しません。 当該箇所を引用すると:

残念ながら、このパッチは、オブジェクトが割り当てられていない場合にのみアリーナを解放できます。これは、断片化が大きな問題であることを意味します。アプリケーションには、すべてのアリーナに散らばった数メガバイトの空きメモリがありますが、どれも解放できません。これは、すべてのメモリ・アロケータで発生する問題です。これを解決する唯一の方法は、メモリ内のオブジェクトを移動できる圧縮ガベージコレクタに移動することです。これには、Pythonインタープリターの大幅な変更が必要になります。

メモリ消費を適切に保つために、ジョブをいくつかの小さなジョブに分割するか、 永続ジョブ・キュー を有効にして、スパイダーを時々停止/開始できます。

ファイルと画像のダウンロードおよび処理

Scrapyは、特定のアイテムに添付されたファイルをダウンロードするための再利用可能な アイテム・パイプライン を提供します(たとえば、製品をスクレイピングし、画像をローカルにダウンロードする場合)。 これらのパイプラインは少しの機能と構造を共有します(メディア・パイプラインと呼びます)が、通常はファイル・パイプラインまたは画像パイプラインを使用します。

両方のパイプラインは以下の機能を実装しています:

  • 最近ダウンロードした媒体の再ダウンロードを避ける

  • メディアの保存場所の指定(ファイル・システム・ディレクトリ、FTPサーバ、Amazon S3バケット、Google Cloud Storageバケット)

画像パイプラインには、画像を処理するためのいくつかの追加機能があります:

  • ダウンロードしたすべての画像を共通の形式(JPG)とモード(RGB)に変換する

  • サムネイル生成

  • 画像の幅/高さをチェックして、最小の制約を満たしていることを確認します

パイプラインは、現在ダウンロードがスケジュールされている媒体URLの内部キューを保持し、到着したレスポンスのうち、同じ媒体を含むレスポンスをそのキューに接続します。これにより、複数のアイテムで共有されている場合に同じ媒体を複数回ダウンロードすることがなくなります。

ファイル・パイプラインの使用

FilesPipeline を使用する場合の典型的なワークフローは次のようになります:

  1. Spiderでは、アイテムをスクレイプし、目的のURLを file_urls フィールドに入れます。

  2. アイテムはスパイダーから返され、アイテム・パイプラインに送られます。

  3. アイテムが FilesPipeline に到達すると、 file_urls フィールドのURLは標準のScrapyスケジューラーとダウンローダー(スケジューラーとダウンローダーのミドルウェアが再利用されることを意味します)を使用してダウンロード用にスケジュールされます。しかし、他のページの処理より高い優先度で、他のページがスクレイピングされる前にダウンロード用の処理を行います。ファイルのダウンロードが完了する(または何らかの理由で失敗する))まで、アイテムはその特定のパイプライン・ステージでロックされたままになります。

  4. ファイルがダウンロードされると、別のフィールド( files )に結果が入力されます。このフィールドには、ダウンロードしたパスと、スクレイプされた元のURL( file_urls フィールドから取得)と、ファイルのチェックサムと、ファイルのステータス、のような、ダウンロードしたファイルに関する情報を含む辞書(dict)のリストが含まれます。 files フィールドのリストにあるファイルは、 元の file_urls フィールドと同じ順序を保持します。ファイルのダウンロードに失敗した場合、エラーがログに記録され、ファイルは files フィールドに存在しません。

画像パイプラインの使用

ImagesPipeline を使用することは、使用されるデフォルトのフィールド名が異なることを除き FilesPipeline を使用することとよく似ています。あなたがアイテムの画像URLに image_urls を使用すると、ダウンロードした画像に関する情報が images フィールドに入力されます。

画像ファイルに ImagesPipeline を使用する利点は、サムネイルの生成やサイズに基づいた画像のフィルタリングなどの追加機能を設定できることです。

画像パイプラインには Pillow 4.0.0 以降が必要です。 これは、画像のサムネイル化と JPEG/RGB 形式への正規化に使用されます。

あなたのメディア・パイプラインを有効にする

メディア・パイプラインを有効にするには、まずプロジェクトに ITEM_PIPELINES 設定を追加する必要があります。

画像パイプラインを使うには:

ITEM_PIPELINES = {'scrapy.pipelines.images.ImagesPipeline': 1}

ファイル・パイプラインを使うには:

ITEM_PIPELINES = {'scrapy.pipelines.files.FilesPipeline': 1}

注釈

ファイルと画像のパイプラインの両方を同時に使用することもできます。

次に、ダウンロードした画像の保存に使用される有効な値でターゲット・ストレージ設定を構成(configure)します。 そうしないと、パイプラインは ITEM_PIPELINES 設定に含めても無効のままになります。

ファイル・パイプラインの場合、 FILES_STORE 設定を設定します:

FILES_STORE = '/path/to/valid/dir'

画像パイプラインの場合、 IMAGES_STORE 設定を設定します:

IMAGES_STORE = '/path/to/valid/dir'

サポートされるストレージ

ファイル・システム・ストレージ

ファイルは、ファイル名のURLから生成する SHA1 hash を使用して保存されます。

たとえば、次の画像URL:

http://www.example.com/image.jpg

SHA1 hash は:

3afec3b4765f8f0a07b78f98c07b83f013567a0a

ダウンロードされ、以下のファイルに保存されます:

<IMAGES_STORE>/full/3afec3b4765f8f0a07b78f98c07b83f013567a0a.jpg

ここで:

  • <IMAGES_STORE> は、画像パイプラインの IMAGES_STORE 設定で定義されているディレクトリです。

  • `` full`` は、(使用する場合)サムネイルから完全な画像を分離するためのサブディレクトリです。詳細は 画像のサムネイル生成 を参照。

FTPサーバ・ストレージ

バージョン 2.0 で追加.

FILES_STOREIMAGES_STORE はFTPサーバを指し示すことができます。Scrapyはファイルをサーバーに自動的にアップロードします。

FILES_STOREIMAGES_STORE 以下のいずれかの形式で記述しなければなりません:

ftp://username:password@address:port/path
ftp://address:port/path

usernamepassword が指定されていない場合、それぞれ FTP_USER 設定や FTP_PASSWORD 設定から取得されます。

FTPは、アクティブまたはパッシブの2つの異なる接続モードをサポートします。 Scrapyはデフォルトでパッシブ接続モードを使用します。 代わりにアクティブ接続モードを使用するには、 FEED_STORAGE_FTP_ACTIVE 設定を True に設定します。

Amazon S3 ストレージ

botocore 1.4.87 以上がインストールされていれば、FILES_STOREIMAGES_STORE はAmazon S3バケットを表すことができます。 Scrapyは自動的にファイルをバケットにアップロードします。

たとえば、以下は有効な IMAGES_STORE 値です:

IMAGES_STORE = 's3://bucket/images'

あなたは FILES_STORE_S3_ACLIMAGES_STORE_S3_ACL 設定によって定義される、保存されたファイルに使用されるアクセス制御リスト(ACL)ポリシーを変更できます。デフォルトでは、ACLは private に設定されています。ファイルを公開するには、 public-read ポリシーを使用します:

IMAGES_STORE_S3_ACL = 'public-read'

詳細については、Amazon S3開発者ガイドの canned ACLs を参照してください。

あなたは他のS3のようなストレージも使用できます。自己ホスト型の Minios3.scality のようなストレージです。あなたがする必要があるのはScrapy設定でendpointオプションを設定することです:

AWS_ENDPOINT_URL = 'http://minio.example.com:9000'

セルフホスティングの場合は、SSLを使用する必要はなく、SSL接続を確認する必要もないと感じるかもしれません:

AWS_USE_SSL = False # or True (None by default)
AWS_VERIFY = False # or True (None by default)
Google Cloud ストレージ

FILES_STOREIMAGES_STORE は、Google Cloud Storageバケットを表すことができます。Scrapyは自動的にファイルをバケットにアップロードします( google-cloud-storage が必要です)。

たとえば、以下は有効な IMAGES_STORE および GCS_PROJECT_ID 設定です:

IMAGES_STORE = 'gs://bucket/images/'
GCS_PROJECT_ID = 'project_id'

認証については、この documentation を参照してください。

FILES_STORE_GCS_ACL および IMAGES_STORE_GCS_ACL 設定によって定義される、保存されたファイルに使用されるアクセス制御リスト(ACL)ポリシーを変更できます。デフォルトでは、ACLは '' (空の文字列)に設定されます。これは、Cloud Storageがバケットのデフォルト・オブジェクトACLをオブジェクトに適用することを意味します。ファイルを公開するには、 publicRead ポリシーを使用します:

IMAGES_STORE_GCS_ACL = 'publicRead'

詳細については、Google Cloud Platform Developer Guide の Predefined ACLs を参照してください。

使用例

メディア・パイプラインを使用するには、まず、 メディア・パイプラインを有効にする を行います。

次に、スパイダーがURLフィールド(file_urls (ファイル・パイプラインの場合) または image_urls (画像パイプラインの場合)) を含む アイテム・オブジェクト を返すならば、そのパイプラインは結果をそれぞれのフィールド (files または images) の下に配置します。

フィールドが事前に定義されている アイテム型 を使用する場合は、URLフィールドと結果フィールドの両方を定義する必要があります。 たとえば、画像パイプラインを使用する場合、アイテムは image_urls フィールドと images フィールドの両方を定義しなければなりません。 たとえば、 Item クラスを使用します:

import scrapy

class MyItem(scrapy.Item):
    # ... other item fields ...
    image_urls = scrapy.Field()
    images = scrapy.Field()

URLキーまたは結果キーに別のフィールド名を使用する場合は、それをオーバーライドすることもできます。

ファイル・パイプラインでは、 FILES_URLS_FIELD and/or FILES_RESULT_FIELD 設定を設定します:

FILES_URLS_FIELD = 'field_name_for_your_files_urls'
FILES_RESULT_FIELD = 'field_name_for_your_processed_files'

画像パイプラインでは、 IMAGES_URLS_FIELD and/or IMAGES_RESULT_FIELD 設定を設定します:

IMAGES_URLS_FIELD = 'field_name_for_your_images_urls'
IMAGES_RESULT_FIELD = 'field_name_for_your_processed_images'

より複雑なものが必要で、カスタム・パイプラインの動作をオーバーライドする場合は、 メディア・パイプラインの拡張 を参照してください。

ImagePipelineを継承する複数の画像パイプラインがあり、あなたが異なるパイプラインで異なる設定を行いたい場合は、パイプライン・クラス名を大文字化した名前を先頭に付けた設定キーを設定できます。例えば、パイプラインの名前がMyPipelineで、カスタムIMAGES_URLS_FIELDが必要な場合は、設定MYPIPELINE_IMAGES_URLS_FIELDを定義すると、カスタム設定が使用されます。

追加機能

ファイルの有効期限

画像パイプラインは、最近ダウンロードされたファイルのダウンロードを回避します。この保持遅延を調整するには、 FILES_EXPIRES (または、画像パイプラインの場合は IMAGES_EXPIRES )設定を使用します。これは、日数で保持遅延を指定します:

# 120 days of delay for files expiration
FILES_EXPIRES = 120

# 30 days of delay for images expiration
IMAGES_EXPIRES = 30

両方の設定のデフォルト値は90日です。

FilesPipelineをサブクラス化するパイプラインがあり、それに対して別の設定が必要な場合は、クラス名を大文字化した名前を先頭に付けた設定キーを設定できます。例えば、パイプラインの名前がMyPipelineで、カスタムFIlE_EXPIERSが必要な場合は、以下のように設定すると、カスタム設定が使用されます。

MYPIPELINE_FILES_EXPIRES = 180

こうすると、パイプライン・クラスMyPipelineの有効期限は180に設定されます。

画像のサムネイル生成

画像Pipelineは、ダウンロードした画像のサムネイルを自動的に作成できます。

この機能を使用するには、 IMAGES_THUMBS を辞書に設定する必要があります。ここで、キーはサムネイル名であり、値はその寸法です。

例えば:

IMAGES_THUMBS = {
    'small': (50, 50),
    'big': (270, 270),
}

この機能を使用すると、画像パイプラインは指定された各サイズのサムネイルをこの形式で作成します:

<IMAGES_STORE>/thumbs/<size_name>/<image_id>.jpg

ここで:

  • <size_name>IMAGES_THUMBS 辞書キーで指定されたもの( smallbig など)です

  • <image_id> は画像のURLの SHA1 hash です

small および big のサムネイル名を使用して保存された画像ファイルの例:

<IMAGES_STORE>/full/63bbfea82b8880ed33cdb762aa11fab722a90a24.jpg
<IMAGES_STORE>/thumbs/small/63bbfea82b8880ed33cdb762aa11fab722a90a24.jpg
<IMAGES_STORE>/thumbs/big/63bbfea82b8880ed33cdb762aa11fab722a90a24.jpg

最初のものは、サイトからダウンロードされたフル画像です。

小さな画像を除外する

画像パイプラインを使用する場合、 IMAGES_MIN_HEIGHT および IMAGES_MIN_WIDTH 設定で最小許容サイズを指定することにより、小さすぎる画像をドロップできます。

例えば:

IMAGES_MIN_HEIGHT = 110
IMAGES_MIN_WIDTH = 110

注釈

サイズの制約は、サムネイルの生成にはまったく影響しません。

1つのサイズ制約または両方を設定することができます。両方を設定すると、両方の最小サイズを満たす画像のみが保存されます。上記の例では、サイズが(105×105)または(105×200)または(200×105)の画像はすべて削除されます。これは、少なくとも1つの寸法が制約よりも短いためです。

デフォルトでは、サイズの制限はないため、すべての画像が処理されます。

リダイレクトを許可する

デフォルトでは、メディア・パイプラインはリダイレクトを無視します。つまり、メディア・ファイルURLリクエストへのHTTPリダイレクトは、メディアのダウンロードが失敗したと見なされることを意味します。

メディアのリダイレクトを処理するには、この設定を True に設定します:

MEDIA_ALLOW_REDIRECTS = True

メディア・パイプラインの拡張

ここで、カスタム・ファイル・パイプラインでオーバーライドできるメソッドを参照してください:

class scrapy.pipelines.files.FilesPipeline[ソース]
file_path(self, request, response=None, info=None, *, item=None)[ソース]

このメソッドは、ダウンロードされたアイテムごとに1回呼び出されます。 指定された response から始まるファイルのダウンロード・パスを返します。

response に加えて、このメソッドは元の requestinfoitem を受け取ります。

このメソッドをオーバーライドして、各ファイルのダウンロード・パスをカスタマイズできます。

たとえば、ファイルのURLが通常のパスのように終わる場合(例 https://example.com/a/b/c/foo.png )、次のアプローチを使用して、全てのファイルを元のファイル(例 files/foo.png)で files フォルダーにダウンロードできます:

import os
from urllib.parse import urlparse

from scrapy.pipelines.files import FilesPipeline

class MyFilesPipeline(FilesPipeline):

    def file_path(self, request, response=None, info=None, *, item=None):
        return 'files/' + os.path.basename(urlparse(request.url).path)

同様に、 item を使用して、アイテムのプロパティに基づいてファイル・パスを決定できます。

デフォルトでは file_path() メソッドは full/<request URL hash>.<extension> を返します。

バージョン 2.4 で追加: アイテム パラメータ。

get_media_requests(item, info)[ソース]

ワークフローにあるように、パイプラインはアイテムからダウンロードする画像のURLを取得します。これを行うには、 get_media_requests() メソッドをオーバーライドして、各ファイルURLのリクエストを返すことができます:

from itemadapter import ItemAdapter

def get_media_requests(self, item, info):
    adapter = ItemAdapter(item)
    for file_url in adapter['file_urls']:
        yield scrapy.Request(file_url)

これらのリクエストはパイプラインによって処理され、ダウンロードが完了すると、結果が item_completed() メソッドに2要素タプルのリストとして送信されます。各タプルには (success, file_info_or_error) が含まれます:

  • success は、画像が正常にダウンロードされた場合は True であるブール値であり、何らかの理由で失敗した場合は False です

  • file_info_or_error は、(success True の場合)以下のキーを含む辞書です。問題が発生した場合は Failure です。

    • url - ファイルのダウンロード元のURL。これは get_media_requests() メソッドから返されるリクエストのURLです。

    • path - ファイルが保存されたパス( FILES_STORE への相対パス)

    • checksum - 画像コンテンツのMD5ハッシュ(MD5 hash)

    • status - ファイル・ステータスの表示。

      バージョン 2.2 で追加.

      以下のいずれかになります:

      • downloaded - ダウンロードされたファイル。

      • uptodate - それは最近ダウンロードされたことがあるため、ファイルの有効期限ポリシーに従って、ファイルはダウンロードされませんでした。

      • cached - 同一のファイルを共有している別のアイテムによって、ファイルのダウンロードがすでにスケジュールされていました。

item_completed() が受け取るタプルのリストは、 get_media_requests() メソッドから返されたリクエストと同じ順序を保持することが保証されています。

以下は results 引数の典型的な値です:

[(True,
  {'checksum': '2b00042f7481c7b056c4b410d28f33cf',
   'path': 'full/0a79c461a4062ac383dc4fade7bc09f1384a3910.jpg',
   'url': 'http://www.example.com/files/product1.pdf',
   'status': 'downloaded'}),
 (False,
  Failure(...))]

デフォルトでは、 get_media_requests() メソッドは None を返します。これは、アイテムにダウンロードするファイルがないことを意味します。

item_completed(results, item, info)[ソース]

FilesPipeline.item_completed() メソッドは、1つのアイテムに対するすべてのファイルリクエストが完了した(ダウンロードが完了したか、何らかの理由で失敗した)ときに呼び出されます。

item_completed() メソッドは、後続のアイテム・パイプライン・ステージに送信される出力を返す必要があるため、パイプラインの場合と同様に、アイテムを返す(またはドロップする)必要があります。

以下は item_completed() メソッドの例で、(結果で渡された)ダウンロードしたファイル・パスを file_paths アイテム・フィールドに保存し、ファイルが含まれていない場合はアイテムをドロップします:

from itemadapter import ItemAdapter
from scrapy.exceptions import DropItem

def item_completed(self, results, item, info):
    file_paths = [x['path'] for ok, x in results if ok]
    if not file_paths:
        raise DropItem("Item contains no files")
    adapter = ItemAdapter(item)
    adapter['file_paths'] = file_paths
    return item

デフォルトでは、 item_completed() メソッドはアイテムを返します:

カスタム画像パイプラインでオーバーライドできるメソッドをご覧ください:

class scrapy.pipelines.images.ImagesPipeline[ソース]

ImagesPipelineFilesPipeline の拡張であり、フィールド名をカスタマイズして画像のカスタム動作を追加します。

file_path(self, request, response=None, info=None, *, item=None)[ソース]

このメソッドは、ダウンロードされたアイテムごとに1回呼び出されます。 指定された response から始まるファイルのダウンロード・パスを返します。

response に加えて、このメソッドは元の requestinfoitem を受け取ります。

このメソッドをオーバーライドして、各ファイルのダウンロード・パスをカスタマイズできます。

たとえば、ファイルのURLが通常のパスのように終わる場合(例 https://example.com/a/b/c/foo.png )、次のアプローチを使用して、全てのファイルを元のファイル(例 files/foo.png)で files フォルダーにダウンロードできます:

import os
from urllib.parse import urlparse

from scrapy.pipelines.images import ImagesPipeline

class MyImagesPipeline(ImagesPipeline):

    def file_path(self, request, response=None, info=None, *, item=None):
        return 'files/' + os.path.basename(urlparse(request.url).path)

同様に、 item を使用して、アイテムのプロパティに基づいてファイル・パスを決定できます。

デフォルトでは file_path() メソッドは full/<request URL hash>.<extension> を返します。

バージョン 2.4 で追加: アイテム パラメータ。

get_media_requests(item, info)[ソース]

FilesPipeline.get_media_requests() メソッドと同じように機能しますが、画像のURLに異なるフィールド名を使用します。

各画像URLのリクエストを返す必要があります。

item_completed(results, item, info)[ソース]

ImagesPipeline.item_completed() メソッドは、1つのアイテムに対するすべての画像リクエストが完了した(ダウンロードが完了したか、何らかの理由で失敗した)ときに呼び出されます。

FilesPipeline.item_completed() メソッドと同じように機能しますが、画像のダウンロード結果を保存するために異なるフィールド名を使用します。

デフォルトでは、 item_completed() メソッドはアイテムを返します:

カスタム画像パイプライン例

上記で例示されたメソッドについて、以下に画像パイプラインの完全な例を示します:

import scrapy
from itemadapter import ItemAdapter
from scrapy.exceptions import DropItem
from scrapy.pipelines.images import ImagesPipeline

class MyImagesPipeline(ImagesPipeline):

    def get_media_requests(self, item, info):
        for image_url in item['image_urls']:
            yield scrapy.Request(image_url)

    def item_completed(self, results, item, info):
        image_paths = [x['path'] for ok, x in results if ok]
        if not image_paths:
            raise DropItem("Item contains no images")
        adapter = ItemAdapter(item)
        adapter['image_paths'] = image_paths
        return item

カスタム・メディア・パイプライン・コンポーネントを有効にするには、以下例のように、クラス・インポート・パスを ITEM_PIPELINES 設定に追加する必要があります:

ITEM_PIPELINES = {
    'myproject.pipelines.MyImagesPipeline': 300
}

スパイダーのデプロイ

この節では、Scrapyスパイダーをデプロイして定期的に実行するためのさまざまなオプションについて説明します。ローカルマシンでScrapyスパイダーを実行することは(初期の)開発段階には非常に便利ですが、長時間実行されるスパイダーを実行したり、スパイダーを動かして実稼働で実行する必要がある場合はそれほど便利ではありません。そこで、Scrapyスパイダーをデプロイするためのソリューションの出番です。

Scrapyスパイダーをデプロイするための一般的な選択肢は以下の通りです:

Scrapydサーバへのデプロイ

Scrapyd は、Scrapyスパイダーを実行するためのオープン・ソース・アプリケーションです。Scrapyスパイダーを実行および監視できるHTTP APIをサーバーに提供します。

スパイダーをScrapydにデプロイするには、 scrapyd-client パッケージで提供されるscrapyd-deployツールを使用できます。 詳細については、 scrapyd-deploy documentation を参照してください。

Scrapydは、一部のScrapy開発者によって管理されています。

Zyte Scrapyクラウドへのデプロイ

Zyte Scrapy Cloud は、Scrapyの後ろだてとなっている会社である Zyte によってクラウドベースのサービスとしてホストされています。

Zyte Scrapyクラウドは、サーバーをセットアップおよび監視する必要をなくし、スパイダーを管理し、スクレイプされたアイテム、ログ、および統計を確認するための素晴らしいUIを提供します。

スパイダーをZyte Scrapy Cloudにデプロイするには、 shub コマンドラインツールを使用できます。詳細については、 Zyte Scrapy Cloud documentation を参照してください。

Zyte ScrapyクラウドはScrapydと互換性があり、必要に応じてそれらを切り替えることができます。設定は scrapyd-deploy と同様に scrapy.cfg ファイルから読み込まれます。

AutoThrottle拡張機能

これは、ScrapyサーバーとクロールするWebサイトの両方の負荷に基づいて、クロール速度を自動的に落とすための拡張機能です。

設計目標

  1. デフォルト・ゼロのダウンロード遅延を使用する代わりに、サイトに優しくする

  2. Scrapyを最適なクロール速度に自動的に調整するので、ユーザーは最適なものを見つけるためにダウンロードの遅延を調整する必要がありません。 ユーザーは、許可する同時要求の最大数を指定するだけでよく、拡張機能が残りを行います。

仕組み

AutoThrottle拡張機能はダウンロード遅延を動的に調整して、スパイダーが各リモートWebサイトに平均的に AUTOTHROTTLE_TARGET_CONCURRENCY 並列リクエストを送信するようにします。

ダウンロード遅延を使用して遅延を計算します。主なアイデアは次のとおりです。サーバーが応答するのに latency 秒が必要な場合、クライアントは latency/N 秒ごとにリクエストを送信して、N 個のリクエストを並行して処理する必要があります。

遅延を調整する代わりに、小さな固定ダウンロード遅延を設定し、 CONCURRENT_REQUESTS_PER_DOMAIN または CONCURRENT_REQUESTS_PER_IP オプションを使用して同時実行に厳しい制限を課すことができます。この2つは同様の効果を提供しますが、いくつかの重要な違いがあります:

  • ダウンロードの遅延が小さいため、リクエストのバーストがときどき発生します;

  • 多くの場合、200以外の(エラー)レスポンスは通常のレスポンスよりも速く返される可能性があるため、サーバーがエラーを返し始めると、ダウンロード遅延が小さく、ハード同時実行制限のクローラーがサーバーにリクエストをより速く送信します。 しかし、これはクローラーが行うべきことの反対です。エラーが発生した場合、速度を落とすのがより理にかなっています。これらのエラーはリクエスト率が高いことが原因である可能性があります。

AutoThrottleにはこれらの問題はありません。

速度を絞るアルゴリズム

AutoThrottleアルゴリズムは、次のルールに基づいてダウンロード遅延を調整します:

  1. スパイダーは常に AUTOTHROTTLE_START_DELAY のダウンロード遅延で始まります;

  2. レスポンスが受信されると、ターゲットのダウンロード遅延は latency / N として計算されます。 latency は応答の遅延であり、 NAUTOTHROTTLE_TARGET_CONCURRENCY です。

  3. 次のリクエストのダウンロード遅延は、以前のダウンロード遅延とターゲット・ダウンロード遅延の平均に設定されます;

  4. 200以外のレスポンスのレイテンシ(latency)では、遅延を減らすことはできません;

  5. ダウンロードの遅延が DOWNLOAD_DELAY よりも小さくなったり、 AUTOTHROTTLE_MAX_DELAY よりも大きくなったりすることはできません

注釈

AutoThrottle拡張機能は、並列性と遅延の標準的なScrapy設定を優先します。これは、 CONCURRENT_REQUESTS_PER_DOMAINCONCURRENT_REQUESTS_PER_IP オプションを尊重し、かつ、 DOWNLOAD_DELAY よりも低いダウンロード遅延を設定しないことを意味します。

Scrapyでは、ダウンロードの遅延は、TCP接続の確立からHTTPヘッダーの受信までの経過時間として測定されます。

Scrapyは、例えば、スパイダー・コールバックの処理に忙しいとダウンロードに参加できないため、これらのレイテンシ(latency)を協調マルチタスク環境で正確に測定するのは非常に難しいことに注意してください。 ただし、これらのレイテンシ(latency)は、Scrapy(および最終的にはサーバー)がどれだけビジー(busy)であるかの妥当な推定値を提供する必要があり、この拡張機能はその前提に基づいています。

設定

AutoThrottle拡張機能の制御に使用される設定は次のとおりです:

詳細については 仕組み を参照してください。

AUTOTHROTTLE_ENABLED

デフォルト: False

AutoThrottle拡張機能を有効にします。

AUTOTHROTTLE_START_DELAY

デフォルト: 5.0

初期ダウンロード遅延(秒単位)。

AUTOTHROTTLE_MAX_DELAY

デフォルト: 60.0

待ち時間が長い場合に設定される最大ダウンロード遅延(秒単位)。

AUTOTHROTTLE_TARGET_CONCURRENCY

デフォルト: 1.0

ScrapyがリモートWebサイトに並列して送信するリクエストの平均数。

デフォルトでは、AutoThrottleは遅延を調整して、各リモートWebサイトに単一の同時リクエストを送信します。 このオプションをより高い値(例: 2.0 )に設定すると、リモート・サーバーのスループットと負荷が増加します。 AUTOTHROTTLE_TARGET_CONCURRENCY の値(例: 0.5 )が低いと、クローラーはより保守的で礼儀正しくなります。

AutoThrottle拡張機能が有効になっている場合、 CONCURRENT_REQUESTS_PER_DOMAIN および CONCURRENT_REQUESTS_PER_IP オプションは引き続き尊重されることに注意してください。つまり、 AUTOTHROTTLE_TARGET_CONCURRENCYCONCURRENT_REQUESTS_PER_DOMAIN または CONCURRENT_REQUESTS_PER_IP よりも高い値に設定されている場合、クローラーはこの同時リクエスト数に到達しません。

指定されたすべての時点で、Scrapyは AUTOTHROTTLE_TARGET_CONCURRENCY よりも多いまたは少ない同時リクエストを送信できます。クローラーが接近しようとする推奨値であり、ハードリミットではありません。

AUTOTHROTTLE_DEBUG

デフォルト: False

AutoThrottleデバッグモードを有効にすると、受信したすべてのレスポンスの統計が表示されるため、スロットル・パラメーターがリアルタイムでどのように調整されているかを確認できます。

ベンチマーキング

Scrapyには、ローカルHTTPサーバーを生成し、可能な最大速度でクロールする単純なベンチマーキング・スイートが付属しています。 このベンチマークの目標は、ハードウェアでScrapyがどのように機能するかを把握し、比較のための共通のベースラインを得ることにあります。 何もせず、リンクをたどるシンプルなスパイダーを使用します。

その実行は:

scrapy bench

次のような出力が表示されるはずです:

2016-12-16 21:18:48 [scrapy.utils.log] INFO: Scrapy 1.2.2 started (bot: quotesbot)
2016-12-16 21:18:48 [scrapy.utils.log] INFO: Overridden settings: {'CLOSESPIDER_TIMEOUT': 10, 'ROBOTSTXT_OBEY': True, 'SPIDER_MODULES': ['quotesbot.spiders'], 'LOGSTATS_INTERVAL': 1, 'BOT_NAME': 'quotesbot', 'LOG_LEVEL': 'INFO', 'NEWSPIDER_MODULE': 'quotesbot.spiders'}
2016-12-16 21:18:49 [scrapy.middleware] INFO: Enabled extensions:
['scrapy.extensions.closespider.CloseSpider',
 'scrapy.extensions.logstats.LogStats',
 'scrapy.extensions.telnet.TelnetConsole',
 'scrapy.extensions.corestats.CoreStats']
2016-12-16 21:18:49 [scrapy.middleware] INFO: Enabled downloader middlewares:
['scrapy.downloadermiddlewares.robotstxt.RobotsTxtMiddleware',
 'scrapy.downloadermiddlewares.httpauth.HttpAuthMiddleware',
 'scrapy.downloadermiddlewares.downloadtimeout.DownloadTimeoutMiddleware',
 'scrapy.downloadermiddlewares.defaultheaders.DefaultHeadersMiddleware',
 'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware',
 'scrapy.downloadermiddlewares.retry.RetryMiddleware',
 'scrapy.downloadermiddlewares.redirect.MetaRefreshMiddleware',
 'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware',
 'scrapy.downloadermiddlewares.redirect.RedirectMiddleware',
 'scrapy.downloadermiddlewares.cookies.CookiesMiddleware',
 'scrapy.downloadermiddlewares.stats.DownloaderStats']
2016-12-16 21:18:49 [scrapy.middleware] INFO: Enabled spider middlewares:
['scrapy.spidermiddlewares.httperror.HttpErrorMiddleware',
 'scrapy.spidermiddlewares.offsite.OffsiteMiddleware',
 'scrapy.spidermiddlewares.referer.RefererMiddleware',
 'scrapy.spidermiddlewares.urllength.UrlLengthMiddleware',
 'scrapy.spidermiddlewares.depth.DepthMiddleware']
2016-12-16 21:18:49 [scrapy.middleware] INFO: Enabled item pipelines:
[]
2016-12-16 21:18:49 [scrapy.core.engine] INFO: Spider opened
2016-12-16 21:18:49 [scrapy.extensions.logstats] INFO: Crawled 0 pages (at 0 pages/min), scraped 0 items (at 0 items/min)
2016-12-16 21:18:50 [scrapy.extensions.logstats] INFO: Crawled 70 pages (at 4200 pages/min), scraped 0 items (at 0 items/min)
2016-12-16 21:18:51 [scrapy.extensions.logstats] INFO: Crawled 134 pages (at 3840 pages/min), scraped 0 items (at 0 items/min)
2016-12-16 21:18:52 [scrapy.extensions.logstats] INFO: Crawled 198 pages (at 3840 pages/min), scraped 0 items (at 0 items/min)
2016-12-16 21:18:53 [scrapy.extensions.logstats] INFO: Crawled 254 pages (at 3360 pages/min), scraped 0 items (at 0 items/min)
2016-12-16 21:18:54 [scrapy.extensions.logstats] INFO: Crawled 302 pages (at 2880 pages/min), scraped 0 items (at 0 items/min)
2016-12-16 21:18:55 [scrapy.extensions.logstats] INFO: Crawled 358 pages (at 3360 pages/min), scraped 0 items (at 0 items/min)
2016-12-16 21:18:56 [scrapy.extensions.logstats] INFO: Crawled 406 pages (at 2880 pages/min), scraped 0 items (at 0 items/min)
2016-12-16 21:18:57 [scrapy.extensions.logstats] INFO: Crawled 438 pages (at 1920 pages/min), scraped 0 items (at 0 items/min)
2016-12-16 21:18:58 [scrapy.extensions.logstats] INFO: Crawled 470 pages (at 1920 pages/min), scraped 0 items (at 0 items/min)
2016-12-16 21:18:59 [scrapy.core.engine] INFO: Closing spider (closespider_timeout)
2016-12-16 21:18:59 [scrapy.extensions.logstats] INFO: Crawled 518 pages (at 2880 pages/min), scraped 0 items (at 0 items/min)
2016-12-16 21:19:00 [scrapy.statscollectors] INFO: Dumping Scrapy stats:
{'downloader/request_bytes': 229995,
 'downloader/request_count': 534,
 'downloader/request_method_count/GET': 534,
 'downloader/response_bytes': 1565504,
 'downloader/response_count': 534,
 'downloader/response_status_count/200': 534,
 'finish_reason': 'closespider_timeout',
 'finish_time': datetime.datetime(2016, 12, 16, 16, 19, 0, 647725),
 'log_count/INFO': 17,
 'request_depth_max': 19,
 'response_received_count': 534,
 'scheduler/dequeued': 533,
 'scheduler/dequeued/memory': 533,
 'scheduler/enqueued': 10661,
 'scheduler/enqueued/memory': 10661,
 'start_time': datetime.datetime(2016, 12, 16, 16, 18, 49, 799869)}
2016-12-16 21:19:00 [scrapy.core.engine] INFO: Spider closed (closespider_timeout)

これは、Scrapyを実行するあなたのハードウェアで1分あたり約3000ページをクロールできることを示しています。 これは、リンクをたどることを目的とした非常に単純なスパイダーであることに注意してください。作成するカスタム・スパイダーは、おそらくより多くの処理を行うため、クロール速度が遅くなります。 どれだけ遅くなるかは、スパイダーがどれだけ行うかと、それがどれだけうまく書かれているかに依存します。

より複雑なベンチマークには scrapy-bench を使用してください。

ジョブ制御: クロールの一時停止と再開

大きなサイトでは、クロールを一時停止して後で再開できることが望ましい場合があります。

Scrapyは、以下の機構を提供することにより、この機能をいち早くサポートしています:

  • スケジュールされたリクエストをディスクに保持するスケジューラー

  • 訪問したリクエストをディスク上に保持する重複フィルター

  • バッチ間でいくつかのスパイダーの状態(キー/値のペア)を保持する拡張機能

Jobディレクトリ

永続性サポートを有効にするには、 JOBDIR 設定で jobディレクトリ を定義するだけです。このディレクトリは、単一のジョブ(スパイダー実行など)の状態を維持するために必要なすべてのデータを保存するためのものです。このディレクトリは、単一ジョブ の状態を保存するために使用されるため、異なるスパイダー、または同じスパイダーの異なる job/run でさえ共有してはならないことに注意することが重要です。

使い方

永続性サポートを有効にしてスパイダーを起動するには、次のように実行します:

scrapy crawl somespider -s JOBDIR=crawls/somespider-1

その後、いつでも(Ctrl-Cを押すかシグナルを送信することにより)スパイダーを安全に停止し、同じコマンドを発行して後で再開できます:

scrapy crawl somespider -s JOBDIR=crawls/somespider-1

バッチ間で永続的な状態を維持する

時々、一時停止/再開バッチ間で永続的なスパイダー状態を維持したい場合があります。 それには spider.state 属性を使用できます。これは辞書である必要があります。スパイダーが開始および停止するときに、ジョブ・ディレクトリからの属性のシリアル化、保存、および読み込みを処理する組み込みの拡張機能があります。

スパイダー状態を使用するコールバックの例を次に示します(簡潔にするため、他のスパイダー・コードは省略されています):

def parse_item(self, response):
    # parse item here
    self.state['items_count'] = self.state.get('items_count', 0) + 1

永続性サポートあるある

Scrapy永続性サポートを使用できるようにしたい場合、留意すべきことがいくつかあります:

クッキーの有効期限

クッキーの有効期限が切れる場合があります。 そのため、スパイダーをすぐに再開しないと、スケジュールされたリクエストが機能しなくなる可能性があります。 スパイダーがクッキーに依存していない場合、これは問題になりません。

リクエストのシリアル化

永続性が機能するためには、 __init__ メソッドに渡される callbackerrback の値を除いて、 Request オブジェクトは pickle シリアル化可能である必要があります。 これは、実行中の Spider クラスのメソッドである必要があります。

シリアル化できなかったリクエストをログに記録したい場合、プロジェクトの設定ページで SCHEDULER_DEBUG 設定を True に設定できます。デフォルトでは False です。

コルーチン

バージョン 2.0 で追加.

Scrapy は、 コルーチン構文部分的にサポート しています。

呼び出し可能オブジェクト(callable)サポート

以下の呼び出し可能オブジェクト(callable)は、 async def を使用してコルーチンとして定義できるため、コルーチン構文を使用します(例: await, async for, async with):

使い方

Scrapyのコルーチンにはいくつかのユースケースがあります。 ダウンローダー・ミドルウェアやシグナル・ハンドラーなど、以前のScrapyバージョン用に記述されたときにDeferredを返すコードは、より短く、よりクリーンになるように書き直すことができます:

from itemadapter import ItemAdapter

class DbPipeline:
    def _update_item(self, data, item):
        adapter = ItemAdapter(item)
        adapter['field'] = data
        return item

    def process_item(self, item, spider):
        adapter = ItemAdapter(item)
        dfd = db.get_some_data(adapter['id'])
        dfd.addCallback(self._update_item, item)
        return dfd

上記は以下のようになります:

from itemadapter import ItemAdapter

class DbPipeline:
    async def process_item(self, item, spider):
        adapter = ItemAdapter(item)
        adapter['field'] = await db.get_some_data(adapter['id'])
        return item

コルーチンは、非同期コードを呼び出すために使用できます。 これには、他のコルーチン、Deferredを返す関数、および Future などの awaitableオブジェクト を返す関数が含まれます。 これは、そのようなコードを提供する多くの便利なPythonライブラリを使用できることを意味します:

class MySpider(Spider):
    # ...
    async def parse_with_deferred(self, response):
        additional_response = await treq.get('https://additional.url')
        additional_data = await treq.content(additional_response)
        # ... use response and additional_data to yield items and requests

    async def parse_with_asyncio(self, response):
        async with aiohttp.ClientSession() as session:
            async with session.get('https://additional.url') as additional_response:
                additional_data = await r.text()
        # ... use response and additional_data to yield items and requests

注釈

aio-libs などのコルーチンを使用する多くのライブラリは asyncio ループを必要とし、それらを使用するには Scrapyで非同期サポートを有効にする 必要があります。

非同期コードの一般的な使用例は以下のとおりです:

  • ウェブサイトとデータベースとその他のサービス(コールバック、パイプライン、ミドルウェア)からのデータのリクエスト。

  • (パイプラインおよびミドルウェアの)データベースにデータを保存する。

  • ( spider_opened ハンドラー内の)何らかの外部イベントまでスパイダーの初期化を遅らせる。

  • ExecutionEngine.download のような非同期Scrapyメソッドを呼び出す( スクリーンショット・パイプライン 参照)。

asyncio(非同期I/O)

バージョン 2.0 で追加.

Scrapyは asyncio を部分的にサポートしています。 asyncioリアクターのインストール の後で、任意の コルーチンasyncio および asyncio を利用したライブラリを使用できます。

警告

Scrapyでの asyncio のサポートは実験的なものであり、実稼働環境ではまだ推奨されていません。 将来のScrapyバージョンでは、非推奨の期間や警告なしに関連する変更が導入される可能性があります。

asyncioリアクターのインストール

asyncio サポートを有効にするには、 TWISTED_REACTOR 設定を 'twisted.internet.asyncioreactor.AsyncioSelectorReactor' に設定します。

CrawlerRunner を使用している場合は、 AsyncioSelectorReactor リアクターも手動でインストールする必要があります。 install_reactor() を使用してこれを行うことができます:

install_reactor('twisted.internet.asyncioreactor.AsyncioSelectorReactor')

カスタムasyncioループの使用

asyncioリアクターでカスタムasyncioイベント・ループを使用することもできます。 ASYNCIO_EVENT_LOOP 設定を目的のイベント・ループ・クラスのインポート・パスに設定して、デフォルトのasyncioイベント・ループの代わりに使用します。

F.A.Q.(よくある質問と回答)

よくある質問とその回答。

スパイダーのデバッグ

Scrapyスパイダーの一般的な問題をデバッグする方法を学びます。

スパイダー規約(contract)

スパイダーをテストするために規約(contract)を使用する方法を学びます。

よくある例

Scrapyのいくつかの一般的な慣例に親しみます。

広範なクロール

多数のドメインを並行してクロールするためのScrapyのチューニング。

Webブラウザの開発ツールを使ってスクレイピングする

Webブラウザ付属の開発ツールを使用してスクレイプする方法を学びます。

動的に読み込まれたコンテンツの選択

動的にロードされるWebページ・データを読み取ります。

メモリ・リークのデバッグ

クローラーで、どのようにメモリ・リークを探して、そしてどのように取り除くかを学びます。

ファイルと画像のダウンロードおよび処理

あなたがスクレイプしたアイテムに関連するファイルや画像をダウンロードします。

スパイダーのデプロイ

リモート・サーバに、あなたのScrapyスパイダーを配置し実行します。

AutoThrottle拡張機能

負荷に応じてクロール速度を動的に調整します。

ベンチマーキング

Scrapyがあなたのハードウェアでどのように機能するかをチェックします。

ジョブ制御: クロールの一時停止と再開

大きなスパイダーのクロールを一時停止および再開する方法を学習します。

スパイダー規約(contract)

コルーチン構文 の利用

asyncio(非同期I/O)

asyncioasyncio-powered ライブラリ

Scrapyの拡張

アーキテクチャ概観

この文書では、Scrapyのアーキテクチャとそのコンポーネントの相互作用について説明します。

概観

以下の図は、Scrapyアーキテクチャの概要とそのコンポーネント、およびシステム内で発生するデータフローの概要(赤い矢印で表示)を示しています。コンポーネントの簡単な説明と、それらの詳細情報へのリンクを以下に示します。データフローについても以下で説明します。

データ・フロー

Scrapy architecture

Scrapyのデータ・フローは実行エンジンによって制御され、次のようになります:

  1. Scrapyエンジン は、 スパイダー からクロールする最初のリクエストを取得します。

  2. Scrapyエンジン は、 スケジューラ でリクエストをスケジュールし、クロールする次のリクエストを求めます。

  3. スケジューラ は、次のリクエストを Scrapyエンジン に返します。

  4. Scrapyエンジン は、 ダウンローダー にリクエストを送信し、 ダウンローダー・ミドルウェア を通過します( process_request() 参照)。

  5. ページのダウンロードが完了すると、 ダウンローダー は(そのページの)レスポンスを生成し、Scrapyエンジンに送信し、 ダウンローダー・ミドルウェア を通過します( process_response() 参照)。

  6. Scrapyエンジンダウンローダー からResponseを受け取り、それを スパイダー に送信して処理し、 スパイダー・ミドルウェア を通過します( see process_spider_input() )。

  7. スパイダー はレスポンスを処理し、スクレイピングされたアイテムと(後に続く)新しいリクエストを Scrapyエンジン に返し、 スパイダー・ミドルウェア を通過します( process_spider_output() 参照 )。

  8. Scrapyエンジン は処理済みのアイテムを アイテム・パイプライン に送信し、処理済みのリクエストを スケジューラ に送信し、可能なら次のクロール要求を求めます。

  9. スケジューラ からの要求がなくなるまで、プロセスは(ステップ1から)繰り返されます。

コンポーネント

Scrapyエンジン

エンジンは、システムのすべてのコンポーネント間のデータ・フローを制御し、特定のアクションが発生したときにイベントをトリガーします。詳細については、上記の データ・フロー 節を参照してください。

スケジューラ

スケジューラはScrapyエンジンからリクエストを受信し、後でScrapyエンジンが求めたときにリクエストをキューに入れて(Scrapyエンジンにも)送信します。

ダウンローダー

ダウンローダーはWebページを取得し、それらをScrapyエンジンに送り、Scrapyエンジンがそれらをスパイダーに送ります。

スパイダー

スパイダーは、Scrapyユーザーによって作成されたカスタムクラスであり、レスポンスをパースして、レスポンスまたは追跡する追加のレスポンスから アイテム を抽出します。詳細については スパイダー を参照してください。

アイテム・パイプライン

アイテム・パイプラインは、スパイダーによってアイテムが抽出(またはスクレイピング)された後にアイテムを処理する役割を果たします。典型的なタスクには、クレンジング、検証、永続化(データベースへのアイテムの保存など)が含まれます。詳細については、 アイテム・パイプライン を参照してください。

ダウンローダー・ミドルウェア

ダウンローダー・ミドルウェアは、エンジンとダウンローダーの間にある特定のフックであり、エンジンからダウンローダーに渡されるときにリクエストを処理し、ダウンローダーからエンジンに渡されるリクエストを処理します。

あなたが以下のいずれかを行う必要がある場合は、ダウンローダー・ミドルウェアを使用します:

  • ダウンローダーに送信される直前にリクエストを処理します(Scrapyがウェブサイトにリクエストを送信する直前);

  • スパイダーに渡す前に受信したリクエストを変更する;

  • 受信したレスポンスをスパイダーに渡すのではなく、新しいリクエストを送信します;

  • Webページを取得せずにスパイダーにレスポンスを渡す;

  • いくつかのリクエストを黙って廃棄する。

詳細は ダウンローダー・ミドルウェア 参照。

スパイダー・ミドルウェア

スパイダー・ミドルウェアは、エンジンとスパイダーの間にある特定のフックであり、スパイダーの入力(レスポンス)と出力(アイテムとリクエスト)を処理できます。

あなたが必要な場合はスパイダー・ミドルウェアを使用します

  • スパイダー・コールバックのポスト・プロセス出力 - リクエストまたはアイテムの変更/追加/削除;

  • start_requests の後処理;

  • スパイダー例外を処理します;

  • レスポンス内容に基づいて、一部のリクエストに対してコールバックの代わりに偉ー・バック(errback)を呼び出します。

詳細については スパイダー・ミドルウェア 参照。

イベント駆動型ネットワーキング

Scrapyは、Python用の人気のあるイベント駆動型ネットワーク・フレームワークである Twisted を使って記述されています。したがって、並行性のために非ブロッキング(別名「非同期」)コードを使用して実装されています。

非同期プログラミングとTwistedの詳細については、これらのリンクを参照してください:

ダウンローダー・ミドルウェア

ダウンローダー・ミドルウェアは、Scrapyのリクエスト/レスポンス処理へのフックのフレームワークです。Scrapyのリクエストとレスポンスをグローバルに変更するための軽量で低レベルのシステムです。

ダウンローダーミドルウェアをアクティブにする

ダウンローダー・ミドルウェア・コンポーネントを有効にするには、それを DOWNLOADER_MIDDLEWARES 設定に追加します。これは、キーがミドルウェア・クラス・パスであり、値がミドルウェアの順序である辞書です。

ここに例があります:

DOWNLOADER_MIDDLEWARES = {
    'myproject.middlewares.CustomDownloaderMiddleware': 543,
}

DOWNLOADER_MIDDLEWARES 設定は、Scrapyで定義された DOWNLOADER_MIDDLEWARES_BASE 設定とマージされ(オーバーライドされることはありません)、有効なミドルウェアの最終ソートリストを取得するために順序でソートされます。1つはエンジンに近く、最後はダウンローダーに近いものです。つまり、各ミドルウェアの process_request() メソッドは、ミドルウェアの昇順(100、200、300…)で呼び出され、各ミドルウェアの process_response() メソッドは、降順で呼び出されます。

ミドルウェアに割り当てる順序を決定するには、 DOWNLOADER_MIDDLEWARES_BASE 設定を参照し、ミドルウェアを挿入する場所に応じて値を選択します。各ミドルウェアは異なるアクションを実行し、ミドルウェアは適用される以前の(または後続の)ミドルウェアに依存する可能性があるため、順序は重要です。

組み込みのミドルウェア( DOWNLOADER_MIDDLEWARES_BASE で定義され、デフォルトで有効になっているミドルウェア)を無効にするには、プロジェクトの DOWNLOADER_MIDDLEWARES 設定で定義し、その値として None を割り当てる必要があります。たとえば、ユーザーエージェントミドルウェアを無効にする場合、以下の通りです:

DOWNLOADER_MIDDLEWARES = {
    'myproject.middlewares.CustomDownloaderMiddleware': 543,
    'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware': None,
}

最後に、特定の設定で一部のミドルウェアを有効にする必要がある場合があることに注意してください。詳細については、各ミドルウェアのドキュメントを参照してください。

あなた自身のダウンローダー・ミドルウェアを書く

各ダウンローダー・ミドルウェアは、以下で定義される1つ以上のメソッドを定義するPythonクラスです。

メインのエントリー・ポイントは from_crawler クラス・メソッドで、これは Crawler インスタンスを受け取ります。 Crawler オブジェクトは、たとえば 設定 へのアクセスを提供します。

class scrapy.downloadermiddlewares.DownloaderMiddleware

注釈

どのダウンローダー・ミドルウェア・メソッドも遅延オブジェクト(deferred)を返す場合があります。

process_request(request, spider)

このメソッドは、ダウンロード・ミドルウェアを通過するリクエストごとに呼び出されます。

process_request() の結果は次のいずれかでなければなりません: None を返す、 Response オブジェクトを返す、 Request オブジェクトを返す、 IgnoreRequest 例外を起こす。

None を返した場合、Scrapyはこのリクエストの処理を続け、最終的に適切なダウンローダー・ハンドラーが実行されたリクエスト(およびダウンロードされたレスポンス)が呼ばれるまで、他のすべてのミドルウェアを実行します。

Response オブジェクトを返す場合、Scrapyは他の 任意の process_request() メソッドまたは process_exception() メソッド、または適切なダウンロード関数の呼び出しを考慮しません。そのレスポンスオブジェクトそのものを返します。なお、インストールされたミドルウェアの process_response() メソッドは、すべてのレスポンスで常に呼び出されます。

Request オブジェクトを返す場合、Scrapyはprocess_requestメソッドの呼び出しを停止し、返されたリクエストを再スケジュールします。 新しく返されたリクエストが実行されると、ダウンロードされたレスポンスで適切なミドルウェア・チェーンが呼び出されます。

IgnoreRequest 例外が発生した場合、インストールされたダウンローダー・ミドルウェアの process_exception() メソッドが呼び出されます。それらのいずれもが例外を処理しない場合、リクエストのerrback関数( Request.errback )が呼び出されます。発生した例外を処理するコードがない場合、無視され、(他の例外とは異なり)ログに記録されません。

パラメータ
  • request (Request object) -- 処理中のリクエスト

  • spider (Spider object) -- このリクエストの対象となるスパイダー

process_response(request, response, spider)

process_response() は次のいずれかの結果でなければなりません: Response オブジェクトを返す、 Request オブジェクトを返す、 IgnoreRequest 例外を起こす。

Response が返された場合(指定されたレスポンスと同じか、まったく新しいレスポンスである可能性があります)、そのレスポンスは次のチェーン内のミドルウェアの process_response() で引き続き処理されます。

Request オブジェクトを返す場合、ミドルウェア・チェーンは停止し、返されたリクエストは将来ダウンロードされるように再スケジュールされます。これは、リクエストが process_request() から返される場合と同じ動作です。

IgnoreRequest 例外が発生した場合、リクエストのerrback関数( Request.errback )が呼び出されます。発生した例外を処理するコードがない場合、無視され、(他の例外とは異なり)ログに記録されません。

パラメータ
  • request (is a Request object) -- レスポンスを引き起こしたリクエスト

  • response (Response object) -- 処理中のレスポンス

  • spider (Spider object) -- このレスポンスを意図したスパイダー

process_exception(request, exception, spider)

Scrapyは、ダウンロード・ハンドラーまたは、(ダウンローダー・ミドルウェアから) process_request() が例外( IgnoreRequest 例外を含む)を発生させると、 process_exception() を呼び出します

process_exception() は、 None または Response オブジェクトまたは Request オブジェクトを返す必要があります。

None を返す場合、Scrapyはこの例外の処理を続け、ミドルウェアが無くなりデフォルトの例外処理が開始されるまで、順にインストールされた他のミドルウェアの process_exception() メソッドを実行します。

Response オブジェクトを返す場合、インストールされたミドルウェアの process_response() メソッド・チェーンが開始され、Scrapyは他のミドルウェアの process_exception() メソッドを呼び出すことはありません。

Request オブジェクトを返す場合、返されたリクエストは将来ダウンロードされるように再スケジュールされます。これは、レスポンスを返すのと同様に、ミドルウェアの process_exception() メソッドの実行を停止します。

パラメータ
  • request (is a Request object) -- 例外を生成したリクエスト

  • exception (an Exception object) -- 発生した例外

  • spider (Spider object) -- このリクエストの対象となるスパイダー

from_crawler(cls, crawler)

存在する場合、このクラス・メソッドは Crawler からミドルウェア・インスタンスを作成するために呼び出されます。ミドルウェアの新しいインスタンスを返す必要があります。クローラー・オブジェクトは、設定や信号などのすべてのScrapyコアコンポーネントへのアクセスを提供します。それはミドルウェアがそれらにアクセスし、その機能をScrapyにフックする方法です。

パラメータ

crawler (Crawler object) -- このミドルウェアを使用するクローラー

組み込みダウンローダー・ミドルウェア・リファレンス

この文書では、Scrapyに付属するすべてのダウンローダー・ミドルウェア・コンポーネントについて説明します。それらの使用方法と独自のダウンローダ・ミドルウェアの作成方法については、ダウンローダミドルウェア使用ガイド を参照してください。

デフォルトで有効になっているコンポーネント(およびその順序)のリストについては、 DOWNLOADER_MIDDLEWARES_BASE 設定を参照してください。

CookiesMiddleware
class scrapy.downloadermiddlewares.cookies.CookiesMiddleware[ソース]

このミドルウェアにより、セッションを使用するサイトなど、クッキーを必要とするサイトを操作できます。Webサーバーが送信したクッキーを追跡し、Webブラウザーが行うように、その後の(スパイダーからの)リクエストでそれらを送り返します。

注意

UTF8でエンコードされていないバイト・シーケンスが Request に渡されると、 CookiesMiddleware は警告をログに取ります。 ログ取り動作をカスタマイズするには、 高度なカスタマイズ を参照してください。

注意

Cookie ヘッダーを介して設定されたCookieは、 CookiesMiddleware では考慮されません。リクエストにCookieを設定する必要がある場合は、 Request.cookies パラメータを使用します。これは現在改善に取り組んでいる既知の制限です。

次の設定を使用して、クッキー・ミドルウェアを構成(configure)できます:

COOKIES_ENABLED

デフォルト: True

クッキー・ミドルウェアを有効にするかどうか。 無効にすると、クッキーはWebサーバーに送信されません。

Request.meta['dont_merge_cookies']True と評価される場合、 COOKIES_ENABLED 設定にかかわらず、リクエス・トクッキーは Webサーバーに 送信されません 。そして Response で受信されたクッキーは、既存のクッキーとは マージされません

詳細については、 Requestcookies パラメーターを参照してください。

COOKIES_DEBUG

デフォルト: False

有効にすると、Scrapyはリクエストで送信されたすべてのクッキー( Cookie ヘッダー)およびレスポンスで受信されたすべてのクッキー( Set-Cookie ヘッダー)をログに記録します。

COOKIES_DEBUG が有効になっているログの例を次に示します:

2011-04-06 14:35:10-0300 [scrapy.core.engine] INFO: Spider opened
2011-04-06 14:35:10-0300 [scrapy.downloadermiddlewares.cookies] DEBUG: Sending cookies to: <GET http://www.diningcity.com/netherlands/index.html>
        Cookie: clientlanguage_nl=en_EN
2011-04-06 14:35:14-0300 [scrapy.downloadermiddlewares.cookies] DEBUG: Received cookies from: <200 http://www.diningcity.com/netherlands/index.html>
        Set-Cookie: JSESSIONID=B~FA4DC0C496C8762AE4F1A620EAB34F38; Path=/
        Set-Cookie: ip_isocode=US
        Set-Cookie: clientlanguage_nl=en_EN; Expires=Thu, 07-Apr-2011 21:21:34 GMT; Path=/
2011-04-06 14:49:50-0300 [scrapy.core.engine] DEBUG: Crawled (200) <GET http://www.diningcity.com/netherlands/index.html> (referer: None)
[...]
DefaultHeadersMiddleware
class scrapy.downloadermiddlewares.defaultheaders.DefaultHeadersMiddleware[ソース]

このミドルウェアは、 DEFAULT_REQUEST_HEADERS 設定で指定されたすべてのデフォルト・リクエスト・ヘッダーを設定します。

DownloadTimeoutMiddleware
class scrapy.downloadermiddlewares.downloadtimeout.DownloadTimeoutMiddleware[ソース]

このミドルウェアは、 DOWNLOAD_TIMEOUT 設定または download_timeout スパイダー属性で指定されたリクエストのダウンロード・タイムアウトを設定します。

注釈

download_timeout リクエスト・メタ・キーを使用して、リクエストごとにダウンロード・タイムアウトを設定することもできます。これは、DownloadTimeoutMiddlewareが無効になっている場合でもサポートされます。

HttpAuthMiddleware
class scrapy.downloadermiddlewares.httpauth.HttpAuthMiddleware[ソース]

このミドルウェアは、 Basic access authentication (別名BASIC認証)を使用して、特定のスパイダーから生成されたすべてのリクエストを認証します。

特定のスパイダーからのBASIC認証を有効にするには、それらのスパイダーの http_userhttp_pass 属性を設定します。

例:

from scrapy.spiders import CrawlSpider

class SomeIntranetSiteSpider(CrawlSpider):

    http_user = 'someuser'
    http_pass = 'somepass'
    name = 'intranet.example.com'

    # .. rest of the spider code omitted ...
HttpCacheMiddleware
class scrapy.downloadermiddlewares.httpcache.HttpCacheMiddleware[ソース]

このミドルウェアは、すべてのHTTPリクエストおよびレスポンスに低レベルのキャッシュを提供します。 キャッシュ・ストレージ・バックエンドおよびキャッシュ・ポリシーと組み合わせる必要があります。

Scrapyには3つのHTTPキャッシュ・ストレージ・バックエンドが付属しています:

HTTPCACHE_STORAGE 設定でHTTPキャッシュ・ストレージ・バックエンドを変更できます。また、 独自のストレージ・バックエンドの実装 もできます。

Scrapyには2つのHTTPキャッシュ・ポリシーが付属しています:

HTTPCACHE_POLICY 設定でHTTPキャッシュ・ポリシーを変更できます。または、独自のポリシーを実装することもできます。

dont_cache メタ・キーが True に等しいことを使用して、すべてのポリシーで応答をキャッシュしないようにすることもできます。

ダミー・ポリシー(デフォルト)
class scrapy.extensions.httpcache.DummyPolicy[ソース]

このポリシーは、HTTPキャッシュ制御ディレクティブを認識しません。すべてのリクエストとそれに対応するレスポンスはキャッシュされます。同じリクエストが再び現れるると、インターネットから何も転送せずにレスポンスが返されます。

ダミー・ポリシーは、スパイダーをより高速にテストする(毎回ダウンロードを待つ必要なしに)ときや、インターネット接続が利用できないときにスパイダーをオフラインで試すのに役立ちます。設計目標は、スパイダーの実行を前に実行したとおりに再現できるようにすることです。

RFC2616ポリシー
class scrapy.extensions.httpcache.RFC2616Policy[ソース]

このポリシーは、RFC2616準拠のHTTPキャッシュ、つまりHTTP Cache-Control認識を提供します。これは、新たな生成物に狙いを定め、変更されていないデータのダウンロードを回避するために連続実行で使用されます(帯域幅を節約し、クロールを高速化するため)。

実装されているもの:

  • no-store キャッシュ制御ディレクティブが設定されている場合、レスポンス/リクエストを保存しようとしないでください。

  • no-cache キャッシュ制御ディレクティブが新しいレスポンスに対しても設定されている場合、キャッシュからレスポンスを提供しません

  • max-age キャッシュ制御ディレクティブから鮮度寿命を計算します

  • Expires レスポンス・ヘッダーから鮮度寿命を計算します

  • Last-Modified レスポンス・ヘッダーから鮮度の有効期間を計算します(Firefoxで使用されるヒューリスティック)

  • Age レスポンス・ヘッダーから現在の年齢を計算する

  • Date ヘッダーから現在の年齢を計算

  • Last-Modified レスポンス・ヘッダーに基づいて古いレスポンスを再検証します

  • ETag レスポンス・ヘッダーに基づいて古いレスポンスを再検証します

  • 受信したレスポンスがない場合に Date ヘッダーを設定します

  • リクエストで max-stale キャッシュ制御ディレクティブをサポート

これにより、スパイダーを完全なRFC2616キャッシュ・ポリシーで構成できますが、HTTP仕様に準拠したまま、リクエストごとの再検証を回避できます。

例:

Cache-Control: max-stale=600 をリクエスト・ヘッダーに追加して、600秒以内ならば有効期限を超えたレスポンスを受け入れます。

RFC2616, 14.9.3 も参照下さい。

実装されてないもの:

ファイルシステム・ストレージ・バックエンド(デフォルト)
class scrapy.extensions.httpcache.FilesystemCacheStorage[ソース]

ファイルシステム・ストレージ・バックエンドは、HTTPキャッシュ・ミドルウェアで使用できます。

各リクエスト/レスポンスのペアは、次のファイルを含む異なるディレクトリに保存されます:

  • request_body - 生のリクエスト・ボディそのもの

  • request_headers - リクエスト・ヘッダ(生HTTP書式)

  • response_body - 生のレスポンス・ボディそのもの

  • response_headers - リクエスト・ヘッダ(生HTTP書式)

  • meta - Python repr() 形式の、このキャッシュ・リソースのメタ・データ(grepに優しい形式)

  • pickled_meta - `` meta`` と同じメタデータですが、より効率的な逆シリアル化のために直列化(pickled)されています

ディレクトリ名はリクエストのフィンガー・プリントから作成され( scrapy.utils.request.fingerprint 参照)、1つのレベルのサブ・ディレクトリを使用して、同じディレクトリに多くのファイルを作成しないようにします(多くのファイルシステムでは非効率的です)。ディレクトリの例以下です:

/path/to/cache/dir/example.com/72/72811f648e718090f041317756c03adb0ada46c7
DBMストレージ・バックエンド
class scrapy.extensions.httpcache.DbmCacheStorage[ソース]

DBM ストレージ・バックエンドは、HTTPキャッシュ・ミドルウェアでも使用できます。

デフォルトでは dbm を使用しますが、 HTTPCACHE_DBM_MODULE 設定で変更できます。

あなた自身のストレージ・バックエンドを書く

以下に説明するメソッドを定義するPythonクラスを作成することにより、キャッシュス・トレージ・バックエンドを実装できます。

class scrapy.extensions.httpcache.CacheStorage
open_spider(spider)

このメソッドは、クロールのためにスパイダーがオープンされた後に呼び出されます。 open_spider シグナルを処理します。

パラメータ

spider (Spider object) -- オープンされたスパイダー

close_spider(spider)

このメソッドは、スパイダーがクローズさられた後に呼び出されます。 close_spider シグナルを処理します。

パラメータ

spider (Spider object) -- クローズされたスパイダー

retrieve_response(spider, request)

キャッシュに存在する場合はレスポンスを返し、そうでない場合は None を返します。

パラメータ
  • spider (Spider object) -- リクエストを生成したスパイダー

  • request (Request object) -- キャッシュされたレスポンスを見つけるためのリクエスト

store_response(spider, request, response)

与えられたレスポンスをキャッシュに保存します。

パラメータ
  • spider (Spider object) -- このレスポンスを意図したスパイダー

  • request (Request object) -- スパイダーが生成した対応するリクエスト

  • response (Response object) -- キャッシュに保存するレスポンス

ストレージ・バックエンドを使用するには、以下の設定をします:

  • HTTPCACHE_STORAGE をあなたのカスタム・ストレージ・クラスのPythonインポート・パスに設定します。

HTTPCache middleware 設定

HttpCacheMiddleware は次の設定で構成(configure)できます:

HTTPCACHE_ENABLED

デフォルト: False

HTTPキャッシュを有効にするかどうか。

HTTPCACHE_EXPIRATION_SECS

デフォルト: 0

キャッシュされたリクエストの有効期限(秒単位)。

この時間より古いキャッシュされたリクエストは再ダウンロードされます。ゼロの場合、キャッシュされたリクエストは期限切れになりません。

HTTPCACHE_DIR

デフォルト: 'httpcache'

(低レベル)HTTPキャッシュを保存するために使用するディレクトリ。空の場合、HTTPキャッシュは無効になります。相対パスが指定されている場合、プロジェクト・データ・ディレクトリからの相対パスが使用されます。詳細については、 Scrapyプロジェクトのデフォルト構造 を参照してください。

HTTPCACHE_IGNORE_HTTP_CODES

デフォルト: []

これらのHTTPコードでレスポンスをキャッシュしないでください。

HTTPCACHE_IGNORE_MISSING

デフォルト: False

有効にすると、キャッシュに見つからないリクエストはダウンロードされずに無視されます。

HTTPCACHE_IGNORE_SCHEMES

デフォルト: ['file']

これらのURIスキームでレスポンスをキャッシュしないでください。

HTTPCACHE_STORAGE

デフォルト: 'scrapy.extensions.httpcache.FilesystemCacheStorage'

キャッシュ・ストレージ・バックエンドを実装するクラス。

HTTPCACHE_DBM_MODULE

デフォルト: 'anydbm'

DBMストレージ・バックエンド で使用するデータベース・モジュール。この設定は、DBMバックエンド固有です。

HTTPCACHE_POLICY

デフォルト: 'scrapy.extensions.httpcache.DummyPolicy'

キャッシュ・ポリシーを実装するクラス。

HTTPCACHE_GZIP

デフォルト: False

有効にすると、キャッシュされたすべてのデータがgzipで圧縮されます。この設定は、ファイルシステム・バックエンド固有です。

HTTPCACHE_ALWAYS_STORE

デフォルト: False

有効にすると、ページを無条件にキャッシュします。

スパイダーは、たとえば Cache-Control:max-stale で将来使用するために、すべてのレスポンスをキャッシュで利用可能にしたい場合があります。 DummyPolicyはすべてのレスポンスをキャッシュしますが、それらを再検証することはありません。また、より微妙なポリシーが望ましい場合があります。

この設定は、レスポンスの Cache-Control:no-store ディレクティブを引き続き尊重します。不要な場合は、キャッシュ・ミドルウェアにフィードするレスポンスのCache-Controlヘッダーから no-store をフィルターします。

HTTPCACHE_IGNORE_RESPONSE_CACHE_CONTROLS

デフォルト: []

無視されるレスポンスのキャッシュ制御ディレクティブのリスト。

サイトは "no-store"、"no-cache"、"must-revalidate"などを設定することがよくありますが、これらのディレクティブを尊重するとスパイダーが生成できる取引(traffic)をろうばいさせます。この設定により、クロールされるサイトにとって重要ではないことがわかっているCache-Controlディレクティブを選択的に無視できます。

スパイダーは、実際に必要な場合を除き、リクエストでCache-Controlディレクティブを発行しないため、リクエストのディレクティブはフィルタリングされません。

HttpCompressionMiddleware
class scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware[ソース]

このミドルウェアにより、圧縮(gzip、deflate)取引(traffic)をWebサイトから送受信できます。

このミドルウェアは、 brotlipy または zstandard がインストールされている場合、それぞれに、 brotli-compressed と共に zstd-compressed レスポンスのデコードもサポートします。

HttpCompressionMiddleware 設定
COMPRESSION_ENABLED

デフォルト: True

圧縮ミドルウェアを有効にするかどうか。

HttpProxyMiddleware
class scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware[ソース]

このミドルウェアは、 Request オブジェクトに proxy メタ値を設定することにより、リクエストに使用するHTTPプロキシを設定します。

Python標準ライブラリモジュール urllib.request と同様に、以下の環境変数に従います:

  • http_proxy

  • https_proxy

  • no_proxy

リクエストごとにメタ・キー proxyhttp://some_proxy_server:port または http://username:password@some_proxy_server:port のような値に設定することもできます。この値は http_proxy / https_proxy 環境変数よりも優先され、また no_proxy 環境変数も無視することに注意してください。

RedirectMiddleware
class scrapy.downloadermiddlewares.redirect.RedirectMiddleware[ソース]

このミドルウェアは、レスポンス・ステータスに基づいてリクエストのリダイレクトを処理します。

(リダイレクト中に)リクエストが通過するURLは Request.metaredirect_urls キーで見つけることができます。

redirect_urls の各リダイレクトの理由は、 Request.metaredirect_reasons キーにあります。例: [301, 302, 307, 'meta refresh']

理由の形式は、対応するリダイレクトを処理したミドルウェアによって異なります。 たとえば、 RedirectMiddleware はトリガーとなったレスポンス・ステータ・スコードを整数で示しますが、 MetaRefreshMiddleware は常に 'meta refresh' 文字列を理由として使用します。

RedirectMiddleware は次の設定で設定できます(詳細については設定ドキュメントを参照してください):

Request.metadont_redirect キーがTrueに設定されている場合、リクエストはこのミドルウェアによって無視されます。

スパイダーでいくつかのリダイレクト・ステータス・コードを処理したい場合、これらを handle_httpstatus_list スパイダー属性で指定できます。

たとえば、リダイレクト・ミドルウェアで、301と302レスポンスを無視する(およびそれらをスパイダーに渡す)場合は、以下のようにします:

class MySpider(CrawlSpider):
    handle_httpstatus_list = [301, 302]

Request.metahandle_httpstatus_list キーは、リクエストごとに許可するレスポンス・コードを指定するためにも使用できます。リクエストに対するレスポンス・コードを許可したい場合、メタ・キー handle_httpstatus_allTrue に設定することもできます。

RedirectMiddleware 設定
REDIRECT_ENABLED

デフォルト: True

リダイレクト・ミドルウェアを有効にするかどうか。

REDIRECT_MAX_TIMES

デフォルト: 20

1回のリクエストで追跡されるリダイレクトの最大数。この最大値を超えると、そのリクエストのレスポンスがそのまま返されます。

MetaRefreshMiddleware
class scrapy.downloadermiddlewares.redirect.MetaRefreshMiddleware[ソース]

このミドルウェアは、メタ・リフレッシュhtmlタグに基づいてリクエストのリダイレクトを処理します。

MetaRefreshMiddleware は次の設定で設定できます(詳細については設定ドキュメントを参照してください):

このミドルウェアは、 RedirectMiddleware で説明されているように、 :REDIRECT_MAX_TIMES 設定と dont_redirect リクエスト・メタ・キーと redirect_urls リクエスト・メタ・キーと redirect_reasons リクエスト・メタ・キーに従います。

MetaRefreshMiddleware 設定
METAREFRESH_ENABLED

デフォルト: True

メタ・リフレッシュ・ミドルウェアを有効にするかどうか。

METAREFRESH_IGNORE_TAGS

デフォルト: []

これらのタグ内のメタ・タグは無視されます。

バージョン 2.0 で変更: METAREFRESH_IGNORE_TAGS のデフォルト値は ['script', 'noscript'] kから [] に変更されました。

METAREFRESH_MAXDELAY

デフォルト: 100

リダイレクト後の最大メタリフレッシュ遅延(秒単位)。一部のサイトでは、セッションの期限切れページへのリダイレクトにメタ・リフレッシュを使用しているため、自動リダイレクトを最大遅延に制限しています。

RetryMiddleware
class scrapy.downloadermiddlewares.retry.RetryMiddleware[ソース]

接続タイムアウトやHTTP 500エラーなどの一時的な問題が原因である可能性のある失敗した要求を再試行するミドルウェア。

スパイダーがすべての通常の(失敗していない)ページのクロールを完了すると、失敗したページはスクレイピング・プロセスで収集され、最後に再スケジュールされます。

RetryMiddleware は次の設定で設定できます(詳細については設定ドキュメントを参照):

Request.metadont_retry キーがTrueに設定されている場合、リクエストはこのミドルウェアによって無視されます。

スパイダー・コールバックからのリクエストを再試行するには、 get_retry_request() 関数を使用できます:

scrapy.downloadermiddlewares.retry.get_retry_request(request: scrapy.http.request.Request, *, spider: scrapy.spiders.Spider, reason: Union[str, Exception] = 'unspecified', max_retry_times: Optional[int] = None, priority_adjust: Optional[int] = None, logger: logging.Logger = <Logger scrapy.downloadermiddlewares.retry (WARNING)>, stats_base_key: str = 'retry')[ソース]

新しい Request オブジェクトを返し、指定されたリクエストを再試行します。指定されたリクエストの再試行をやり尽くした場合は None を返します。

たとえば、 Spider コールバックは以下のように使用できます:

def parse(self, response):
    if not response.text:
        new_request_or_none = get_retry_request(
            response.request,
            spider=self,
            reason='empty',
        )
        return new_request_or_none

spider は、再試行リクエストを求めている Spider インスタンスです。 これは、 settingsstats にアクセスし、追加のロギング・コンテキストを提供するために使用されます( logging.debug() を参照)。

reason は、リクエストを再試行する必要がある理由を示す文字列または Exception オブジェクトです。再試行統計(訳注:retry stats)に名前を付けるために使用されます。

max_retry_times は、 request を再試行できる最大回数を決定する数値です。 指定されていない場合または None の場合、数値はリクエストの max_retry_times メタ・キーから読み取られます。 max_retry_times メタ・キーが定義されていないか None の場合、数値は RETRY_TIMES 設定から読み取られます。

priority_adjust は、 request に関連して新しいリクエストの優先度がどのように変化するかを決定する数値です。 指定しない場合、数値は RETRY_PRIORITY_ADJUST 設定から読み取られます。

logger は、メッセージをログに記録するときに使用されるlogging.Logger オブジェクトです

stats_base_key は、再試行関連のジョブ統計のベース・キーとして使用される文字列です

RetryMiddleware 設定
RETRY_ENABLED

デフォルト: True

再試行ミドルウェアを有効にするかどうか。

RETRY_TIMES

デフォルト: 2

(最初のダウンロードに加えて)再試行する最大回数。

再試行の最大回数は、 Request.metamax_retry_times 属性を使用してリクエストごとに指定することもできます。初期化されると、 max_retry_times メタ・キーは RETRY_TIMES 設定よりも優先されます。

RETRY_HTTP_CODES

デフォルト: [500, 502, 503, 504, 522, 524, 408, 429]

再試行するHTTPレスポンス・コード。その他のエラー(DNSルックアップの問題、接続の切断など)は常に再試行されます。

場合によっては、400を RETRY_HTTP_CODES に追加することもできます。これは、サーバーの過負荷を示すために使用される一般的なコードだからです。HTTPの仕様ではそうなっているため、デフォルトでは含まれていません。

RETRY_PRIORITY_ADJUST

デフォルト: -1

元のリクエストに対して再試行リクエストの優先度を調整します:

  • 正の優先度調整は、より高い優先度を意味します。

  • 負の優先度調整(デフォルト)は、優先度が低いことを意味します。

RobotsTxtMiddleware
class scrapy.downloadermiddlewares.robotstxt.RobotsTxtMiddleware[ソース]

このミドルウェアは、robots.txt除外標準で禁止されているリクエストを除外します。

Scrapyがrobots.txtを尊重するようにするには、ミドルウェアが有効になっており、かつ、 ROBOTSTXT_OBEY 設定が有効になっていることを確認してください。

ROBOTSTXT_USER_AGENT 設定を使用して、robots.txt ファイルでの照合に使用するユーザー・エージェント文字列を指定できます。 None の場合、リクエストで送信しているUser-Agentヘッダーまたは USER_AGENT 設定(この順序で)は、robots.txt ファイルで使用するユーザー・エージェントを決定するために使用されます。

このミドルウェアは robots.txt パーサと組み合わせる必要があります。

Scrapyには、次の robots.txt パーサがサポートされています:

robots.txt パーサは、 ROBOTSTXT_PARSER 設定で変更できます。または、 新しいパーサ のサポートを実装することもできます。

Request.metadont_obey_robotstxt キーがTrueに設定されている場合、 ROBOTSTXT_OBEY が有効になっていても、このミドルウェアは要求を無視します。

パーサはいくつかの側面で異なります:

  • 実装言語

  • サポートされている仕様

  • ワイルドカードマッチングのサポート

  • 長さベースのルール( length based rule )の使い方: 特に AllowDisallow ディレクティブは、パスの長さに基づく最も具体的なルールが、より具体的でない(短い)ルールよりも優先されます

さまざまなパーサの性能比較については the following link で入手できます。

Protegoパーサ

Protego に基づく:

  • Pythonによる実装

  • GoogleのRobots.txt仕様( Google's Robots.txt Specification )に準拠しています。

  • ワイルドカード・マッチングのサポート

  • 長さベースのルールの使用

Scrapyはデフォルトでこのパーサを使います

RobotFileParser

RobotFileParser に基づく:

Protegoよりも高速で、1.8.0より前のバージョンのScrapyと下位互換性があります。

このパーサーを使用するには、以下を設定します:

Reppyパーサ

Reppy に基づいています:

ネイティブ実装で、Protegoよりも高速です。

このパーサーを使用するには:

  • pip install reppy を実行して Reppy をインストールします

  • ROBOTSTXT_PARSER 設定に scrapy.robotstxt.ReppyRobotParser をセットします

Robotexclusionrulesparser

Robotexclusionrulesparser に基づいています:

このパーサーを使用するには:

新しいパーサのサポートの実装

抽象基本クラス RobotParser をサブクラス化し、以下に説明するメソッドを実装することにより、新しい robots.txt パーサーのサポートを実装できます。

class scrapy.robotstxt.RobotParser[ソース]
abstract allowed(url, user_agent)[ソース]

user_agenturl をクロールできる場合は True``を返し、そうでない場合は ``False を返します。

パラメータ
  • url (str) -- 絶対URL

  • user_agent (str) -- ユーザ・エージェント

abstract classmethod from_crawler(crawler, robotstxt_body)[ソース]

robots.txt ファイルのコンテンツをbyte型データとして解析します。 これはクラス・メソッドである必要があります。パーサ・バックエンドの新しいインスタンスを返す必要があります。

パラメータ
  • crawler (Crawler instance) -- リクエストを行ったクローラー

  • robotstxt_body (bytes) -- robots.txt ファイルの内容。

DownloaderStats
class scrapy.downloadermiddlewares.stats.DownloaderStats[ソース]

通過するすべてのリクエストとレスポンスと例外の統計を保存するミドルウェア。

このミドルウェアを使用するには、 DOWNLOADER_STATS 設定を有効にする必要があります。

UserAgentMiddleware
class scrapy.downloadermiddlewares.useragent.UserAgentMiddleware[ソース]

スパイダーがデフォルトのユーザ・エージェントをオーバーライドできるようにするミドルウェア。

スパイダーがデフォルトのユーザー・エージェントを上書きするには、その user_agent 属性を設定する必要があります。

AjaxCrawlMiddleware
class scrapy.downloadermiddlewares.ajaxcrawl.AjaxCrawlMiddleware[ソース]

メタ・フラグメントHTMLタグに基づいて「AJAXクロール可能な」ページ・バリアントを検出するミドルウェア。 詳細については、 https://developers.google.com/search/docs/ajax-crawling/docs/getting-started をご覧ください。

注釈

Scrapyは、このミドルウェアがなくても、「 'http://example.com/!#foo=bar'」などのURLの「AJAXクロール可能な」ページを検出します。AjaxCrawlMiddlewareは、URLに '!#' が含まれていない場合に必要です。これは多くの場合、 'index' または 'main' のWebサイトページの場合です。

AjaxCrawlMiddleware 設定
AJAXCRAWL_ENABLED

デフォルト: False

AjaxCrawlMiddlewareを有効にするかどうか。 broad crawls に対して有効にすることをお勧めします。

HttpProxyMiddleware 設定
HTTPPROXY_ENABLED

デフォルト: True

HttpProxyMiddleware を有効にするかどうか。

HTTPPROXY_AUTH_ENCODING

デフォルト: "latin-1"

HttpProxyMiddleware のプロキシ認証のデフォルトのエンコーディング。

スパイダー・ミドルウェア

スパイダー・ミドルウェアは、Scrapyのスパイダー処理メカニズムへのフックのフレームワークであり、カスタム機能をプラグインして、処理のために スパイダー に送信されるレスポンスを処理し、スパイダーから生成されたリクエストとアイテムを処理できます。

スパイダー・ミドルウェアをアクティブにする

スパイダー・ミドルウェア・コンポーネントをアクティブにするには、それを SPIDER_MIDDLEWARES 設定に追加します。これは、キーがミドルウェア・クラス・パスであり、値がミドルウェアの順序値である辞書です。

以下に例があります:

SPIDER_MIDDLEWARES = {
    'myproject.middlewares.CustomSpiderMiddleware': 543,
}

SPIDER_MIDDLEWARES 設定は、Scrapyで定義された SPIDER_MIDDLEWARES_BASE 設定とマージされ(オーバーライドされることはありません)、有効なミドルウェアの最終ソート・リストを取得するために順序値の昇順にソートされます。最初がエンジンに近い方でスパイダーに近い方が最後です。 つまり、各ミドルウェアの process_spider_input() メソッドは、ミドルウェアの昇順(100、200、300、…)で呼び出され、各ミドルウェアの process_spider_output() メソッドは、降順に呼び出されます。

ミドルウェアに割り当てる順序を決定するには、 SPIDER_MIDDLEWARES_BASE 設定を参照し、ミドルウェアを挿入する場所に応じて値を選択します。 各ミドルウェアは異なるアクションを実行し、ミドルウェアは適用される以前の(または後続の)ミドルウェアに依存する可能性があるため、順序は重要です。

組み込みミドルウェア( SPIDER_MIDDLEWARES_BASE で定義され、デフォルトで有効になっているミドルウェア)を無効にする場合は、プロジェクトの SPIDER_MIDDLEWARES 設定で定義し、その値として None を割り当てる必要があります。たとえば、オフサイト・ミドルウェアを無効にする場合は次の通りです:

SPIDER_MIDDLEWARES = {
    'myproject.middlewares.CustomSpiderMiddleware': 543,
    'scrapy.spidermiddlewares.offsite.OffsiteMiddleware': None,
}

最後に、特定の設定で一部のミドルウェアを有効にする必要がある場合があることに注意してください。 詳細については、各ミドルウェアのドキュメントを参照してください。

あなた自身のスパイダー・ミドルウェアを書く

各スパイダー・ミドルウェアは、以下で定義される1つ以上のメソッドを定義するPythonクラスです。

メインのエントリーポイントは from_crawler クラス・メソッドで、これは Crawler インスタンスを受け取ります。 Crawler オブジェクトは、たとえば 設定 へのアクセスを提供します。

class scrapy.spidermiddlewares.SpiderMiddleware
process_spider_input(response, spider)

このメソッドは、処理のためにスパイダー・ミドルウェアを通過してスパイダーに送信される各レスポンスに対して呼び出されます。

process_spider_input()None を返すか、例外を発生させます。

None を返す場合、Scrapyはこのレスポンスの処理を続行し、最後にレスポンスがスパイダーに渡されて処理されるまで、他のすべてのミドルウェアを実行します。

例外が発生した場合、Scrapyは他のスパイダーミドルウェアの process_spider_input() を呼び出さず、リクエストがある場合はリクエストのerrbackを呼び出し、そうでない場合は process_spider_exception() チェーンを開始します。errbackの出力は、 process_spider_output() が処理するために別の方向に戻される(chain back)か、または、例外がを発生した場合は process_spider_exception() に戻り(chain back)ます。

パラメータ
  • response (Response object) -- 処理中のレスポンス

  • spider (Spider object) -- このレスポンスを意図したスパイダー

process_spider_output(response, result, spider)

このメソッドは、レスポンスを処理した後、Spiderから返された結果で呼び出されます。

process_spider_output()Request オブジェクトと item object の反復可能オブジェクト(iterable)を返さなければなりません。

パラメータ
  • response (Response object) -- スパイダーからこの出力を生成したレスポンス

  • result (an iterable of Request objects and item object) -- スパイダーによって返された結果

  • spider (Spider object) -- 結果が処理されているスパイダー

process_spider_exception(response, exception, spider)

このメソッドは、スパイダーまたは、(以前のスパイダー・ミドルウェアの) process_spider_output() メソッドが例外を発生させたときに呼び出されます。

process_spider_exception()None または Request オブジェクトと、 アイテム・オブジェクト の反復可能オブジェクト(iterable)を返す必要があります。

None が返された場合、Scrapyはこの例外の処理を続行し、処理するミドルウェア・コンポーネントが無くなってエンジンに到達するまで、続くミドルウェア・コンポーネントで process_spider_exception() を実行します。

反復可能オブジェクト(iterable)を返す場合、 process_spider_output() パイプラインは次のスパイダー・ミドルウェアから開始され、他の process_spider_exception() は呼び出されません。

パラメータ
  • response (Response object) -- 例外が発生したときに処理されているレスポンス

  • exception (Exception object) -- 発生した例外

  • spider (Spider object) -- 例外を発生させたスパイダー

process_start_requests(start_requests, spider)

このメソッドは、スパイダーの開始リクエストで呼び出され、レスポンスが関連付けられておらず、リクエストのみ(アイテムではなく)を返す必要があることを除いて、 process_spider_output() メソッドと同様に機能します。

( start_requests パラメーターで)反復可能オブジェクト(iterable)を受け取り、別の Request オブジェクトの反復可能オブジェクト(iterable)を返さなければなりません。

注釈

スパイダー・ミドルウェアでこのメソッドを実装する場合、(入力に従って)常に反復可能オブジェクトを返す必要があり、start_requests イテレータを消費しないでください。 Scrapyエンジンは、リクエスト開始を処理する能力がある間はリクエスト開始求を呼ぶように設計されているため、リクエスト開始イテレータは、スパイダーを停止するための他の条件(時間制限やアイテム/ページ数など)がある場合、事実上無限になります。

パラメータ
  • start_requests (an iterable of Request) -- リクエストの開始

  • spider (Spider object) -- 開始したリクエストが属するスパイダー

from_crawler(cls, crawler)

存在する場合、このクラスメソッドは Crawler からミドルウェア・インスタンスを作成するために呼び出されます。ミドルウェアの新しいインスタンスを返す必要があります。クローラー・オブジェクトは、設定や信号などのすべてのScrapyコアコンポーネントへのアクセスを提供します。それはミドルウェアがそれらにアクセスし、その機能をScrapyにフックする方法です。

パラメータ

crawler (Crawler object) -- このミドルウェアを使用するクローラー

組み込みのスパイダー・ミドルウェア・リファレンス

この文書では、Scrapyに付属するすべてのスパイダー・ミドルウェア・コンポーネントについて説明します。それらの使用方法と独自のスパイダー・ミドルウェアの作成方法については、 スパイダーミドルウェア使用ガイド を参照してください。

デフォルトで有効になっているコンポーネント(およびその順序)のリストについては、 SPIDER_MIDDLEWARES_BASE 設定を参照してください。

DepthMiddleware
class scrapy.spidermiddlewares.depth.DepthMiddleware[ソース]

DepthMiddlewareは、スクレイピングされるサイト内の各リクエストの深さを追跡するために使用されます。以前に値が設定された事がない場合は、request.meta['depth'] = 0 を設定し(通常は最初のリクエストのみ)、それ以外の場合は1インクリメントします。

スクレイピングする最大深度を制限したり、深度に基づいてリクエストの優先度を制御したりすることができます。

DepthMiddleware は次の設定で設定できます(詳細については設定ドキュメントを参照してください):

  • DEPTH_LIMIT - 任意のサイトでクロールできる最大深度。ゼロの場合、制限は課されません。

  • DEPTH_STATS_VERBOSE - 各深さのレベルでリクエスト数を収集するかどうか。

  • DEPTH_PRIORITY - 深さに基づいてリクエストに優先順位を付けるかどうか。

HttpErrorMiddleware
class scrapy.spidermiddlewares.httperror.HttpErrorMiddleware[ソース]

失敗した(誤った)HTTPレスポンスをフィルター処理して、スパイダーがそれらに対処する必要がないようにします。これにより、(ほとんどの場合)オーバーヘッドが発生し、より多くのリソースが消費され、スパイダー・ロジックがより複雑になります。

HTTP standard によると、成功したレスポンスとは、ステータスコードが200〜300の範囲です。

それでもその範囲外のレスポンス・コードを処理したい場合は、 handle_httpstatus_list スパイダー属性または HTTPERROR_ALLOWED_CODES 設定を使用して、スパイダーが処理できるレスポンス・コードを指定できます。

たとえば、スパイダーに404 レスポンスを処理させたい場合、以下を行うことができます:

class MySpider(CrawlSpider):
    handle_httpstatus_list = [404]

Request.metahandle_httpstatus_list キーを使用して、リクエストごとに許可するレスポンス・コードを指定することもできます。 また、メタキー handle_httpstatus_allTrue に設定すると、リクエストに対する任意のレスポンス・コードを許可し、 Falsehandle_httpstatus_all キーの効果を無効にすることができます。

ただし、自分が何をしているのか本当にわかっていない限り、200以外の応答を処理することは通常良くない考えです。

詳細情報は HTTP Status Code Definitions を参照ください。

HttpErrorMiddleware 設定
HTTPERROR_ALLOWED_CODES

デフォルト: []

このリストに含まれる、200以外のステータ・スコードを持つすべてのレスポンスを渡します。

HTTPERROR_ALLOW_ALL

デフォルト: False

ステータスコードに関係なく、すべてのレスポンスを渡します。

OffsiteMiddleware
class scrapy.spidermiddlewares.offsite.OffsiteMiddleware[ソース]

スパイダーが対象とするドメインから外れているURLのリクエストを除外します。

このミドルウェアは、スパイダーの allowed_domains 属性にない全てのホスト名のリクエストを除外します。なお、リスト内のドメインのすべてのサブドメインも許可されます。 例えば、ルール www.example.orgbob.www.example.org も許可しますが、 www2.example.comexample.com も許可しません。

スパイダーがカバーするドメインに属していないドメインへのリクエストをスパイダーが返すと、このミドルウェアは、以下に似たデバッグ・メッセージを記録します:

DEBUG: Filtered offsite request to 'www.othersite.com': <GET http://www.othersite.com/some/page.html>

ログが過剰なノイズでいっぱいになるのを避けるため、フィルターされた新しいドメインごとにこれらのメッセージの1つのみを出力します。そのため、たとえば、 www.othersite.com への別のリクエストがフィルタリングされた場合、ログメッセージは出力されません。 しかし、 someothersite.com へのリクエストがフィルターされると、メッセージが出力されます(ただし、フィルターされる最初のリクエストのみ)。

スパイダーが allowed_domains 属性を定義していない場合、または属性が空の場合、オフサイト・ミドルウェアはすべてのリクエストを許可します。

リクエストに dont_filter 属性が設定されている場合、そのドメインが許可されたドメインにリストされていなくても、オフサイト・ミドルウェアはリクエストを許可します。

RefererMiddleware
class scrapy.spidermiddlewares.referer.RefererMiddleware[ソース]

リクエストを生成したレスポンスのURLに基づいて、リクエスト Referer ヘッダーを生成します。

RefererMiddleware 設定
REFERER_ENABLED

デフォルト: True

リファラー・ミドルウェアを有効にするかどうか。

REFERRER_POLICY

デフォルト: 'scrapy.spidermiddlewares.referer.DefaultReferrerPolicy'

リクエストの "Referer" ヘッダーを設定するときに適用する Referrer Policy

注釈

Request.meta の特別な "referrer_policy" キーを使用して、 REFERRER_POLICY 設定と同じ許容値を使用して、リクエストごとにリファラー・ポリシーを設定することもできます。

REFERRER_POLICYが受け入れる値
  • scrapy.spidermiddlewares.referer.ReferrerPolicy サブクラスへのパス - カスタム・ポリシーまたは組み込みポリシーのいずれか(以下のクラスを参照)

  • または、標準のW3C定義の文字列値のいずれか

  • または特別な "scrapy-default"

文字列値

クラス名(文字列)

"scrapy-default" (デフォルト)

scrapy.spidermiddlewares.referer.DefaultReferrerPolicy

"no-referrer"

scrapy.spidermiddlewares.referer.NoReferrerPolicy

"no-referrer-when-downgrade"

scrapy.spidermiddlewares.referer.NoReferrerWhenDowngradePolicy

"same-origin"

scrapy.spidermiddlewares.referer.SameOriginPolicy

"origin"

scrapy.spidermiddlewares.referer.OriginPolicy

"strict-origin"

scrapy.spidermiddlewares.referer.StrictOriginPolicy

"origin-when-cross-origin"

scrapy.spidermiddlewares.referer.OriginWhenCrossOriginPolicy

"strict-origin-when-cross-origin"

scrapy.spidermiddlewares.referer.StrictOriginWhenCrossOriginPolicy

"unsafe-url"

scrapy.spidermiddlewares.referer.UnsafeUrlPolicy

class scrapy.spidermiddlewares.referer.DefaultReferrerPolicy[ソース]

"no-referrer-when-downgrade" の変形(variant)。さらに、親リクエストが file:// または s3:// スキームを使用している場合、 "Referer" は送信されません。

警告

" no-referrer-when-downgrade " のように、ブラウザのW3C推奨値である、Scrapyのデフォルトのリファラー・ポリシーは、ドメインが異なっていても、 任意の http(s):// から空でない "Referer" ヘッダーをすべての https:// に送信します。

クロス・ドメイン・リクエストのリファラー情報を削除する場合は、 "same-origin" の方が適している場合があります。

class scrapy.spidermiddlewares.referer.NoReferrerPolicy[ソース]

https://www.w3.org/TR/referrer-policy/#referrer-policy-no-referrer

最も単純なポリシーは「no-referrer」です。これは、特定のリクエスト・クライアントからのリクエストとともにリファラー情報を任意のオリジン(origin)に送信しないことを指定します。ヘッダーは完全に省略されます。

class scrapy.spidermiddlewares.referer.NoReferrerWhenDowngradePolicy[ソース]

https://www.w3.org/TR/referrer-policy/#referrer-policy-no-referrer-when-downgrade

"no-referrer-when-downgrade" ポリシーは、TLSで保護された環境設定オブジェクトから潜在的に信頼できるURLへのリクエスト、およびTLSで保護されていないクライアントからのリクエストとともに完全なURLを送信します。

一方、TLSで保護されたクライアントから潜在的に信頼できないURLへの要求には、リファラー情報は含まれません。 Referer HTTPヘッダーは送信されません。

ポリシーが指定されていない場合、これはユーザー・エージェントのデフォルトの振る舞いです。

注釈

"no-referrer-when-downgrade" ポリシーはW3C推奨のデフォルトであり、主要なWebブラウザーで使用されます。

ただし、それはScrapyのデフォルトのリファラー・ポリシーではありません( DefaultReferrerPolicy を参照)。

class scrapy.spidermiddlewares.referer.SameOriginPolicy[ソース]

https://www.w3.org/TR/referrer-policy/#referrer-policy-same-origin

"same-origin"ポリシー(同一オリジン・ポリシー)は、特定のリクエスト・クライアントから同一オリジン・リクエストを行うときに、リファラーとして使用するために取り除かれた完全なURLがリファラー情報として送信されることを指定します。

一方、クロス・オリジンリ・クエストにはリファラー情報は含まれません。リファラーHTTPヘッダーは送信されません。

class scrapy.spidermiddlewares.referer.OriginPolicy[ソース]

https://www.w3.org/TR/referrer-policy/#referrer-policy-origin

オリジン・ポリシーは、特定のリクエスト・クライアントから同一オリジン・リクエストとクロス・オリジン・リクエストの両方を行うときに、リクエスト・クライアントのオリジンのASCIIシリアル化のみがリファラー情報として送信されることを指定します。

class scrapy.spidermiddlewares.referer.StrictOriginPolicy[ソース]

https://www.w3.org/TR/referrer-policy/#referrer-policy-strict-origin

strict-originポリシーは、リクエストを行うときにリクエスト・クライアントの発信元のASCIIシリアル化を送信します。-TLSで保護された環境設定オブジェクトから潜在的に信頼できるURLへ、そして、TLSで保護されていない環境設定オブジェクトから任意のオリジンへ。

一方、TLSで保護されたリクエスト・クライアントから潜在的に信頼できないURLへのリクエストには、リファラー情報は含まれません。

class scrapy.spidermiddlewares.referer.OriginWhenCrossOriginPolicy[ソース]

https://www.w3.org/TR/referrer-policy/#referrer-policy-origin-when-cross-origin

origin-when-cross-originポリシーは、リファラーとして使用するために分割(strip)された完全なURLが、特定のリクエスト・クライアントから同一オリジン・リクエストを行うときにリファラー情報として送信され、リクエスト・クライアントは、特定の要求クライアントからクロス・オリジン・リクエストを行うときに、リファラー情報として送信されます。

class scrapy.spidermiddlewares.referer.StrictOriginWhenCrossOriginPolicy[ソース]

https://www.w3.org/TR/referrer-policy/#referrer-policy-strict-origin-when-cross-origin

strict-origin-when-cross-originポリシーは、リファラーとして使用するために取り除かれた完全なURLが、特定のリクエスト・クライアントから同一オリジン・リクエストを行うときにリファラー情報として送信されることを指定します。クロス・オリジン・リクエストを行うときのリクエスト・クライアントのオリジン:

  • TLSで保護された環境設定オブジェクトから潜在的に信頼できるURLへ、そして、

  • TLSで保護されていない環境設定オブジェクトから任意のオリジン(origin)へ。

一方、TLSで保護されたクライアントから信頼できない可能性のあるURLへの要求には、リファラー情報は含まれません。 Referer HTTPヘッダーは送信されません。

class scrapy.spidermiddlewares.referer.UnsafeUrlPolicy[ソース]

https://www.w3.org/TR/referrer-policy/#referrer-policy-unsafe-url

unsafe-urlポリシーは、リファラーとして使用するために分割(strip)された完全なURLが、特定のリクエスト・クライアントからのクロス・オリジン・リクエストと同一オリジン・リクエストの両方とともに送信されることを指定します。

注:ポリシーの名前に頼ってはいけません。安全ではありません。このポリシーは、TLSで保護されたリソースから安全でないオリジンにオリジンとパスをリークします。機密性の高いドキュメントに対してこのようなポリシーを設定した場合の影響を慎重に検討してください。

警告

"unsafe-url" ポリシーは 推奨されません

UrlLengthMiddleware
class scrapy.spidermiddlewares.urllength.UrlLengthMiddleware[ソース]

URLLENGTH_LIMITより長いURLを持つリクエストを除外します

UrlLengthMiddleware は次の設定で構成(configure)できます(詳細については設定ドキュメントをご覧ください):

拡張機能

拡張フレームワークは、独自のカスタム機能をScrapyに挿入するメカニズムを提供します。

拡張機能は単なる通常のクラスです。

拡張機能の設定

拡張機能は Scrapy設定 を使用して、他のScrapyコードと同様に設定を管理します。

既存の(および将来の)拡張機能との衝突を避けるために、拡張機能が独自の名前を設定の前に付けるのが慣例です。たとえば、 Google Sitemaps を処理する仮想拡張機能では、 GOOGLESITEMAP_ENABLEDGOOGLESITEMAP_DEPTH などの設定を使用します。

拡張機能の読み込みとアクティブ化

拡張機能は、実行中のスパイダーごとに拡張機能クラスの単一インスタンスをインスタンス化することにより、起動時にロードおよびアクティブ化されます。すべての拡張機能初期化コードは、クラス __init__ メソッドで実行する必要があります。

拡張機能を使用可能にするには、Scrapy設定の EXTENSIONS 設定に追加します。 EXTENSIONS では、各拡張機能は文字列(拡張機能のクラス名への完全なPythonパス)で表されます。例えば以下のようにします:

EXTENSIONS = {
    'scrapy.extensions.corestats.CoreStats': 500,
    'scrapy.extensions.telnet.TelnetConsole': 500,
}

ご覧のとおり、 EXTENSIONS 設定はキーが拡張パスであり、その値が拡張機能 読み込み 順序値を定義する辞書です。 EXTENSIONS 設定は、Scrapyで定義された EXTENSIONS_BASE 設定とマージされ(但し、オーバーライドされることはありません)、有効な拡張機能の最終ソート・リストを取得するために順序値でソートされます。

通常、拡張機能は相互に依存しないため、ほとんどの場合、読み込み順序は無関係です。 これが EXTENSIONS_BASE 設定がすべての拡張機能を同じ順序値( 0 )で定義する理由です。ただし、すでに読み込まれているされている他の拡張機能に依存する拡張機能を追加する必要がある場合、この機能を利用できます。

利用可能な、デフォルトで有効およびデフォルトで無効な拡張機能

利用可能なすべての拡張機能が有効になるわけではありません。それらのいくつかは通常、特定の設定に依存しています。たとえば、HTTPキャッシュ拡張機能はデフォルトで使用可能ですが、 HTTPCACHE_ENABLED 設定が設定されていない限り無効になっています。

拡張機能を無効にする

デフォルトで有効になっている拡張機能(つまり、 EXTENSIONS_BASE 設定に含まれている拡張機能)を無効にするには、その順序値を None に設定する必要があります。 例えば以下のようにします:

EXTENSIONS = {
    'scrapy.extensions.corestats.CoreStats': None,
}

あなた自身の拡張機能を書く

各拡張機能はPythonクラスです。 Scrapy拡張機能の主なエントリ・ポイント(これにはミドルウェアとパイプラインも含まれます)は、 Crawler インスタンスを受け取る from_crawler クラスメソッドです。Crawlerオブジェクトを使用して、設定、信号、統計にアクセスしたり、クロール動作を制御したりできます。

通常、拡張機能は シグナル に接続し、それらによってトリガーされるタスクを実行します。

最後に、 from_crawler メソッドが NotConfigured 例外を発生させた場合、拡張機能は無効になります。 それ以外の場合、拡張機能は有効になります。

拡張機能例

ここでは、前のセクションで説明した概念を説明するために、簡単な拡張機能を実装します。この拡張機能は毎回メッセージを記録します:

  • スパイダーがオープンされます

  • スパイダーがクローズされます

  • 指定の数のアイテムがスクレイプされます

拡張機能は MYEXT_ENABLED 設定で有効になり、アイテムの数は MYEXT_ITEMCOUNT 設定で指定されます。

そのような拡張機能のコードは次のとおりです:

import logging
from scrapy import signals
from scrapy.exceptions import NotConfigured

logger = logging.getLogger(__name__)

class SpiderOpenCloseLogging:

    def __init__(self, item_count):
        self.item_count = item_count
        self.items_scraped = 0

    @classmethod
    def from_crawler(cls, crawler):
        # first check if the extension should be enabled and raise
        # NotConfigured otherwise
        if not crawler.settings.getbool('MYEXT_ENABLED'):
            raise NotConfigured

        # get the number of items from settings
        item_count = crawler.settings.getint('MYEXT_ITEMCOUNT', 1000)

        # instantiate the extension object
        ext = cls(item_count)

        # connect the extension object to signals
        crawler.signals.connect(ext.spider_opened, signal=signals.spider_opened)
        crawler.signals.connect(ext.spider_closed, signal=signals.spider_closed)
        crawler.signals.connect(ext.item_scraped, signal=signals.item_scraped)

        # return the extension object
        return ext

    def spider_opened(self, spider):
        logger.info("opened spider %s", spider.name)

    def spider_closed(self, spider):
        logger.info("closed spider %s", spider.name)

    def item_scraped(self, item, spider):
        self.items_scraped += 1
        if self.items_scraped % self.item_count == 0:
            logger.info("scraped %d items", self.items_scraped)

組み込み拡張機能リファレンス

汎用拡張機能
ログ統計拡張機能
class scrapy.extensions.logstats.LogStats[ソース]

クロールされたページやスクレイプされたアイテムなどの基本的な統計情報を記録します。

コア統計拡張機能
class scrapy.extensions.corestats.CoreStats[ソース]

統計コレクションが有効になっている場合、コア統計のコレクションを有効にします( 統計をとる 参照)。

Telnetコンソール拡張機能
class scrapy.extensions.telnet.TelnetConsole[ソース]

現在実行中のScrapyプロセス内のPythonインタープリターに入るためのTelnetコンソールを提供します。これはデバッグに非常に役立ちます。

telnetコンソールは TELNETCONSOLE_ENABLED 設定を有効にする必要があり、サーバーは TELNETCONSOLE_PORT で指定されたポートでリッスンします。

メモリ使用量の拡張機能
class scrapy.extensions.memusage.MemoryUsage[ソース]

注釈

この拡張機能はWindowsでは機能しません。

スパイダーを実行するScrapyプロセスが使用するメモリを監視し、そして:

  1. 特定の値を超えたときに通知メールを送信します

  2. 特定の値を超えたときにスパイダーを閉じます

MEMUSAGE_WARNING_MB が特定の警告値に達し、かつ、 MEMUSAGE_LIMIT_MB が最大値に達すると通知メールがトリガーされ、スパイダーが閉じられてScrapyプロセスが終了(terminate)します。

この拡張機能は MEMUSAGE_ENABLED 設定によって有効になり、以下設定で構成(configure)できます:

メモリ・デバッガー拡張機能
class scrapy.extensions.memdebug.MemoryDebugger[ソース]

メモリ使用量をデバッグするための拡張機能。 以下に関する情報を収集します:

この拡張機能を有効にするには、 MEMDEBUG_ENABLED 設定をオンにします。情報は統計に保存されます。

スパイダー拡張機能を閉じる
class scrapy.extensions.closespider.CloseSpider[ソース]

各条件に特定の終了理由を使用して、いくつかの条件が満たされたときにスパイダーを自動的に閉じます。

スパイダーを閉じるための条件は、以下の設定で構成(configure)できます:

注釈

特定の終了条件が満たされた場合でも、現在ダウンローダー・キューにあるリクエスト(その最大値は CONCURRENT_REQUESTS による) は引き続き処理されます。

CLOSESPIDER_TIMEOUT

デフォルト: 0

秒数を指定する整数。 スパイダーがその秒数を超えて開いたままの場合、理由を closespider_timeout として自動的に閉じられます。ゼロ(または設定されていない)の場合、スパイダーはタイムアウトによって閉じられません。

CLOSESPIDER_ITEMCOUNT

デフォルト: 0

アイテムの数を指定する整数。 スパイダーがその量を超えてスクレイピングし、それらのアイテムがアイテム・パイプラインを通過した場合、スパイダーは closespider_itemcount という理由で閉じられます。 ゼロ(または設定されていない)場合、スパイダーは渡されたアイテムの数によって閉じられる事はありません。

CLOSESPIDER_PAGECOUNT

デフォルト: 0

クロールするレスポンスの最大数を指定する整数。 スパイダーがそれ以上クロールした場合、スパイダーは理由 `` closespider_pagecount`` によって閉じられます。ゼロ(または未設定)の場合、クロールされたレスポンスの数に応じてスパイダーが閉じられることはありません。

CLOSESPIDER_ERRORCOUNT

デフォルト: 0

スパイダーを閉じる前に受け取るエラーの最大数を指定する整数。 スパイダーがその数を超えるエラーを生成した場合、 closespider_errorcount の理由で閉じられます。ゼロ(または設定されていない)の場合、スパイダーはエラーの数に応じて閉じられることはありせん。

StatsMailer拡張機能
class scrapy.extensions.statsmailer.StatsMailer[ソース]

この単純な拡張機能を使用して、収集されたScrapy統計など、ドメインがスクレイピングを完了するたびに通知メールを送信できます。 メールは、 STATSMAILER_RCPTS 設定で指定されたすべての受信者に送信されます。

拡張機能のデバッグ
拡張機能のスタックトレースをダンプする
class scrapy.extensions.debug.StackTraceDump[ソース]

SIGQUIT または SIGUSR2 シグナルを受信したときに、実行中のプロセスに関する情報をダンプします。ダンプされる情報は次のとおりです:

  1. エンジンの状態( scrapy.utils.engine.get_engine_status() を使用)

  2. 生存中の参照( trackref を使用したメモリ・リークのデバッグ を参照 )

  3. 全てのスレッドのスタックトレース

スタック・トレースとエンジン・ステータスがダンプされた後、Scrapyプロセスは正常に実行を続けます。

SIGQUIT および SIGUSR2 シグナルはWindowsでは利用できないため、この拡張機能はPOSIX準拠のプラットフォーム(つまり、Windowsではない)でのみ機能します。

Scrapyに SIGQUIT シグナルを送信するには、少なくとも2つの方法があります:

  1. Scrapyプロセスの実行中にCtrl-を押す(Linuxのみ?)

  2. 以下のコマンドを実行( <pid> がScrapyプロセスのプロセスIDであるとして):

    kill -QUIT <pid>
    
デバッガー拡張機能
class scrapy.extensions.debug.Debugger[ソース]

SIGUSR2 シグナルを受信すると、実行中のScrapyプロセス内で Pythonデバッガ を呼び出します。 デバッガが終了した後、Scrapyプロセスは正常に実行を続けます。

詳細は Debugging in Python 参照。

この拡張機能はPOSIX準拠のプラットフォームでのみ機能します(つまり、Windowsでは機能しません)。

コアAPI

この節は、ScrapyコアAPIについて説明します。これは、拡張機能とミドルウェアの開発者を対象としています。

クローラーAPI

Scrapy APIの主要なエントリポイントは、 from_crawler クラス・メソッドを通じて拡張機能に渡される Crawler オブジェクトです。 このオブジェクトは、すべてのScrapyコア・コンポーネントへのアクセスを提供し、拡張機能がそれらにアクセスし、その機能をScrapyにフックする唯一の方法です。

拡張機能マネージャーは、インストールされた拡張機能を読み込んで追跡する責任があり、利用可能な全ての拡張機能の辞書と、 ダウンローダー・ミドルウェアの構成(configure) 方法と類似した順序を含む EXTENSIONS 設定で構成(configure)されます。

class scrapy.crawler.Crawler(spidercls, settings)[ソース]

Crawlerオブジェクトは、 scrapy.spiders.Spider のサブクラスと scrapy.settings.Settings オブジェクトでインスタンス化する必要があります。

settings

このクローラーの設定マネージャ

これは、拡張機能とミドルウェアがこのクローラーのScrapy設定にアクセスするために使用します。

Scrapy設定の概要については、設定 を参照してください。

APIについては、 Settings クラスを参照してください。

signals

このクローラーのシグナル・マネージャ

これは、拡張機能およびミドルウェアがScrapy機能にフックするために使用されます。

シグナルの概要については、 シグナル を参照してください。

APIについては、 SignalManager クラスを参照してください。

stats

このクローラーの統計収集器

これは拡張機能とミドルウェアから使用され、その動作の統計を記録したり、他の拡張機能によって収集された統計にアクセスしたりします。

統計収集器の概要は 統計をとる を参照下さい。

APIについては StatsCollector クラス参照。

extensions

有効な拡張機能を追跡(track)する拡張機能マネージャ

ほとんどの拡張機能は、この属性にアクセスする必要はありません。

拡張機能の紹介と、Scrapyで利用可能な拡張機能のリストについては、 拡張機能 を参照してください。

engine

スケジューラ、ダウンローダー、スパイダーの間のコア・クロール・ロジックを調整する実行エンジン。

一部の拡張機能では、Scrapyエンジンにアクセスして、ダウンローダーとスケジューラの動作を検査または変更することができますが、これは高度な使用方法であり、このAPIはまだ安定していません。

spider

現在スパイダーがクロールされています。これはクローラーの構築中に提供されるスパイダー・クラスのインスタンスであり、 crawl() メソッドで指定された引数の後に作成されます。

crawl(*args, **kwargs)[ソース]

指定された args 引数と kwargs 引数を使用してスパイダー・クラスをインスタンス化することでクローラーを起動し、実行エンジンを起動します。

クロールが終了したときに起動される遅延オブジェクトを返します。

stop()[ソース]

Starts a graceful stop of the crawler and returns a deferred that is fired when the crawler is stopped.

class scrapy.crawler.CrawlerRunner(settings=None)[ソース]

This is a convenient helper class that keeps track of, manages and runs crawlers inside an already setup reactor.

The CrawlerRunner object must be instantiated with a Settings object.

This class shouldn't be needed (since Scrapy is responsible of using it accordingly) unless writing scripts that manually handle the crawling process. See スクリプトからScrapyを実行する for an example.

crawl(crawler_or_spidercls, *args, **kwargs)[ソース]

Run a crawler with the provided arguments.

It will call the given Crawler's crawl() method, while keeping track of it so it can be stopped later.

If crawler_or_spidercls isn't a Crawler instance, this method will try to create one using this parameter as the spider class given to it.

Returns a deferred that is fired when the crawling is finished.

パラメータ
  • crawler_or_spidercls (Crawler instance, Spider subclass or string) -- already created crawler, or a spider class or spider's name inside the project to create it

  • args -- arguments to initialize the spider

  • kwargs -- keyword arguments to initialize the spider

property crawlers

Set of crawlers started by crawl() and managed by this class.

create_crawler(crawler_or_spidercls)[ソース]

Return a Crawler object.

  • If crawler_or_spidercls is a Crawler, it is returned as-is.

  • If crawler_or_spidercls is a Spider subclass, a new Crawler is constructed for it.

  • If crawler_or_spidercls is a string, this function finds a spider with this name in a Scrapy project (using spider loader), then creates a Crawler instance for it.

join()[ソース]

Returns a deferred that is fired when all managed crawlers have completed their executions.

stop()[ソース]

Stops simultaneously all the crawling jobs taking place.

Returns a deferred that is fired when they all have ended.

class scrapy.crawler.CrawlerProcess(settings=None, install_root_handler=True)[ソース]

ベースクラス: scrapy.crawler.CrawlerRunner

A class to run multiple scrapy crawlers in a process simultaneously.

This class extends CrawlerRunner by adding support for starting a reactor and handling shutdown signals, like the keyboard interrupt command Ctrl-C. It also configures top-level logging.

This utility should be a better fit than CrawlerRunner if you aren't running another reactor within your application.

The CrawlerProcess object must be instantiated with a Settings object.

パラメータ

install_root_handler -- whether to install root logging handler (default: True)

This class shouldn't be needed (since Scrapy is responsible of using it accordingly) unless writing scripts that manually handle the crawling process. See スクリプトからScrapyを実行する for an example.

crawl(crawler_or_spidercls, *args, **kwargs)

Run a crawler with the provided arguments.

It will call the given Crawler's crawl() method, while keeping track of it so it can be stopped later.

If crawler_or_spidercls isn't a Crawler instance, this method will try to create one using this parameter as the spider class given to it.

Returns a deferred that is fired when the crawling is finished.

パラメータ
  • crawler_or_spidercls (Crawler instance, Spider subclass or string) -- already created crawler, or a spider class or spider's name inside the project to create it

  • args -- arguments to initialize the spider

  • kwargs -- keyword arguments to initialize the spider

property crawlers

Set of crawlers started by crawl() and managed by this class.

create_crawler(crawler_or_spidercls)

Return a Crawler object.

  • If crawler_or_spidercls is a Crawler, it is returned as-is.

  • If crawler_or_spidercls is a Spider subclass, a new Crawler is constructed for it.

  • If crawler_or_spidercls is a string, this function finds a spider with this name in a Scrapy project (using spider loader), then creates a Crawler instance for it.

join()

Returns a deferred that is fired when all managed crawlers have completed their executions.

start(stop_after_crawl=True)[ソース]

This method starts a reactor, adjusts its pool size to REACTOR_THREADPOOL_MAXSIZE, and installs a DNS cache based on DNSCACHE_ENABLED and DNSCACHE_SIZE.

If stop_after_crawl is True, the reactor will be stopped after all crawlers have finished, using join().

パラメータ

stop_after_crawl (bool) -- stop or not the reactor when all crawlers have finished

stop()

Stops simultaneously all the crawling jobs taking place.

Returns a deferred that is fired when they all have ended.

APIの設定

scrapy.settings.SETTINGS_PRIORITIES

Scrapyで使用されるデフォルト設定の優先度のキー名と優先度を設定する辞書。

各項目は設定エントリ・ポイントを定義し、識別のためのコード名と整数の優先度を与えます。 Settings クラスで値を設定および取得する場合、優先順位が高いほど順番値が小さくなります。

SETTINGS_PRIORITIES = {
    'default': 0,
    'command': 10,
    'project': 20,
    'spider': 30,
    'cmdline': 40,
}

各設定ソースの詳細な説明については、 設定 を参照してください。

scrapy.settings.get_settings_priority(priority)[ソース]

SETTINGS_PRIORITIES 辞書で特定の文字列優先度を検索し、その数値を返す、または特定の数値優先度を直接返す小さなヘルパー関数。

class scrapy.settings.Settings(values=None, priority='project')[ソース]

ベースクラス: scrapy.settings.BaseSettings

このオブジェクトは、内部コンポーネントの構成のためのScrapy設定を保存し、さらにカスタマイズするために使用できます。

これは直接のサブクラスであり、 BaseSettings のすべてのメソッドをサポートします。さらに、このクラスのインスタンス化の後、新しいオブジェクトには、すでに入力されている、 組み込みの設定リファレンス で説明されているグローバルなデフォルト設定が含まれます。

class scrapy.settings.BaseSettings(values=None, priority='project')[ソース]

このクラスのインスタンスは辞書のように動作しますが、 (key, value) ペアとともに優先度を保存し、凍結することができます(つまり、不変(immutable)とマークされます)。

キー値エントリは初期化時に values 引数で渡すことができ、それらは priority レベルを取ります( values がすでに BaseSettings のインスタンスである場合を除き。その場合、既存の優先度レベルが保持されます)。 priority 引数が文字列の場合、優先度名は SETTINGS_PRIORITIES で検索されます。それ以外の場合は、特定の整数を指定する必要があります。

オブジェクトが作成されると、新しい設定は set() メソッドを使用してロードまたは更新でき、辞書の角括弧表記または get() メソッドとその値変換variantを使用してアクセスできます。保存されたキーを要求すると、最高の優先度を持つ値が取得されます。

copy()[ソース]

現在の設定のdeepコピーを作成します。

このメソッドは、 Settings クラスの新しいインスタンスを返し、同じ値とその優先度が入力されます。

新しいオブジェクトへの変更は、元の設定には反映されません。

copy_to_dict()[ソース]

現在の設定のコピーを作成し、辞書に変換します。

このメソッドは、現在の設定と同じ値とそれらの優先度が設定された新しい辞書を返します。

返された辞書への変更は、元の設定には反映されません。

このメソッドは、Scrapyシェルの印刷(printing)設定などに役立ちます。

freeze()[ソース]

現在の設定への、さらなる変更を無効にします。

このメソッドを呼び出した後、設定の現在の状態は不変(immutable)になります。 :set() メソッドとその変形(variant)を使用して値を変更しようとすることは不可能であり、警告されます。

frozencopy()[ソース]

現在の設定の不変(immutable)のコピーを返します。

copy() によって返されるオブジェクトの freeze() 呼び出しのエイリアス。

get(name, default=None)[ソース]

元のタイプに影響を与えずに設定値を取得します。

パラメータ
  • name (str) -- 設定名

  • default (object) -- 設定が見つからない場合に返す値

getbool(name, default=False)[ソース]

設定値をブール値として取得します。

1'1'True`'True'True を返しますが、 0'0'False'False'NoneFalse を返します。

たとえば、 '0'``に設定された環境変数を通じて設定された設定は、このメソッドを使用するときに ``False を返します。

パラメータ
  • name (str) -- 設定名

  • default (object) -- 設定が見つからない場合に返す値

getdict(name, default=None)[ソース]

辞書として設定値を取得します。 設定元のタイプが辞書の場合、そのコピーが返されます。文字列の場合、JSON辞書として評価されます。それ自体が BaseSettings インスタンスである場合、それは辞書に変換され、 get() によって返される現在の設定値をすべて含み、優先度(priority)と可変性(mutability)に関するすべての情報を失います。

パラメータ
  • name (str) -- 設定名

  • default (object) -- 設定が見つからない場合に返す値

getfloat(name, default=0.0)[ソース]

設定値をfloatとして取得します。

パラメータ
  • name (str) -- 設定名

  • default (object) -- 設定が見つからない場合に返す値

getint(name, default=0)[ソース]

設定値をintとして取得します。

パラメータ
  • name (str) -- 設定名

  • default (object) -- 設定が見つからない場合に返す値

getlist(name, default=None)[ソース]

設定値をリストとして取得します。 設定元のタイプはリストであり、そのコピーが返されます。 文字列の場合、","で分割されます。

たとえば、 'one,two' に設定された環境変数を通じて設定された設定は、このメソッドを使用するときにリスト ['one', 'two'] を返します。

パラメータ
  • name (str) -- 設定名

  • default (object) -- 設定が見つからない場合に返す値

getpriority(name)[ソース]

設定の現在の数値優先順位値を返します。指定された name が存在しない場合は None を返します。

パラメータ

name (str) -- 設定名

getwithbase(name)[ソース]

辞書のような設定と、それに対応する _BASE の合成を取得します。

パラメータ

name (str) -- 辞書風設定の名前

maxpriority()[ソース]

すべての設定を通して存在する最も高い優先度の数値を返します。設定が保存されていない場合は、 SETTINGS_PRIORITIES から default の数値を返します。

set(name, value, priority='project')[ソース]

指定の優先度でキー/値属性を保存します。

( configure() メソッドを使用して、)Crawlerオブジェクトを設定する前に、設定を読み込む必要があります。設定しないと、効果がありません。

パラメータ
  • name (str) -- 設定名

  • value (object) -- 設定に関連付ける値

  • priority (str or int) -- 設定の優先順位。 SETTINGS_PRIORITIES のキーまたは整数でなければなりません

setmodule(module, priority='project')[ソース]

与えられた優先度でモジュールの設定を保存します。

これは、提供された prioritymodule のグローバルに宣言されたすべての大文字変数に対して set() を呼び出すヘルパー関数です。

パラメータ
  • module (types.ModuleType or str) -- モジュールまたは、モジュールのパス(path)

  • priority (str or int) -- 設定の優先順位。 SETTINGS_PRIORITIES のキーまたは整数でなければなりません

update(values, priority='project')[ソース]

与えられた優先度で キー/値 のペアを保存します。

これは、提供された priority を持つ values のすべての項目に対して set() を呼び出すヘルパー関数です。

values が文字列の場合、JSONエンコードされていると見なされ、最初に json.loads() でパースされ辞書になります。 BaseSettings`インスタンスの場合、キーごとの優先度が使用され、 ``priority` パラメーターは無視されます。 これにより、単一のコマンドで異なる優先度の設定を挿入/更新できます。

パラメータ
  • values (dict or string or BaseSettings) -- 設定名と値

  • priority (str or int) -- 設定の優先順位。 SETTINGS_PRIORITIES のキーまたは整数でなければなりません

SpiderLoader API

class scrapy.spiderloader.SpiderLoader[ソース]

このクラスは、プロジェクト全体で定義されたスパイダー・クラスの取得と処理を担当します。

SPIDER_LOADER_CLASS プロジェクト設定でパスを指定することにより、カスタム・スパイダー・ローダーを使用できます。エラーのない実行を保証するには、 scrapy.interfaces.ISpiderLoader インターフェースを完全に実装する必要があります。

from_settings(settings)[ソース]

このクラスメソッドは、クラスのインスタンスを作成するためにScrapyによって使用されます。現在のプロジェクト設定で呼び出され、 SPIDER_MODULES 設定のモジュールで見つかったスパイダーを再帰的にロードします。

パラメータ

settings (Settings instance) -- プロジェクト設定

load(spider_name)[ソース]

指定された名前のSpiderクラスを取得します。 spider_name という名前のスパイダークラスの、以前にロードされたスパイダーを調べ、見つからない場合はKeyErrorを発生させます。

パラメータ

spider_name (str) -- スパイダー・クラス名

list()[ソース]

プロジェクトで利用可能なスパイダーの名前を取得します。

find_by_request(request)[ソース]

指定されたリクエストを処理できるスパイダーの名前をリストします。リクエストのURLをスパイダーのドメインと照合しようとします。

パラメータ

request (Request instance) -- クエリされたリクエスト

シグナルAPI

class scrapy.signalmanager.SignalManager(sender=_Anonymous)[ソース]
connect(receiver, signal, **kwargs)[ソース]

Connect a receiver function to a signal.

The signal can be any object, although Scrapy comes with some predefined signals that are documented in the シグナル section.

パラメータ
disconnect(receiver, signal, **kwargs)[ソース]

Disconnect a receiver function from a signal. This has the opposite effect of the connect() method, and the arguments are the same.

disconnect_all(signal, **kwargs)[ソース]

Disconnect all receivers from the given signal.

パラメータ

signal (object) -- the signal to disconnect from

send_catch_log(signal, **kwargs)[ソース]

Send a signal, catch exceptions and log them.

The keyword arguments are passed to the signal handlers (connected through the connect() method).

send_catch_log_deferred(signal, **kwargs)[ソース]

Like send_catch_log() but supports returning Deferred objects from signal handlers.

Returns a Deferred that gets fired once all signal handlers deferreds were fired. Send a signal, catch exceptions and log them.

The keyword arguments are passed to the signal handlers (connected through the connect() method).

統計収集器API

scrapy.statscollectors モジュールの下にいくつかの統計収集器があり、それらはすべて StatsCollector クラス(すべての継承元)で定義された統計収集器APIを実装します。

class scrapy.statscollectors.StatsCollector[ソース]
get_value(key, default=None)[ソース]

指定された統計キーの値を返します。値が存在しない場合はデフォルトを返します。

get_stats()[ソース]

現在実行中のスパイダーからすべての統計を辞書として取得します。

set_value(key, value)[ソース]

与えられた統計キーに指定の値を設定します。

set_stats(stats)[ソース]

stats 引数で渡された辞書で現在の統計を上書きします。

inc_value(key, count=1, start=0)[ソース]

(設定されていない場合は開始値を想定して、)指定された統計キーの値を指定されたカウントでインクリメントします。

max_value(key, value)[ソース]

同じキーの現在の値がvalueより小さい場合にのみ、指定されたキーに指定された値を設定します。指定されたキーに現在の値がない場合、値は常に設定されます。

min_value(key, value)[ソース]

同じキーの現在の値がvalueより大きい場合にのみ、指定されたキーに指定された値を設定します。指定されたキーに現在の値がない場合、値は常に設定されます。

clear_stats()[ソース]

全ての統計をクリアする

次のメソッドは、統計収集APIの一部ではありませんが、代わりにカスタム統計収集器を実装するときに使用されます:

open_spider(spider)[ソース]

統計収集のために、指定されたスパイダーを開きます。

close_spider(spider)[ソース]

指定されたスパイダーを閉じます。これが呼び出された後、これ以上特定の統計にアクセスしたり収集したりすることはできません。

シグナル

Scrapyは、特定のイベントが発生したときに通知するためにシグナルを広範囲に使用します。 Scrapyプロジェクトでこれらのシグナルの一部をキャッチして(たとえば 拡張機能 で)、追加のタスクを実行したり、Scrapyを拡張してすぐに使用できない機能を追加したりできます。

シグナルはいくつかの引数を提供しますが、それらをキャッチするハンドラーはそれらのすべてを受け入れる必要はありません。シグナル・ディスパッチ・メカニズムはハンドラーが受け取る引数のみを配信します。

あなたは シグナルAPI を介してシグナルに接続(または独自に送信)できます。

シグナルをキャッチして何らかのアクションを実行する方法を示す簡単な例を次に示します:

from scrapy import signals
from scrapy import Spider


class DmozSpider(Spider):
    name = "dmoz"
    allowed_domains = ["dmoz.org"]
    start_urls = [
        "http://www.dmoz.org/Computers/Programming/Languages/Python/Books/",
        "http://www.dmoz.org/Computers/Programming/Languages/Python/Resources/",
    ]


    @classmethod
    def from_crawler(cls, crawler, *args, **kwargs):
        spider = super(DmozSpider, cls).from_crawler(crawler, *args, **kwargs)
        crawler.signals.connect(spider.spider_closed, signal=signals.spider_closed)
        return spider


    def spider_closed(self, spider):
        spider.logger.info('Spider closed: %s', spider.name)


    def parse(self, response):
        pass

シグナル・ハンドラーの遅延(deferred)

一部のシグナルはハンドラーから Deferred オブジェクトを返すことをサポートしており、Scrapy をブロックしない非同期コードを実行できます。 シグナルハンドラが Deferred を返した場合、Scrapy はその Deferred が起動するのを待ちます。

例を見てみましょう:

class SignalSpider(scrapy.Spider):
    name = 'signals'
    start_urls = ['http://quotes.toscrape.com/page/1/']

    @classmethod
    def from_crawler(cls, crawler, *args, **kwargs):
        spider = super(SignalSpider, cls).from_crawler(crawler, *args, **kwargs)
        crawler.signals.connect(spider.item_scraped, signal=signals.item_scraped)
        return spider

    def item_scraped(self, item):
        # Send the scraped item to the server
        d = treq.post(
            'http://example.com/post',
            json.dumps(item).encode('ascii'),
            headers={b'Content-Type': [b'application/json']}
        )

        # The next item will be scraped only after
        # deferred (d) is fired
        return d

    def parse(self, response):
        for quote in response.css('div.quote'):
            yield {
                'text': quote.css('span.text::text').get(),
                'author': quote.css('small.author::text').get(),
                'tags': quote.css('div.tags a.tag::text').getall(),
            }

どのシグナルが Deferred をサポートするかについては、以下の 組み込みシグナル・リファレンス を参照してください。

組み込みシグナル・リファレンス

Scrapy組み込みシグナルとその意味のリストを以下に示します。

エンジン・シグナル群
engine_started
scrapy.signals.engine_started()

Scrapyエンジンがクロールを開始すると送信されます。

このシグナルは、ハンドラーから遅延オブジェクト(deferred)を返すことをサポートしています。

注釈

このシグナルは、スパイダーの起動方法に応じて、 spider_opened シグナルの 後に 起動される場合があります。 そのため、 spider_opened の前にこのシグナルが発生することに依存しないでください。

engine_stopped
scrapy.signals.engine_stopped()

Scrapyエンジンが停止(stop)したときに送信されます(たとえば、クロール・プロセスが終了したとき)。

このシグナルは、ハンドラーから遅延オブジェクト(deferred)を返すことをサポートしています。

アイテム・シグナル群

注釈

最大 CONCURRENT_ITEMS 数のアイテムが並行して処理されるため、多くの遅延(deferred)は DeferredList を使用して同時に起動されます。 したがって、以下のバッチは DeferredList が起動するのを待ってから、スクレイピングされたアイテムの次のバッチに対してそれぞれのアイテム・シグナル・ハンドラーを実行します。

item_scraped
scrapy.signals.item_scraped(item, response, spider)

すべての アイテム・パイプライン ステージを(ドロップされることなく)通過した後、アイテムがスクレイプされたときに送信されます。

このシグナルは、ハンドラーから遅延オブジェクト(deferred)を返すことをサポートしています。

パラメータ
  • item (item object) -- スクレイプされたアイテム

  • spider (Spider object) -- アイテムをスクレイプしたスパイダー

  • response (Response object) -- アイテムがスクレイピングされたレスポンス

item_dropped
scrapy.signals.item_dropped(item, response, exception, spider)

あるステージで DropItem 例外が発生したときに、アイテムが アイテム・パイプライン からドロップされた後に送信されます。

このシグナルは、ハンドラーから遅延オブジェクト(deferred)を返すことをサポートしています。

パラメータ
  • item (item object) -- アイテム・パイプライン からドロップされたアイテム

  • spider (Spider object) -- アイテムをスクレイプしたスパイダー

  • response (Response object) -- アイテムがドロップされたレスポンス

  • exception (DropItem exception) -- アイテムがドロップされる原因となった例外( DropItem のサブクラスでなければなりません)

item_error
scrapy.signals.item_error(item, response, spider, failure)

DropItem 例外を除き、 アイテム・パイプライン がエラーを生成した(つまり、例外を発生させた)ときに送信されます。

このシグナルは、ハンドラーから遅延オブジェクト(deferred)を返すことをサポートしています。

パラメータ
スパイダー・シグナル群
spider_closed
scrapy.signals.spider_closed(spider, reason)

スパイダーが閉じられた後に送信されます。 これは、 spider_opened で予約しているスパイダーごとのリソースを解放するために使用できます。

このシグナルは、ハンドラーから遅延オブジェクト(deferred)を返すことをサポートしています。

パラメータ
  • spider (Spider object) -- スパイダーがクローズされた

  • reason (str) -- スパイダーが閉じられた理由を説明する文字列。 スパイダーがスクレイピングを完了したために閉じられた場合、その理由は 'finished' です。そうでなければ、 close_spider エンジン・メソッドを呼び出してスパイダーを手動で閉じた場合、その理由はそのメソッドの reason 数に渡されたものが使われます(デフォルトは 'cancelled' です)。エンジンがシャットダウン(たとえば、Ctrl-Cを押してエンジンを停止)された場合、理由は 'shutdown' です。

spider_opened
scrapy.signals.spider_opened(spider)

クロールのためにスパイダーがオープンされた後に送信されます。これは通常、スパイダーごとのリソースを予約するために使用されますが、スパイダーが開かれたときに実行する必要があるタスクに使用できます。

このシグナルは、ハンドラーから遅延オブジェクト(deferred)を返すことをサポートしています。

パラメータ

spider (Spider object) -- スパイダーがオープンされた

spider_idle
scrapy.signals.spider_idle(spider)

スパイダーがアイドル状態になったときに送信されます。つまり、スパイダーはそれ以降何もしない事を意味します:

  • リクエストがダウンロード待ち

  • リクエストがスケジュールされた

  • アイテムがアイテム・パイプラインで処理中

このシグナルのすべてのハンドラーが終了した後もアイドル状態が続く場合、エンジンはスパイダーを閉じ始めます。スパイダーのクローズが完了すると、 spider_closed シグナルが送信されます。

あなたは DontCloseSpider 例外を発生させて、スパイダーが閉じられないようにすることができます。

このシグナルは、ハンドラーから遅延オブジェクト(deferred)を返すことをサポートしていません。

パラメータ

spider (Spider object) -- アイドルに移行したスパイダー

注釈

あなたの spider_idle ハンドラーでいくつかのリクエストをスケジュールすると、スパイダーが閉じられるのを防ぐことができるという保証はありませんが、できる場合もあります。これは、スケジュールされたすべてのリクエストがスケジューラによって拒否された場合(たとえば、重複のためにフィルター処理された場合)、スパイダーがアイドル状態のままになる可能性があるためです。

spider_error
scrapy.signals.spider_error(failure, response, spider)

スパイダー・コールバックがエラーを生成する(つまり、例外を発生させる)ときに送信されます。

このシグナルは、ハンドラーから遅延オブジェクト(deferred)を返すことをサポートしていません。

パラメータ
  • failure (twisted.python.failure.Failure) -- 例外が発生した

  • response (Response object) -- 例外が発生したときに処理されていたレスポンス

  • spider (Spider object) -- 例外を発生させたスパイダー

リクエスト・シグナル群
request_scheduled
scrapy.signals.request_scheduled(request, spider)

エンジンが Request をスケジュールしたときに送信され、後でダウンロードされます。

このシグナルは、ハンドラーから遅延オブジェクト(deferred)を返すことをサポートしていません。

パラメータ
  • request (Request object) -- リクエストはスケジューラに到達した

  • spider (Spider object) -- スパイダーはリクエストを生成(yield)した

request_dropped
scrapy.signals.request_dropped(request, spider)

後でダウンロードされるようにエンジンによってスケジュールされた Request がスケジューラーによって拒否されたときに送信されます。

このシグナルは、ハンドラーから遅延オブジェクト(deferred)を返すことをサポートしていません。

パラメータ
  • request (Request object) -- リクエストはスケジューラに到達した

  • spider (Spider object) -- スパイダーはリクエストを生成(yield)した

request_reached_downloader
scrapy.signals.request_reached_downloader(request, spider)

Request がダウンローダーに到達すると送信されます。

このシグナルは、ハンドラーから遅延オブジェクト(deferred)を返すことをサポートしていません。

パラメータ
  • request (Request object) -- リクエストはダウンローダーに到達した

  • spider (Spider object) -- スパイダーはリクエストを生成(yield)した

request_left_downloader
scrapy.signals.request_left_downloader(request, spider)

バージョン 2.0 で追加.

失敗した場合でも、ダウンローダーを離れるときに Request が送信されます。

このシグナルは、ハンドラーから遅延オブジェクト(deferred)を返すことをサポートしていません。

パラメータ
  • request (Request object) -- リクエストはダウンローダーに到達した

  • spider (Spider object) -- スパイダーはリクエストを生成(yield)した

bytes_received

バージョン 2.2 で追加.

scrapy.signals.bytes_received(data, request, spider)

特定のリクエストに対してバイトのグループが受信されたときに、HTTP 1.1 および S3 ダウンロード・ハンドラーによって送信されます。 このシグナルは、同じリクエストに対して複数回発生する可能性があり、そのたびに部分的なデータが生成されます。 たとえば、25 kb のレスポンスのシナリオとしては、2 つの信号が 10 kb のデータで発信され、最後の信号が 5 kb のデータで発信されます。

このシグナルのハンドラは StopDownload 例外を発生させることで進行中のレスポンスのダウンロードを停止できます. 追加情報と例については、レスポンスのダウンロードの停止 トピックを参照してください。

このシグナルは、ハンドラーから遅延オブジェクト(deferred)を返すことをサポートしていません。

パラメータ
  • data (bytes object) -- ダウンロード・ハンドラーによって受信されたデータ

  • request (Request object) -- ダウンロードを生成したリクエスト

  • spider (Spider object) -- レスポンスに関連付けられたスパイダー

headers_received

バージョン 2.5 で追加.

scrapy.signals.headers_received(headers, request, spider)

追加のコンテンツをダウンロードする前に、特定のリクエストに対してレスポンス・ヘッダーが使用可能な場合に、HTTP 1.1 および S3 ダウンロード・ハンドラーによって送信されます。

このシグナルのハンドラは StopDownload 例外を発生させることで進行中のレスポンスのダウンロードを停止できます. 追加情報と例については、レスポンスのダウンロードの停止 トピックを参照してください。

このシグナルは、ハンドラーから遅延オブジェクト(deferred)を返すことをサポートしていません。

パラメータ
  • headers (scrapy.http.headers.Headers object) -- ダウンロード・ハンドラーによって受信されたヘッダー

  • body_length (int) -- レスポンス・ボディの期待するサイズ(バイト単位)

  • request (Request object) -- ダウンロードを生成したリクエスト

  • spider (Spider object) -- レスポンスに関連付けられたスパイダー

レスポンス・シグナル群
response_received
scrapy.signals.response_received(response, request, spider)

エンジンがダウンローダーから新しい Response を受信すると送信されます。

このシグナルは、ハンドラーから遅延オブジェクト(deferred)を返すことをサポートしていません。

パラメータ
  • response (Response object) -- レスポンスを受信した

  • request (Request object) -- レスポンスを生成したリクエスト

  • spider (Spider object) -- そのレスポンスを意図したスパイダー

注釈

ダウンローダー・ミドルウェアResponse オブジェクトを変更し、特定の request 属性を設定する場合、request 引数はダウンローダに届いた元のリクエストを含まない可能性があります。

response_downloaded
scrapy.signals.response_downloaded(response, request, spider)

HTTPResponse がダウンロードされた直後に、ダウンローダーによって送信されます。

このシグナルは、ハンドラーから遅延オブジェクト(deferred)を返すことをサポートしていません。

パラメータ
  • response (Response object) -- レスポンスがダウンロードされた

  • request (Request object) -- レスポンスを生成したリクエスト

  • spider (Spider object) -- そのレスポンスを意図したスパイダー

アイテム・エクスポーター

アイテムをスクレイピングしたら、他のアプリケーションでデータを使用するために、それらのアイテムを永続化またはエクスポートすることがよくあります。 つまり、結局のところ、それがスクレイピング・プロセス全体の目的です。

この目的のために、Scrapyは、XML、CSV、JSONなどのさまざまな出力形式のアイテム・エクスポーターのコレクションを提供します。

アイテム・エクスポーターの使用

あなたが急いでいて、アイテム・エクスポータを使用してスクレイプ・データを出力するだけの場合は、 フィード・エクスポート を参照してください。それ以外の場合または、アイテム・エクスポータがどのように機能するかを知りたい場合または、またはより多くのカスタム機能(デフォルトのエクスポートではカバーされてない機能)が必要な場合は、以下をお読みください。

アイテム・エクスポーターを使用するには、必要な引数でインスタンス化する必要があります。 各アイテム・エクスポーターには異なる引数が必要なため、 組み込みアイテム・エクスポーター・リファレンス で各エクスポーターのドキュメントを確認してください。エクスポーターをインスタンス化した後、以下の作業が必要です:

1.エクスポート・プロセスの開始を通知するために、メソッド start export() を呼び出します。

2.エクスポートする各アイテムに対して export_item() メソッドを呼び出します

3.最後に finish export() を呼び出して、エクスポート・プロセスの終了を通知します

以下の アイテム・パイプライン をご覧ください。これは、複数のアイテム・エクスポーターを使用して、それらのフィールドの値に従って、スクレイプされたアイテムを異なるファイルにグループ化します:

from itemadapter import ItemAdapter
from scrapy.exporters import XmlItemExporter

class PerYearXmlExportPipeline:
    """Distribute items across multiple XML files according to their 'year' field"""

    def open_spider(self, spider):
        self.year_to_exporter = {}

    def close_spider(self, spider):
        for exporter, xml_file in self.year_to_exporter.values():
            exporter.finish_exporting()
            xml_file.close()

    def _exporter_for_item(self, item):
        adapter = ItemAdapter(item)
        year = adapter['year']
        if year not in self.year_to_exporter:
            xml_file = open(f'{year}.xml', 'wb')
            exporter = XmlItemExporter(xml_file)
            exporter.start_exporting()
            self.year_to_exporter[year] = (exporter, xml_file)
        return self.year_to_exporter[year][0]

    def process_item(self, item, spider):
        exporter = self._exporter_for_item(item)
        exporter.export_item(item)
        return item

アイテム・フィールドのシリアル化

デフォルトでは、フィールド値は変更されずに基礎となるシリアル化ライブラリに渡され、それらをシリアル化する方法の決定は特定の各シリアル化ライブラリに委任されます。

ただし、あなたは、各フィールド値をシリアル化する方法を、 シリアル化ライブラリに渡す前の段階で カスタマイズできます。

フィールドのシリアル化方法をカスタマイズするには、以下の2つの方法があります。

1. フィールドでシリアライザーを宣言する

あなたが Item を使用する場合、 フィールド・メタ・データ でシリアライザーを宣言できます。シリアライザーは、値を受け取り、シリアル化された形式を返す、呼び出し可能オブジェクトでなければなりません。

例:

import scrapy

def serialize_price(value):
    return f'$ {str(value)}'

class Product(scrapy.Item):
    name = scrapy.Field()
    price = scrapy.Field(serializer=serialize_price)
2. serialize_field() メソッドをオーバーライドする

あなたは serialize_field() メソッドをオーバーライドして、フィールド値のエクスポート方法をカスタマイズすることもできます。

カスタムコードの後に必ずベースクラス serialize_field() メソッドを呼び出してください。

例:

from scrapy.exporter import XmlItemExporter

class ProductXmlExporter(XmlItemExporter):

    def serialize_field(self, field, name, value):
        if field == 'price':
            return f'$ {str(value)}'
        return super().serialize_field(field, name, value)

組み込みアイテム・エクスポーター・リファレンス

Scrapyにバンドルされているアイテム・エクスポーターのリストを次に示します。それらの一部には、以下の2つのアイテムをエクスポートすることを想定した出力例が含まれています:

Item(name='Color TV', price='1200')
Item(name='DVD player', price='200')
BaseItemExporter
class scrapy.exporters.BaseItemExporter(fields_to_export=None, export_empty_fields=False, encoding='utf-8', indent=0, dont_fail=False)[ソース]

これは、すべてのアイテム・エクスポーターの(抽象的な)基本クラスです。 エクスポートするフィールド、空のフィールドをエクスポートするか、使用するエンコードを定義するなど、すべての(具体的な)アイテム・エクスポーターで使用される共通機能のサポートを提供します。

これらの機能は、それぞれのインスタンス属性を設定する __init__ メソッド引数を介して構成できます。それらは、 fields_to_exportexport_empty_fieldsencodingindent です。

バージョン 2.0 で追加: dont_fail パラメータ

export_item(item)[ソース]

与えられたアイテムをエクスポートします。このメソッドはサブクラスで実装する必要があります。

serialize_field(field, name, value)[ソース]

指定のフィールドのシリアル化された値を返します。特定のフィールドまたは値をシリアル化/エクスポートする方法を制御する場合は、カスタム・アイテム・エクスポーターでこのメソッドをオーバーライドできます。

デフォルトでは、このメソッドは アイテムフィールドで宣言された シリアライザーを検索し、そして、そのシリアライザーを値に適用した結果を返します。 シリアライザーが見つからない場合は、値を変更せずに返します。

パラメータ
  • field (Field object or a dict instance) -- シリアル化されるフィールド。 ソースの アイテム・オブジェクト がフィールド・メタデータを定義していない場合、 field は空の辞書( dict )です。

  • name (str) -- シリアル化されるフィールドの名前

  • value -- シリアル化される値

start_exporting()[ソース]

エクスポート・プロセスの開始を通知します。一部のエクスポーターはこれを使用して、必要なヘッダー( XmlItemExporter など)を生成します。アイテムをエクスポートする前に、このメソッドを呼び出す必要があります。

finish_exporting()[ソース]

エクスポート・プロセスの終了を通知します。一部のエクスポーターはこれを使用して、必要なフッター(たとえば、 XmlItemExporter )を生成します。エクスポートするアイテムがなくなったら、常にこのメソッドを呼び出す必要があります。

fields_to_export

エクスポートされるフィールドの名前のリスト、またはすべてのフィールドをエクスポートする場合は None 。デフォルトは None です。

一部のエクスポーター( CsvItemExporter など)は、この属性で定義されたフィールドの順序を尊重します。

可能なすべてのフィールドを公開しない アイテム・オブジェクト を使用する場合、アイテムごとに異なるサブセットのフィールドのエクスポートをサポートしないエクスポーターは、最初にエクスポートされたアイテムで見つかったフィールドのみをエクスポートします。 fields_to_export を使用して、エクスポートするすべてのフィールドを定義します。

export_empty_fields

エクスポートされたデータに空/未入力の項目フィールドを含めるかどうか。デフォルトは False です。 一部のエクスポーター( CsvItemExporter など)はこの属性を無視し、常にすべての空のフィールドをエクスポートします。

このオプションは、辞書アイテムでは無視されます。

encoding

出力キャラクタ・エンコーディング

indent

各レベルで出力をインデントするために使用されるスペースの量。デフォルトは 0 です。

  • indent=None は、全てのアイテムを同一行にインテント無しで出力する、最もコンパクトな表現を選択します

  • indent<=0 はアイテム毎に行を分けますが、インデントはありません

  • indent>0 はアイテム毎に行を分け、指定した数値でインデントします

PythonItemExporter
class scrapy.exporters.PythonItemExporter(*, dont_fail=False, **kwargs)[ソース]

これは、ネストされたアイテムをサポートする BaseItemExporter を拡張するアイテム・エクスポーターの基本クラスです。

アイテムをPython組み込み型にシリアル化するため、シリアル化ライブラリ(例: json または msgpack )をその上で使用できます。

XmlItemExporter
class scrapy.exporters.XmlItemExporter(file, item_element='item', root_element='items', **kwargs)[ソース]

指定のファイルオブジェクトにアイテムをXML形式でエクスポートします。

パラメータ
  • file -- データのエクスポートに使用するファイルのようなオブジェクト。 その write メソッドは bytes (バイナリ・モードで開かれたディスクファイルや、 io.BytesIO オブジェクトなど)を受け入れる必要があります

  • root_element (str) -- エクスポートされたXMLのルート要素の名前。

  • item_element (str) -- エクスポートされたXMLの各アイテム要素の名前。

この __init__ メソッドの追加のキーワード引数は、 BaseItemExporter__init__ メソッドに渡されます。

このエクスポーターの典型的な出力は次のようになります:

<?xml version="1.0" encoding="utf-8"?>
<items>
  <item>
    <name>Color TV</name>
    <price>1200</price>
 </item>
  <item>
    <name>DVD player</name>
    <price>200</price>
 </item>
</items>

serialize_field() メソッドでオーバーライドされない限り、複数の値を持つフィールドは <value> 要素内の各値をシリアル化することでエクスポートされます。複数値フィールドは非常に一般的であるため、これは便宜上のものです。

例えば、以下のアイテム:

Item(name=['John', 'Doe'], age='23')

これがシリアル化されると以下のようになります:

<?xml version="1.0" encoding="utf-8"?>
<items>
  <item>
    <name>
      <value>John</value>
      <value>Doe</value>
    </name>
    <age>23</age>
  </item>
</items>
CsvItemExporter
class scrapy.exporters.CsvItemExporter(file, include_headers_line=True, join_multivalued=',', errors=None, **kwargs)[ソース]

与えられたファイルのようなオブジェクトにCSV形式でアイテムをエクスポートします。 fields_to_export 属性が設定されている場合、CSV列とその順序を定義するために使用されます。 export_empty_fields 属性はこのエクスポーターには影響しません。

パラメータ
  • file -- データのエクスポートに使用するファイルのようなオブジェクト。 その write メソッドは bytes (バイナリ・モードで開かれたディスクファイルや、 io.BytesIO オブジェクトなど)を受け入れる必要があります

  • include_headers_line (str) -- 有効にすると、エクスポーターは BaseItemExporter.fields_to_export または最初にエクスポートされたアイテム・フィールドから取得したフィールド名を含むヘッダー行を出力します。

  • join_multivalued -- 複数値フィールドを結合するために使用される単一文字(または複数の文字)。

  • errors (str) -- エンコードおよびデコードエラーの処理方法を指定するオプションの文字列。 詳細については、 io.TextIOWrapper を参照してください。

この __init__ メソッドの追加のキーワード引数は BaseItemExporter__init__ メソッドに渡され、残りの引数は csv.writer() 関数に渡されるため、任意の csv.writer() 関数引数を使用してこのエクスポーターをカスタマイズできます。

このエクスポーターの典型的な出力は次のようになります:

product,price
Color TV,1200
DVD player,200
PickleItemExporter
class scrapy.exporters.PickleItemExporter(file, protocol=0, **kwargs)[ソース]

アイテムをpickle形式で与えられたファイルのようなオブジェクトにエクスポートします。

パラメータ
  • file -- データのエクスポートに使用するファイルのようなオブジェクト。 その write メソッドは bytes (バイナリ・モードで開かれたディスクファイルや、 io.BytesIO オブジェクトなど)を受け入れる必要があります

  • protocol (int) -- 使用するpickleプロトコル。

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

この __init__ メソッドの追加のキーワード引数は、 BaseItemExporter__init__ メソッドに渡されます。

pickleは人間が読める形式ではないため、出力例はありません。

PprintItemExporter
class scrapy.exporters.PprintItemExporter(file, **kwargs)[ソース]

指定のファイルオブジェクトにきれいな(pretty)印刷形式でアイテムをエクスポートします。

パラメータ

file -- データのエクスポートに使用するファイルのようなオブジェクト。 その write メソッドは bytes (バイナリ・モードで開かれたディスクファイルや、 io.BytesIO オブジェクトなど)を受け入れる必要があります

この __init__ メソッドの追加のキーワード引数は、 BaseItemExporter__init__ メソッドに渡されます。

このエクスポーターの典型的な出力は次のようになります:

{'name': 'Color TV', 'price': '1200'}
{'name': 'DVD player', 'price': '200'}

長大な行の場合は綺麗に(pretty)フォーマットされます。

JsonItemExporter
class scrapy.exporters.JsonItemExporter(file, **kwargs)[ソース]

アイテムをJSON形式で、指定のファイル様オブジェクトにエクスポートし、すべてのオブジェクトをオブジェクトのリストとして書き込みます。 追加の __init__ メソッドの引数は BaseItemExporter__init__ メソッドに渡され、残りの引数は JSONEncoder__init__ メソッドに渡されるため、あなたは任意の JSONEncoder__init__ メソッド引数を使用してこのエクスポーターをカスタマイズできます。

パラメータ

file -- データのエクスポートに使用するファイルのようなオブジェクト。 その write メソッドは bytes (バイナリ・モードで開かれたディスクファイルや、 io.BytesIO オブジェクトなど)を受け入れる必要があります

このエクスポーターの典型的な出力は次のようになります:

[{"name": "Color TV", "price": "1200"},
{"name": "DVD player", "price": "200"}]

警告

JSONは非常にシンプルで柔軟なシリアル化形式ですが、(すべての言語で)JSONパーサ間でインクリメンタル(別名ストリームモード)解析が(もしあれば)十分にサポートされていないため、大量のデータに対して適切に拡張できません。それらのほとんどは、メモリ内のオブジェクト全体を解析するだけです。よりストリーム・フレンドリーな形式でJSONのパワーとシンプルさを望む場合は、代わりに JsonLinesItemExporter を使用するか、出力を複数のチャンクに分割することを検討してください。

JsonLinesItemExporter
class scrapy.exporters.JsonLinesItemExporter(file, **kwargs)[ソース]

アイテムをJSON形式で、指定のファイル様オブジェクトにエクスポートし、1行に1つのJSONエンコードされたアイテムを書き込みます。 追加の __init__ メソッド引数は BaseItemExporter__init__ メソッドに渡され、残りの引数は JSONEncoder__init__ メソッドに渡されるため、あなたは任意の JSONEncoder__init__ メソッド引数を使用して、このエクスポーターをカスタマイズできます。

パラメータ

file -- データのエクスポートに使用するファイルのようなオブジェクト。 その write メソッドは bytes (バイナリ・モードで開かれたディスクファイルや、 io.BytesIO オブジェクトなど)を受け入れる必要があります

このエクスポーターの典型的な出力は次のようになります:

{"name": "Color TV", "price": "1200"}
{"name": "DVD player", "price": "200"}

JsonItemExporter によって生成される形式とは異なり、このエクスポーターによって生成される形式は、大量のデータをシリアル化するのに適しています。

MarshalItemExporter
class scrapy.exporters.MarshalItemExporter(file, **kwargs)[ソース]

Python固有のバイナリ形式でアイテムをエクスポートします( marshal 参照)。

パラメータ

file -- データのエクスポートに使用するファイルのようなオブジェクト。 その write メソッドは bytes (バイナリ・モードで開かれたディスク・ファイルや、 BytesIO オブジェクトなど)を受け入れる必要があります

アーキテクチャ概観

Scrapyアーキテクチャを理解する。

ダウンローダー・ミドルウェア

ページのリクエストとダウンロードの方法をカスタマイズします。

スパイダー・ミドルウェア

あなたのスパイダーの入力と出力をカスタマイズします。

拡張機能

あなたのカスタム機能でScrapyを拡張する。

コアAPI

Scrapy機能を拡張するために拡張機能やミドルウェアを使用します。

シグナル

利用可能なすべてのシグナルとそれらがどのように動くかをご覧下さい。

アイテム・エクスポーター

スクレイプしたアイテムをファイル(XML、CSVなど)にすばやくエクスポートします。

その他すべて

リリース・ノート

Scrapy 2.5.0 (2021-04-06)

ハイライト:

非推奨による削除
非推奨
  • scrapy.utils.py36 モジュールは非推奨になり、 scrapy.utils.asyncgen が優先されます。 (issue 4900)

新機能
  • 実験的 DOWNLOAD_HANDLERS 設定にて https プロトコルに割り当てることができる新しいダウンロード・ハンドラーによる実験的な HTTP/2 サポート

  • scrapy.downloadermiddlewares.retry.get_retry_request() 関数は、スパイダー・コールバックまたはミドルウェアから使用し、 RetryMiddleware がサポートするシナリオを超えたリクエストの再試行を処理できます。

  • headers_received シグナルは、レスポンス・ヘッダーへの早期アクセスを提供し、 ダウンロードの中止 を可能にします。 (issue 1772, issue 4897)

  • 新 new Response.protocol 属性は、レスポンスのダウンロードに使用されるプロトコルを識別する文字列へのアクセスを提供します。 (issue 4878)

  • 統計 には、 フィード の保存の成功と失敗の数を示す以下のエントリが含まれるようになりました:

    feedexport/success_count/<storage type>
    feedexport/failed_count/<storage type>
    

    ここで、 <storage type> は、 FileFeedStorage または FTPFeedStorage などのフィード・ストレージ・バックエンド・クラス名です。

    (issue 3947, issue 4850)

  • UrlLengthMiddleware スパイダー・ミドルウェアは、無視されたURLを DEBUG ではなく INFO ログ・レベル でログに記録するようになりました。また、無視されたURLの数を追跡するために 統計 に以下のエントリが含まれるようになりました:

    urllength/request_ignored_count
    

    (issue 5036)

  • HttpCompressionMiddleware ダウンローダー・ミドルウェアは、解凍されたレスポンスの数と結果のバイトの総数をログに記録するようになりました:

    httpcompression/response_bytes
    httpcompression/response_count
    

    (issue 4797, issue 4799)

バグ修正
  • PyPyDispatcherに加えてPyDispatcherをインストールする、PyPyのインストールを修正しました。これにより、インポートされたパッケージによってはScrapyが機能しなくなる可能性がありました。 (issue 4710, issue 4814)

  • コールバックを検査して、それが値も返すジェネレーターであるかどうかを確認するときに、コールバックに続くコードよりも低いインデントのdocstringが含まれている場合、例外が発生しなくなりました。(issue 4477, issue 4935)

  • デフォルトの HTTP/1.1 ダウンロード・ハンドラーを使用する場合、 Content-Length ヘッダーがレスポンスから省略されなくなりました( DOWNLOAD_HANDLERS 参照)。 (issue 5009, issue 5034, issue 5045, issue 5057, issue 5062)

  • handle_httpstatus_all リクエスト・メタ・キー を False に設定すると、 True に設定するのと同じ効果を持つ代わりに、まったく設定しないのと同じ効果があります。 (issue 3851, issue 4694)

文書
品質保証

Scrapy 2.4.1 (2020-11-17)

Scrapy 2.4.0 (2020-10-11)

ハイライト:

  • Python 3.5 のサポートは廃止されました。

  • メディア・パイプラインfile_path メソッドは、源の アイテム にアクセスできるようになりました。

    これにより、アイテム・データに基づいてダウンロード・ファイルのパス(path)を設定できます。

  • FEEDS 設定の新しい item_export_kwargs キーにより、 アイテム・エクスポーター・クラス に渡すキーワード・パラメータを定義できます。

  • フィード・エクスポート が出力ファイルを上書きするか追加するかを選択できるようになりました。

    たとえば、 crawl または runspider コマンドを使用する場合、出力ファイルを上書きするために -o の代わりに -O オプションを使用できます。

  • zstandard がインストールされている場合、Zstd-compressedレスポンス がサポートされるようになりました。

  • クラスのインポート・パスが必要な設定で、代わりにクラス・オブジェクトを渡すことができるようになりました。

必須要件の変更
後方互換性のない変更
  • CookiesMiddleware は再び Request.headers で定義されたクッキーを破棄します。

    現在の実装では既存のコードが壊れる可能性があると報告されたため、Scrapy 2.2.0 で行われたバグ修正を元に戻すことにしました。

    リクエストにクッキーを設定する必要がある場合は、 Request.cookies パラメータを使用してください。

    Scrapy の将来のバージョンには、元に戻されたバグ修正の新しい、より良い実装が含まれます。

    (issue 4717, issue 4823)

非推奨による削除
  • scrapy.extensions.feedexport.S3FeedStorage__init__ メソッドに渡されない場合、実行中のプロジェクト設定から access_keysecret_key の値を読み込まなくなりました。 これらのパラメータを __init__ メソッドに渡すか、あるいは S3FeedStorage.from_crawler を使用する必要があります。 (issue 4356, issue 4411, issue 4688)

  • Rule.process_request は、requestresponse の両方ではなく、単一の request パラメータを期待する呼び出し可能オブジェクトを許可しなくなりました。

非推奨
新機能
バグ修正
  • genspider コマンドは、--force オプションを使用しない限り既存のファイルを上書きしなくなりました (issue 4561, issue 4616, issue 4623)

  • 値が空のクッキーは無効なクッキーとは見なされくなりました(issue 4772)

  • runspider コマンドは、ファイル拡張子 .pyw のファイルをサポートするようになりました。 (issue 4643, issue 4646)

  • HttpProxyMiddleware ミドルウェアは、サポートされていないプロキシ値を単に無視するようになりました (issue 3331, issue 4778)

  • return 文でジェネレータのコールバックをチェックしても、ネストされた関数の return 文について警告しなくなりました (issue 4720, issue 4721)

  • システム・ファイル・モードの作成マスクは、startproject コマンドを使用して生成されたファイルのパーミッションに影響しなくなりました (issue 4722)

  • scrapy.utils.iterators.xmliter() は名前空間付きノード名をサポートするようになりました(issue 861, issue 4746)

  • Request オブジェクトは about: の URL達 を持つことができるようになりました。これはヘッドレス・ブラウザを使用しているときに機能します。

文書
品質保証

Scrapy 2.3.0 (2020-08-04)

ハイライト:

  • フィード・エクスポート は、ストレージ・バックエンドとして Google Cloud Storage をサポートするようになりました

  • 新しい FEED_EXPORT_BATCH_ITEM_COUNT 設定により、指定された数のアイテムのバッチで出力アイテムを配信できます。

    これは、特定のストレージ・バックエンド (S3FTP と 今回の GCS) を使用している場合、クロールが完了した後にのみ Scrapy がアイテムの配信を開始する 遅延ファイル配信 の回避策としても機能します。

  • itemloaders の基本実装は別のライブラリ itemloaders に移動され、Scrapy の外部からの使用と別のリリースのスケジューリングが可能になりました。

非推奨による削除
  • 以下のクラスとその親モジュールを scrapy.linkextractors から削除しました:

    • htmlparser.HtmlParserLinkExtractor

    • regex.RegexLinkExtractor

    • sgml.BaseSgmlLinkExtractor

    • sgml.SgmlLinkExtractor

    代わりに LinkExtractor を使用してください (issue 4356, issue 4679)

非推奨
  • scrapy.utils.python.retry_on_eintr 関数は非推奨になりました (issue 4683)

新機能
バグ修正
文書
品質保証
  • itemloaders の基本実装は itemloaders に移動しました。 (issue 4005, issue 4516)

  • いくつかのスケジューラーテストの沈黙エラー(silenced error)を修正 (issue 4644, issue 4645)

  • SSLテストに使用されるローカルホスト証明書を更新 (issue 4650)

  • Python2固有のクッキー処理コードを削除 (issue 4682)

  • Python 2 unicode リテラル構文の使用を停止 (issue 4704)

  • 行継続のためのバックラッシュの使用をやめました (issue 4673)

  • MyPy 例外リストから不要なエントリを削除 (issue 4690)

  • 継続的インテグレーション・システムの一部として自動テストがWindowsでパス(pass)するようになりました (issue 4458)

  • 自動テストは、継続的インテグレーション・システムでサポートされている Python バージョンの最新の PyPy バージョンに合格するようになりました (issue 4504)

Scrapy 2.2.1 (2020-07-17)

  • startproject コマンドは、実行パーミッションの削除など、宛先フォルダー内のファイルのパーミッションに意図しない変更を加えなくなりました。 (issue 4662, issue 4666)

Scrapy 2.2.0 (2020-06-24)

ハイライト:

後方互換性のない変更
  • Python 3.5.0 および 3.5.1 のサポートは廃止されました。 Scrapy は typing.Type が導入された 3.5.2 より前の Python バージョンでの実行を拒否するようになりました。 (issue 4615)

非推奨
新機能
バグ修正
  • CookiesMiddleware はもはや Request.headers で定義されたクッキーを破棄しません (issue 1992, issue 2400)

  • CookiesMiddleware は、 Request__init__ メソッドの cookies パラメータで bytes として定義されたクッキーを再エンコードしなくなりました。 (issue 2400, issue 3575)

  • FEEDS が複数の URI を定義し、 かつ FEED_STORE_EMPTYFalse であり、かつ クロールでアイテムが生成されない場合、Scrapy は最初の URI の後にフィードのエクスポートを停止しなくなりました (issue 4621, issue 4626)

  • コルーチン構文 を使用して定義された Spider コールバックは、反復可能オブジェク(iterable)を返す必要がなくなり、代わりに Request オブジェクト、または アイテム 、または None を返す場合があります (issue 4609)

  • startproject コマンドは、生成されたプロジェクト・フォルダとファイルに適切なパーミッションを付与するようになりました (issue 4604)

  • 修正: scrapy.utils.datatypes.LocalWeakReferencedCache から時々発生する KeyError 例外を修正 (issue 4597, issue 4599)

  • FEEDS が複数の URI を定義する場合、保存されているアイテム達に関するログ・メッセージ達には、常にフィードの1つだけに関する情報を含むのではなく、対応するフィード達からの情報が含まれるようになりました。 (issue 4619, issue 4629)

文書
品質保証

Scrapy 2.1.0 (2020-04-24)

ハイライト:

  • FEEDS 設定は複数のフィードにエクスポートするための設定です

  • Response.ip_address 属性

後方互換性のない変更
  • assert 文によって引き起こされる AssertionError 例外は、Scrapy の動作を予期しない方法で変更することなく最適化モード (-O を参照) での Python の実行をサポートするために、新しい例外タイプに置き換えられました。

    あなたが Scrapy から AssertionError 例外をキャッチしたい場合、対応する新しい例外をキャッチするためにあなたのコードを更新して下さい。

    (issue 4440)

非推奨による削除
  • LOG_UNSERIALIZABLE_REQUESTS 設定はサポートされなくなりました。代わりに SCHEDULER_DEBUG を使用してください (issue 4385)

  • REDIRECT_MAX_METAREFRESH_DELAY 設定はサポートされなくなりました。代わりに METAREFRESH_MAXDELAY を使用してください (issue 4385)

  • ChunkedTransferMiddleware ミドルウェアが削除されました。これには scrapy.downloadermiddlewares.chunked モジュール全体が含まれています。これに関わらずチャンク転送はいつでも使用可能です。 (issue 4431)

  • spiders プロパティは Crawler から削除されました.代わりに CrawlerRunner.spider_loader を使用するか、設定で SPIDER_LOADER_CLASS をインスタンス化してください (issue 4398)

  • MultiValueDict と``MultiValueDictKeyError`` と``SiteNode`` クラスは scrapy.utils.datatypes から削除されました (issue 4400)

非推奨
新機能
バグ修正
  • リクエストのシリアライズ は、別の名前の関数が割り当てられたスパイダー属性であるコールバックで壊れなくなりました (issue 4500)

  • allowed_domainsNone 値はもはや TypeError 例外を引き起こしません (issue 4410)

  • Zsh 補完で引数の後のオプションが許可されなくなりました (issue 4438)

  • zope.interface 5.0.0 以降のバージョンがサポートされるようになりました (issue 4447, issue 4448)

  • Spider.make_requests_from_url は Scrapy 1.4.0 で非推奨となり、使用時に警告を発するようになりました (issue 4412)

文書
品質保証

Scrapy 2.0.1 (2020-03-18)

  • Response.follow_all は入力として空のURLの反復可能なオブジェクト(iterable)をサポートするようになりました (issue 4408, issue 4420)

  • トップレベルの reactor インポートを削除して、TWISTED_REACTOR を使用して別の Twisted リアクターを設定するときに間違った Twisted リアクターがインストールされるというエラーを防止しました。 (issue 4401, issue 4406)

  • 修正されたテスト (issue 4422)

Scrapy 2.0.0 (2020-03-03)

ハイライト:

後方互換性のない変更
非推奨による削除
  • Scrapy シェルsel プロキシー・オブジェクトを提供しなくなりました。代わりに response.selector を使用してください (issue 4347)

  • LevelDBのサポートを削除(issue 4112)。

  • 次の関数が scrapy.utils.python から削除されました: isbinarytext, is_writable, setattr_default, stringify_dict (issue 4362)

非推奨
  • SCRAPY_ で始まる環境変数を使用して設定をオーバーライドすることは非推奨です (issue 4300, issue 4374, issue 4375)

  • scrapy.linkextractors.FilteringLinkExtractor は非推奨になりました。代わりに scrapy.linkextractors.LinkExtractor を使って下さい。 (issue 4045)

  • プロキシーURL の noconnect クエリ文字列引数は非推奨となり、プロキシ URL から削除する必要があります (issue 4198)

  • scrapy.utils.python.MutableChain クラスの next メソッドは非推奨になりました。代わりに、グローバルの next() 関数または、 MutableChain.__next__ を使って下さい。 (issue 4153)

新機能
バグ修正
  • crawl コマンドは、クロールの開始前に例外が発生した場合にも終了コード 1 で終了するようになりました (issue 4175, issue 4207)

  • LinkExtractor.extract_links は UTF-8 以外のレスポンスからクエリ文字列または URL を再エンコードしなくなりました (issue 998, :issue :1403, issue 1949, issue 4321)

  • 最初のスパイダーミドルウェア( SPIDER_MIDDLEWARES 参照) は、ジェネレーターであるコールバックから発生した例外も処理するようになりました。 (issue 4260, issue 4272)

  • 3 つのスラッシュ (///) で始まる URL へのリダイレクトがサポートされるようになりました (issue 4032, issue 4042)

  • Request は、コロンがあるという理由だけで文字列を url として受け入れなくなりました (issue 2552, issue 4094)

  • 正しいエンコーディングが MailSender のアタッチ名に使用されるようになりました (issue 4229, issue 4239)

  • DUPEFILTER_CLASS のデフォルトである RFPDupeFilter は Windows の各行に余分な \r 文字を書き込まなくなりました。これによりプラットフォーム上で requests.seen ファイルのサイズが不必要に大きくなっていました。 (issue 4283)

  • Zシェルの自動補完は .http ファイルではなく .html ファイルを検索し、-h コマンドラインスイッチをカバーするようになりました。 (issue 4122, issue 4291)

  • limit が定義されていない scrapy.utils.datatypes.LocalCache オブジェクトにアイテムを追加しても、もはや TypeError 例外が発生することはありません。 (issue 4123)

  • scrapy.utils.misc.create_instance()settingscrawler の両方を None に設定したときに発生する ValueError 例外のメッセージのタイプミスを修正しました ( issue 4128)

文書
品質保証
スケジューラー・キュー・クラス群の変更

以下の変更は、すべての型のカスタム・キュー・クラスに影響を与える可能性があります:

  • push メソッドは、もはや request.priority * -1 を含む 2 番目の位置パラメータを受け取りません。 その値が必要な場合は、代わりに最初の位置パラメータ request から取得するか、 scrapy.core.scheduler.ScrapyPriorityQueue サブクラスの新しい priority() メソッドを使用してください。

次の変更は、カスタム・プライオリティ・キュー・クラスに影響する可能性があります:

  • __init__ メソッドまたは from_crawler または from_settings クラスメソッド内で:

    • 以前はファクトリ関数 qfactory を含んでいたパラメータが、 downstream_queue_cls という名前のキーワード・パラメータとして渡されるようになりました。

    • 新しいキーワード・パラメータが追加されました: key これは、メモリ・キューでは常に空の文字列であり、ディスク・キューでは JOB_DIR 値を示す文字列です。

    • 以前のクロールのデータを含むディスク・キューのパラメータ、startprios または slot_startprios は、startprios という名前のキーワード・パラメータとして渡されるようになりました。

    • serialize パラメータは渡されなくなりました。 ディスク・キュー・クラスは、 scrapy.utils.reqser モジュールの request_to_dict()request_from_dict() 関数を使用して、ディスクに書き込む前にリクエストのシリアル化を処理する必要があります。

以下の変更は、カスタムの ディスクおよびメモリの キュー・クラスに影響を与える可能性があります:

  • __init__ メソッドのシグネチャは今や __init__(self, crawler, key) です。

以下の変更は、特に scrapy.core.schedulerScrapyPriorityQueueDownloaderAwarePriorityQueue クラスと、そのサブクラスに影響を与える可能性があります:

  • __init__ メソッドでは、上記の変更のほとんどが適用されます。

    __init__ は引き続きすべてのパラメータを位置パラメータとして受け取りますが、以下のようになります:

    • qfactory を置き換えた downstream_queue_cls は、別の方法でインスタンス化する必要があります。

      qfactory は優先値 (整数) でインスタンス化されました。

      downstream_queue_cls のインスタンスは、新しい ScrapyPriorityQueue.qfactory または DownloaderAwarePriorityQueue.pqfactory メソッドを使用して作成する必要があります。

    • 新しい key パラメータは、startprios パラメータ 1 の位置を右に移動しました。

  • 以下のクラス属性が追加されました:

    • crawler

    • downstream_queue_cls (詳細上記)

    • key (詳細上記)

  • serialize 属性は削除されました (詳細上記)

以下の変更は特に ScrapyPriorityQueue クラスとそのサブクラスに影響を与える可能性があります:

  • 新しい priority() メソッドが追加されました。このメソッドはリクエストを与えると request.priority * -1 を返します。

    これは push() で使用され、その priority パラメータの削除を補います。

  • spider 属性は削除されました。 代わりに crawler.spider を使用してください。

以下の変更は特に DownloaderAwarePriorityQueue クラスとそのサブクラスに影響を与える可能性があります:

  • 新しい pqueues 属性は、ダウンローダー・スロット名を downstream_queue_cls の対応するインスタンスにマッピングします。

(issue 3884)

Scrapy 1.8.0 (2019-10-28)

ハイライト:

後方互換性のない変更

下記の 非推奨による削除 も参照してください。

新機能
バグ修正
文書
非推奨による削除
  • scrapy.xlib は削除されました (issue 4015)

非推奨
  • HttpCacheMiddlewareLevelDB ストレージ・バックエンド (scrapy.extensions.httpcache.LeveldbCacheStorage) は非推奨です (issue 4085, issue 4092)

  • 文書化されていない SCRAPY_PICKLED_SETTINGS_TO_OVERRIDE 環境変数の使用は非推奨です (issue 3910)

  • scrapy.item.DictItem は非推奨です。代わりに Item を使って下さい (issue 3999)

その他の変更

Scrapy 1.7.4 (2019-10-21)

いくつかの望ましくない副作用がある issue 3804 の修正( issue 3819 )を元に戻します。 (issue 3897, issue 3976)

その結果、アイテム・ローダーがアイテムで初期化されると、 ItemLoader.load_item() は、後で ItemLoader.get_output_value() を呼び出すか、または ItemLoader.load_item() が空のデータを返します。

Scrapy 1.7.3 (2019-08-01)

Python 3.4では lxml 4.3.5以下を強制する(issue 3912, issue 3918)

Scrapy 1.7.2 (2019-07-23)

Python 2 サポートを修正(issue 3889, issue 3893, issue 3896).

Scrapy 1.7.1 (2019-07-18)

Scrapy 1.7.0の再パッケージ化。PyPIの一部の変更が欠落していました。

Scrapy 1.7.0 (2019-07-18)

注釈

Scrapy 1.7.1を必ずインストールしてください。 PyPIのScrapy 1.7.0パッケージは誤ったコミットタグ付けの結果であり、以下で説明するすべての変更が含まれていません。

ハイライト:

  • 複数のドメインをターゲットとするクロールの改善

  • 引数をコールバックに渡すよりクリーンな方法

  • JSONリクエストの新しいクラス

  • ルールベースのスパイダーの改善

  • フィード・エクスポートの新機能

後方互換性のない変更
  • 429 はデフォルトで RETRY_HTTP_CODES 設定の一部になりました

    この変更は 後方互換性がありません429 を再試行したくない場合は、それに応じて RETRY_HTTP_CODES をオーバーライドする必要があります。

  • CrawlerCrawlerRunner.crawlCrawlerRunner.create_crawler は、もはや Spider のサブクラスのインスタンスを受け入れなくなり、Spider サブクラスのみを受け入れます。

    〜scrapy.spiders.Spider サブクラスのインスタンスは実行することを意図していなかったため、期待どおりに機能していませんでした。渡された 〜scrapy.spiders.Spider サブクラスのインスタンスを使用する代わりに、〜scrapy.spiders.Spider.from_crawler メソッドは、新しいインスタンスを生成するために呼び出されました。

  • SCHEDULER_PRIORITY_QUEUE 設定のデフォルト以外の値が機能しなくなる場合があります。 スケジューラープライオリティキュークラスは、任意のPythonデータ構造ではなく 〜scrapy.http.Request オブジェクトを処理する必要があります。

  • Scheduler クラスの __init__ メソッドに追加の crawler パラメーターが追加されました。 その `` __init__``メソッドで任意のパラメーターを受け入れてないカスタム・スケジューラ・サブクラスは、この変更により破損する可能性があります。

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

下記の 非推奨による削除 も参照してください。

新機能
バグ修正
文書
非推奨による削除

次の非推奨APIは削除されました(issue 3578):

  • scrapy.conf (Crawler.settings を使用して下さい)

  • scrapy.core.downloader.handlers について:

    • http.HttpDownloadHandler (http10.HTTP10DownloadHandler を使用して下さい)

  • scrapy.loader.ItemLoader._get_values (_get_xpathvalues を使用して下さい)

  • scrapy.loader.XPathItemLoader (ItemLoader を使用して下さい)

  • scrapy.log (ロギング(logging) 参照)

  • scrapy.pipelines について:

    • files.FilesPipeline.file_key (file_path を使用して下さい)

    • images.ImagesPipeline.file_key (file_path を使用して下さい)

    • images.ImagesPipeline.image_key (file_path を使用して下さい)

    • images.ImagesPipeline.thumb_key (thumb_path を使用して下さい)

  • scrapy.selectorscrapy.selector.lxmlsel の両方より:

    • HtmlXPathSelector (Selector を使用して下さい)

    • XmlXPathSelector (Selector を使用して下さい)

    • XPathSelector (Selector を使用して下さい)

    • XPathSelectorList (Selector を使用して下さい)

  • scrapy.selector.csstranslator より:

  • Selector より:

    • `` _root`` ( __init__ メソッド引数とオブジェクト・プロパティの両方で、 root を使用します)

    • extract_unquoted (getall を使用して下さい)

    • select (xpath を使用して下さい)

  • SelectorList より:

    • extract_unquoted (getall を使用して下さい)

    • select (xpath を使用して下さい)

    • x (xpath を使用して下さい)

  • scrapy.spiders.BaseSpider (Spider を使用して下さい)

  • Spider (と、そのサブクラス)より:

  • scrapy.spiders.spiders (SpiderLoader を使用して下さい)

  • scrapy.telnet (scrapy.extensions.telnet を使用して下さい)

  • scrapy.utils.python より:

    • str_to_unicode (to_unicode を使用して下さい)

    • unicode_to_str (to_bytes を使用して下さい)

  • scrapy.utils.response.body_or_str

また、以下の非推奨の設定も削除されました(issue 3578):

非推奨
  • SCHEDULER_PRIORITY_QUEUE 設定の queuelib.PriorityQueue 値は非推奨です。代わりに scrapy.pqueues.ScrapyPriorityQueue を使って下さい。

  • 2つの引数を受け入れない Rule に渡される process_request コールバックは非推奨です。

  • 以下のモジュールは非推奨です:

    • scrapy.utils.http (w3lib.http を使用して下さい)

    • scrapy.utils.markup (w3lib.html を使用して下さい)

    • scrapy.utils.multipart (urllib3 を使用して下さい)

  • scrapy.utils.datatypes.MergeDict クラスは、Python3コードベースでは非推奨です。 代わりに ChainMap を使用してください。 (issue 3878)

  • scrapy.utils.gz.is_gzipped 関数は非推奨です。代わりに scrapy.utils.gz.gzip_magic_number を使って下さい。

その他の変更

Scrapy 1.6.0 (2019-01-30)

ハイライト:

  • より良いWindowsサポート;

  • Python3.7との互換性;

  • .extract_first() + .extract() APIから .get() + .getall() APIへの切り替えを含む、文書の大幅な改善。

  • フィードのエクスポート、FilePipelineおよびMediaPipelineの改善;

  • より優れた拡張性 item_errorrequest_reached_downloader 、それは フィード・エクスポーターとフィード・ストレージと重複フィルターでの from_crawler サポート。

  • scrapy.contracts の修正と新機能;

  • telnetコンソールのセキュリティの改善。最初に Scrapy 1.5.2 (2019-01-22) へのバックポートとしてリリースされました;

  • 非推奨のコードの整理;

  • コードベース全体でのさまざまなバグ修正、小さな新機能、および使いやすさの向上。

セレクターAPI変更

これらはScrapy自体の変更ではなく、Scrapyがxpath/cssセレクターに使用する parsel ライブラリの変更ですが、これらの変更はここで言及する価値があります。Scrapyは現在 parsel>=1.5 に依存しており、Scrapyのドキュメントは最近の parsel API規則に従うように更新されています。

最も目に見える変更は、 .get().getall() セレクター・メソッドが .extract_first().extract() よりも優先されるようになったことです。 これらの新しいメソッドにより、コードがより簡潔で読みやすくなると考えています。 詳細については、 extract() と extract_first() を参照してください。

注釈

現時点では .extract().extract_first() メソッドを非推奨にする 計画 はありません。

もう1つの便利な新機能は、 Selector.attrib プロパティと SelectorList.attrib プロパティの導入です。これにより、HTML要素の属性を簡単に取得できます。 要素属性の選択 を参照してください。

parsel >= 1.5 ではCSSセレクターはキャッシュされるため、同じCSSパスが何度も使用されると高速になります。これは、Scrapyスパイダーではとてもよくあるケースです。コールバックは通常、異なるページで複数回呼び出されます。

カスタム Selector または SelectorList サブクラスを使用している場合、parselの 後方互換性のない 変更がコードに影響する可能性があります。 詳細な説明と改善点の完全なリストについては、 parsel changelog を参照してください。

Telnetコンソール

下位互換性なし : Scrapyのtelnetコンソールには、ユーザー名とパスワードが必要になりました。詳細については、 Telnetコンソール を参照してください。この変更により、 セキュリティの問題 が修正されます。詳細については、 Scrapy 1.5.2 (2019-01-22) リリースノートを参照してください。

新しい拡張機能
  • from_crawler サポートがフィード・エクスポーターとフィード・ストレージに追加されました。 これにより、特に、カスタム・フィードのストレージおよびエクスポーターからScrapy設定にアクセスできます (issue 1605, issue 3348).

  • from_crawler サポートがdupefiltersに追加されました (issue 2956) 。これにより、例えば、dupefilterから設定またはスパイダーにアクセスできます。

  • item_error パイプラインでエラーが発生したときに発生します (issue 3256) ;

  • request_reached_downloader ダウンローダーが新しいリクエストを取得したときに発生します。この信号は、例えばカスタム・スケジューラに便利です。 (issue 3393).

  • 新しい SitemapSpider である sitemap_filter() メソッド。これにより、SitemapSpiderサブクラスの属性に基づいてサイト・マップ・エントリを選択できます (issue 3512).

  • ダウンローダー・ハンドラーの遅延読み込みはオプションになりました。これにより、カスタムダウンローダー・ハンドラーでの初期化エラー処理が向上します。 (issue 3394)

新しい FilePipeline ・ MediaPipeline 機能
scrapy.contracts の改善
  • 規約コードの例外はより適切に処理されます (issue 3377);

  • dont_filter = True は規約リクエストに使用され、同じURLで異なるコールバックをテストできます (issue 3381);

  • Contract サブクラスの request_cls 属性を使用すると、FormRequestなどの規約でさまざまなリクエスト・クラスを使用できます (issue 3383).

  • 規約でのエラーバック(errback)処理を修正しました。例えば200以外のレスポンスを返すURLに対してコントラクトが実行される場合です (issue 3371)

使いやすさの改善
  • RobotsTxtMiddlewareの統計を追加 (issue 3100)

  • telnetホスト/ポートを表示するためにINFOログレベルを使用します (issue 3115)

  • RobotsTxtMiddlewareのIgnoreRequestにメッセージを追加 (issue 3113)

  • Response.followurl 引数のより良い検証 (issue 3131)

  • スパイダーの初期化でエラーが発生すると、Scrapyコマンドからゼロ以外の終了コードが返されます (issue 3226)

  • リンク抽出の改善: "ftp" がスキームリストに追加されました (issue 3152) 。また、 "flv" が一般的なビデオ拡張機能に追加されました (issue 3165)

  • エクスポータが無効になっている場合のエラーメッセージが改善されました (issue 3358);

  • scrapy shell --help は、ローカルファイル( ./file.html )に必要な構文について言及しています ( issue 3496)

  • リファラー・ヘッダー値がRFPDupeFilterログ・メッセージに追加されます (issue 3588)

バグ修正
  • Windowsでの.csvエクスポートの余分な空白行の問題を修正しました (issue 3039);

  • ディスク・キューのオブジェクトをシリアル化するときのPython3でのpickle化エラーの適切な処理 (issue 3082)

  • リクエストをコピーするときにフラグが保持されるようになりました (issue 3342);

  • FormRequest.from_response clickdata は、 input[type=image] の要素を無視してはなりません (issue 3153).

  • FormRequest.from_responseは、重複するキーを保持する必要があります (issue 3247)

文書の改善
非推奨による削除

1.0より前のScrapyモジュール名のための互換性シム(shim)が削除されました (issue 3318):

  • scrapy.command

  • scrapy.contrib (と、全てのサブモジュール)

  • scrapy.contrib_exp (と、全てのサブモジュール)

  • scrapy.dupefilter

  • scrapy.linkextractor

  • scrapy.project

  • scrapy.spider

  • scrapy.spidermanager

  • scrapy.squeue

  • scrapy.stats

  • scrapy.statscol

  • scrapy.utils.decorator

詳細については、 モジュールの再配置 を参照するか、Scrapy1.5.xの非推奨警告による提案を利用してあなたのコードを更新してください。

他の非推奨削除:

  • 非推奨の scrapy.interfaces.ISpiderManager は削除されました。scrapy.interfaces.ISpiderLoader を使って下さい。

  • 非推奨の CrawlerSettings クラスは削除されました (issue 3327).

  • 非推奨の Settings.overridesSettings.defaults 属性は削除されました(issue 3327, issue 3359).

その他の改善、クリーンアップ

Scrapy 1.5.2 (2019-01-22)

  • セキュリティのバグ修正 : Telnetコンソール拡張機能は、コンテンツを http://localhost:6023 にPOSTする不正なWebサイトによって簡単に悪用される可能性があり、Scrapyからそれを悪用する方法は見つかりませんでしたが、ブラウザをだまして悪用するのは非常に簡単であり、ローカル開発環境のリスクを高めます。

    修正には下位互換性がありません ランダムに生成されたパスワードを使用して、デフォルトでtelnetユーザーパスワード認証を有効にします。すぐにアップグレードできない場合は、 TELNETCONSOLE_PORT のデフォルト値の変更を検討してください。

    詳細は telnetコンソール 文書参照

  • botoインポート・エラーが原因で、GCE環境でのバック・ポートCIビルドの失敗。

Scrapy 1.5.1 (2018-07-12)

重要なバグ修正のためのメンテナンス・リリースです。新機能の追加はありません。

Scrapy 1.5.0 (2017-12-29)

このリリースでは、コードベース全体に小さな新機能と改善が加えられています。 いくつかのハイライト:

  • Google Cloud Storageは、FilesPipelineとImagesPipelineでサポートされています。

  • プロキシーへの接続を再利用できるようになったため、プロキシー・サーバーを使用したクロールがより効率的になりました。

  • 警告と例外とログのメッセージが改善され、デバッグが容易になりました。

  • scrapy parse コマンドで、 --meta 引数を介してカスタム・リクエスト・メタを設定できるようになりました。

  • Python 3.6、PyPy、PyPy3との互換性が向上しました。 PyPyとPyPy3は、CIでテストを実行することにより、正式にサポートされるようになりました。

  • HTTP 308と522と524のステータスコードのデフォルト処理が改善されました。

  • 毎度おなじみ文書の改善。

後方互換性の無い変更
  • Scrapy 1.5は、Python3.3のサポートを終了します。

  • デフォルトのScrapy User-Agentは、scrapy.orgへのhttpsリンクを使用するようになりました(issue 2983)。 これは技術的に後方互換性がありません 古い値に依存している場合は、 USER_AGENT をオーバーライドします。

  • custom_settings によってオーバーライドされた設定のログが修正されました。 これは技術的に後方互換性がありません ロガーが [scrapy.utils.log] から [scrapy.crawler] に変更されたためです。 Scrapyログをパースしている場合は、ログパーサーを更新してください (issue 1343).

  • LinkExtractorは、デフォルトで m4v 拡張子を無視するようになりました。これは動作の変更です。

  • 522 と 524 のステータスコードが RETRY_HTTP_CODES に追加されました (issue 2851)

新機能
  • Response.follow 内で <link> タグをサポートしました (issue 2785)

  • ptpython REPL をサポートしました (issue 2654)

  • FilesPipelineとImagesPipelineに対するGoogleCloud Storageのサポート (issue 2923)

  • "scrapy parse" コマンドの新しい --meta オプションにより、追加のrequest.metaを渡すことができます (issue 2883)

  • shell.inspect_response を使用するときは、スパイダー変数に設定します (issue 2812)

  • HTTP 308 恒久的リダイレクト(Permanent Redirect) の処理 (issue 2844)

  • RETRY_HTTP_CODES に 522 と 524 を追加 (issue 2851)

  • 起動時のログバージョン情報 (issue 2857)

  • scrapy.mail.MailSender は今や Python 3 で動作します (Twisted 17.9.0 が必要です)

  • プロキシー・サーバーへの接続(connection)は再利用されます (issue 2743)

  • ダウンローダー・ミドルウェアのためのテンプレートを追加 (issue 2755)

  • パース・コールバックが定義されていない場合のNotImplementedErrorの明示的なメッセージ (issue 2831)

  • CrawlerProcessは、ルート・ログ・ハンドラーのインストールを無効にするオプションが追加されました (issue 2921)

  • LinkExtractorは今やデフォルトで m4v 拡張子を無視します

  • DOWNLOAD_WARNSIZEDOWNLOAD_MAXSIZE の制限を超えるレスポンスのログ・メッセージが改善されました (issue 2927)

  • URLがドメインではなく Spider.allowed_domains に配置されたときに警告を表示します (issue 2250).

バグ修正
  • custom_settings によって上書きされた設定のログを修正しました。 これは技術的に後方互換性がありません ロガーが [scrapy.utils.log] から [scrapy.crawler] に変わるため、必要に応じてログ・パーサーを更新してください (issue 1343)

  • デフォルトのScrapy User-Agentは、scrapy.orgへのhttpsリンクを使用するようになりました(issue 2983)。 これは技術的に後方互換性がありません 古い値に依存している場合は、 USER_AGENT をオーバーライドします。

  • PyPyとPyPy3のテストの失敗を修正し、それらを公式にサポートします (issue 2793, issue 2935, issue 2990, issue 3050, issue 2213, issue 3048)

  • DNSCACHE_ENABLED=False の時のDNSリゾルバーを修正 (issue 2811)

  • Debian Jessie tox test envの cryptography を追加します (issue 2848)

  • リクエスト・コールバックが呼び出し可能かどうかを確認するための検証を追加します (issue 2766)

  • extras/qpsclient.py を Python 3 に移植しました (issue 2849)

  • Python3の環境下でgetfullargspecを使用した時の非推奨警告をやめました (issue 2862)

  • 非推奨のテスト・エイリアスを更新 (issue 2876)

  • 代替リンク(alternate link)の SitemapSpider サポートを修正 (issue 2853)

文書
  • AUTOTHROTTLE_TARGET_CONCURRENCY 設定に欠落していた箇条書きを追加。 (issue 2756)

  • 寄稿文書を更新し、新しいサポート・チャネルを文書化します (issue 2762, issue:3038)

  • 文書にScrapy subredditへの参照を含めます

  • 誤ったリンクを修正。 外部へのリンクには https:// を使用 (issue 2978, issue 2982, issue 2958)

  • CloseSpider拡張機能をより適切に文書化 (issue 2759)

  • MongoDBの例で pymongo.collection.Collection.insert_one() を使用 (issue 2781)

  • スペルミスとタイプミス (issue 2828, issue 2837, issue 2884, issue 2924)

  • CSVFeedSpider.headers 文書を明確にしました (issue 2826)

  • DontCloseSpider 例外を文書化し、 spider_idle を明確にします (issue 2791)

  • README の "Releases" 節を更新 (issue 2764)

  • DOWNLOAD_FAIL_ON_DATALOSS 文書内の rst 文法 を修正 (issue 2763)

  • startproject引数の説明の些細な修正 (issue 2866)

  • Response.body文書でデータ型を明確にする (issue 2922)

  • request.meta['depth'] に関する注記をDepthMiddleware文書に追加 (issue 2374)

  • request.meta['dont_merge_cookies'] に関する注記をCookiesMiddleware文書に追加 (issue 2999)

  • プロジェクト構造の例を更新 (issue 2964, issue 2976)

  • ItemExportersの使用例を改善 (issue 2989)

  • スパイダーとダウンローダーミドルウェアのための from_crawler メソッドについて文書化 (issue 3019)

Scrapy 1.4.0 (2017-05-18)

Scrapy 1.4は、それほど多くの息をのむような新機能をもたらしませんが、それでもかなりの数の便利な改善をもたらします。

Scrapyは、新しい設定 FTP_USERFTP_PASSWORD を介して、カスタマイズ可能なユーザーとパスワードを使用した匿名FTPセッションをサポートするようになりました。 また、Twistedバージョン17.1.0以降を使用している場合、Python3でFTPを使用できるようになりました。

リクエストを作成するための新メソッド response.follow があります。 これは、Scrapyスパイダーでリクエストを作成するための推奨される方法になりました。 この方法により、正しいスパイダーを簡単に作成できます。 response.follow には、 scrapy.Request オブジェクトを直接作成するよりもいくつかの利点があります。

  • 相対URLを処理します;

  • 非UTF8ページの非ASCII URLで適切に機能します;

  • 絶対URLと相対URLに加えて、セレクターをサポートします。 <a> 要素の場合、href値を抽出することもできます。

たとえば、以下の代わりに:

for href in response.css('li.page a::attr(href)').extract():
    url = response.urljoin(href)
    yield scrapy.Request(url, self.parse, encoding=response.encoding)

以下のように書くことができます:

for a in response.css('li.page a'):
    yield response.follow(a, self.parse)

リンクエ抽出器も改善されています。 これらは、汎用の最新のブラウザと同じように機能します。 Link オブジェクトを作成するときに、先頭と末尾の空白が属性から削除されます(例えば href="   http://example.com" と考えて下さい)。この空白の削除は、 FormRequest を含む action 属性でも発生します。

リンク抽出器はデフォルトでURLを正規化しないことにも注意してください。 これは時々ユーザーを困惑させていました、そしてそれは実際にはブラウザがすることではないので、抽出されたリンクの余分な変換を削除しました。

Scrapyがリンクをたどるときに送信する Referer: ヘッダーをより細かく制御したい場合は、独自の Referrer Policy を設定できます。 Scrapy 1.4より前は、デフォルトの RefererMiddleware HTTPリクエストを生成したレスポンスのURLに単純かつ盲目的に設定していました(URLシードの情報が漏洩する可能性がありました)。 デフォルトでは、Scrapyは通常のブラウザと同じように動作するようになりました。 また、このポリシーは、W3C標準値(または必要に応じて独自のカスタム値)を使用して完全にカスタマイズできます。 詳細については、 REFERRER_POLICY を参照してください。

Scrapyスパイダーのデバッグを容易にするために、Scrapyはデフォルトで1.4でより多くの統計をログに記録します。それらは、メモリ使用統計、詳細な再試行統計、詳細なHTTPエラー・コード統計 です。 同様の変更として、HTTPキャッシュパスがログにも表示されるようになりました。

最後になりますが、Scrapyには、新しい FEED_EXPORT_INDENT 設定を使用して、JSONおよびXMLアイテムをより人間が読みやすいようにするオプションがあり、アイテム間の改行やカスタム・インデント・オフセットもあります。

Enjoy! (または、このリリースの残りの変更について読んでください。)

非推奨と下位互換性のない変更
  • デフォルトは scrapy.linkextractors.LinkExtractorcanonicalize=False です (issue 2537, fixes issue 1941 and issue 1982) 警告:これは技術的に後方互換性がありません

  • デフォルトでメモリ拡張を有効にします (issue 2539, fixes issue 2187) 。 これは技術的に後方互換性がありません。 ですので、デフォルト以外の MEMUSAGE_*** オプションが設定されているかどうかを確認してください。

  • EDITOR 環境変数は、settings.py で定義された EDITOR オプションよりも優先されるようになりました (issue 1829) 。 Scrapyのデフォルト設定は、環境変数に依存しなくなりました。 これは技術的には後方互換性のない変更です。

  • Spider.make_requests_from_url は非推奨です (issue 1728, fixes issue 1495)

新機能
バグ修正
  • LinkExtractorは、属性から先頭と末尾の空白を削除するようになりました (issue 2547, 修正 issue 1614)

  • FormRequest のaction属性で空白を適切に処理する (issue 2548)

  • すべてのHTTPヘッダーが受信されるまでプロキシからのCONNECTレスポンス・バイトをバッファリングします (issue 2495, 修正 issue 2491)

  • Twisted>=17.1 を使用している場合、FTPダウンローダーがPython3で動作するようになりました (issue 2599)

  • コンテンツを解凍した後、ボディを使用してレスポンス・タイプを選択します (issue 2393, 修正 issue 2145)

  • 常に Content-Encoding: gzipHttpCompressionMiddleware ステージで解凍します (issue 2391)

  • Spider.custom_settings のカスタムログレベルを尊重します (issue 2581, fixes issue 1612)

  • macOS の 'make htmlview' 修正 (issue 2661)

  • 削除:コマンドリストから "commands" を削除 (issue 2695)

  • 本文が空のPOSTリクエストの重複するContent-Lengthヘッダーを修正しました (issue 2677)

  • 大量のダウンロードを適切にキャンセルします。例えば上記の DOWNLOAD_MAXSIZE (issue 1616)

  • ImagesPipeline: パレットを使用した透明なPNG画像の処理を修正しました (issue 2675)

整理とリファクタリング
  • テスト: 一時ファイルとフォルダーの削除 (issue 2570) 、macOSでのProjectUtilsTestの修正 (issue 2569) 、Travis CIでのLinux用のポータブルpypyの使用 (issue 2710)

  • CrawlSpiderの _requests_to_follow からリクエスト構築を分離します (issue 2562)

  • 削除: “Python 3 progress” バッジを削除 (issue 2567)

  • .gitignore にさらに数行追加します (issue 2557)

  • バンプバージョン(bumpversion)のプレリリース構成を削除します (issue 2159)

  • 追加: codecov.yml ファイル追加 (issue 2750)

  • Twistedのバージョンに基づいてコンテキスト・ファクトリの実装を設定します (issue 2577, 修正 issue 2560)

  • デフォルトのプロジェクト・ミドルウェア・テンプレートに省略された self 引数を追加 (issue 2595)

  • ExecutionEngineで冗長な slot.add_request() 呼び出しを削除 (issue 2617)

  • scrapy.pipelines.files.FSFilesStore でより具体的な os.error 例外をキャッチします (issue 2644)

  • "localhost" テスト・サーバー証明書を変更 (issue 2720)

  • 削除: 未使用の MEMUSAGE_REPORT 設定を削除 (issue 2576)

文書

Scrapy 1.3.3 (2017-03-10)

バグ修正
  • 依存関係が欠落していて、 SPIDER_MODULES が間違っているため、デフォルトで SpiderLoaderImportError を再度発生させます。これらの例外は、1.3.0以降警告として沈黙させていました。必要に応じて警告と例外を切り替えるための新しい設定が導入されました。 詳細については、 SPIDER_LOADER_WARN_ONLY を参照してください。

Scrapy 1.3.2 (2017-02-13)

バグ修正
  • 辞書との間で変換するときにリクエスト・クラスを保持(utils.reqser) (issue 2510)

  • チュートリアルの作成者フィールドに一貫したセレクターを使用します (issue 2551)

  • Twisted 17+のTLS互換性を修正 (issue 2558)

Scrapy 1.3.1 (2017-02-08)

新機能
  • ブーリアン設定で 'True'' False' 文字列値をサポートします (issue 2519) 。 あなたは scrapy crawl myspider -s REDIRECT_ENABLED=False のようなことができるようになりました。

  • response.xpath() でkwargsをサポートして、 XPath変数 とアドホックな名前空間宣言を使用します。これには、少なくとも Parsel v1.1 が必要です。 (issue 2457)

  • Python 3.6のサポートを追加 (issue 2485)

  • PyPyでテストが走ります(警告:一部のテストはまだ失敗するため、PyPyはまだサポートされていません)。

バグ修正
  • DNS_TIMEOUT 設定を適用 (issue 2496)

  • 修正: view コマンド。 v1.3.0 でデグレてた。 (issue 2503)

  • ファイル/画像 パイプラインでの *_EXPIRES settings に関するテストを修正 (issue 2460)

  • 基本的なプロジェクト・テンプレートを使用するときに生成されるパイプライン・クラスの名前を修正 (issue 2466)

  • Twisted 17+ との互換性を修正 (issue 2496, issue 2528)

  • Python 3.6での scrapy.Item の継承を修正 (issue 2511)

  • SPIDER_MIDDLEWARESDOWNLOADER_MIDDLEWARESEXTENSIONSSPIDER_CONTRACTS のコンポーネントの順序の為に数値を適用します (issue 2420)

文書
  • コーディング規範(Code of Conduct)節を書き直し、 Contributor Covenant v1.4 にアップグレードします。 (issue 2469)

  • スパイダー引数を渡すと、それらがスパイダー属性に変換されることを明確にします (issue 2483)

  • FormRequest.from_response()formid 引数について文書化 (issue 2497)

  • READMEファイル達に .rst 拡張子を追加 (issue 2507)

  • LevelDBキャッシュ・ストレージ・バックエンドに言及します (issue 2525)

  • コールバック・コード例で yield を使用 (issue 2533)

  • .re()/.re_first() デコードするHTML要素に関する注記を追加 (issue 1704)

  • タイプミス (issue 2512, issue 2534, issue 2531)

整理
  • MetaRefreshMiddleware の冗長なチェックを削除 (issue 2542)

  • LinkExtractor で allow/deny パターンをより速くチェックします (issue 2538)

  • 古いTwistedバージョンをサポートするデッド・コードを削除 (issue 2544)

Scrapy 1.3.0 (2016-12-21)

このリリースは、1.2.2のある主要な理由により、1.2.2の直後の版となります。0.18から1.2.2(含まれる)以降のリリースでは、Twisted(scrapy.xlib.tx.*)からのバックポートされたコードを使用することがわかりました。 より新しいTwistedモジュールが利用できる場合でも。 Scrapyは twisted.web.clienttwisted.internet.endpoints を直接使用するようになりました。(以下のクリーンアップも参照してください。)

これは大きな変更であるため、1.2シリーズを使用しているプロジェクトを壊すことなく、バグをすばやく修正したかったのです。

新機能
  • MailSenderto 引数と cc 引数の値として単一の文字列を受け入れるようになりました(issue 2272)

  • Scrapyシェル内の scrapy fetch urlscrapy shell urlfetch(url) はデフォルトでHTTPリダイレクトに従います。(issue 2290) 詳細については、fetchshell を参照してください。

  • HttpErrorMiddlewareDEBUG ではなく INFO レベルでエラーを記録するようになりました。 これは技術的には 後方互換性がない ので、ログパーサーを確認してください。

  • デフォルトでは、ロガー名は以前のリリースの短い「トップレベル」バリアント(例 [scrapy])ではなく、長い形式のパス [scrapy.extensions.logstats] を使用するようになりました。短いロガー名の部分を期待するログパーサーがある場合、 後方互換性がありませんLOG_SHORT_NAMESTrue に設定して、短いロガー名に戻すことができます。

依存関係整理とコード整理
  • Scrapyには Twisted >= 13.1 が必要になりました。これは、すでに多くのLinuxディストリビューションに当てはまります。

  • その結果、 scrapy.xlib.tx.* モジュール群を削除しました。これは、 "古い" Twistedのバージョンでスタックしているユーザー向けにTwistedコードの一部をコピーしていました。

  • ChunkedTransferMiddleware は非推奨になり、デフォルトのダウンローダー・ミドルウェアから削除されました。

Scrapy 1.2.3 (2017-03-03)

  • パッケージの修正:setup.pyでサポートされていないTwistedバージョンを禁止します。

Scrapy 1.2.2 (2016-12-06)

バグ修正
  • パイプラインが open_spider() で失敗したときの不可解なトレースバックを修正しました (issue 2011)

  • 埋め込まれたIPythonシェル変数を修正 (1.2.0で再表示された issue 396 の修正は issue 2418 )

  • robots.txtを扱う際のいくつかのパッチ:

    • (非標準の)相対サイトマップURLを処理 (issue 2390)

    • Python 2で非ASCIIのURLとUser-Agentを処理 (issue 2373)

文書
その他の変更
  • conda-forge をScrapyの公式condaチャンネルとして宣伝する (issue 2387)

  • テキスト以外のレスポンスで .css() または .xpath() を使用しようとした場合の、より役立つエラーメッセージ (issue 2264)

  • startproject コマンドは、サンプルの middlewares.py ファイルを生成するようになりました (issue 2335)

  • scrapy version の詳細出力に依存関係のバージョン情報を追加します (issue 2404)

  • ソース配布からすべての *.pyc ファイルを削除 (issue 2386)

Scrapy 1.2.1 (2016-10-21)

バグ修正
  • TLS/SSL接続を確立するときにOpenSSLのより寛容な(permissive)デフォルト暗号を含めます (issue 2314)

  • 非ASCIIURLリダイレクトでの "Location" HTTPヘッダー・デコードを修正 (issue 2321)

文書
  • JsonWriterPipeline例を修正 (issue 2302)

  • さまざまな注意事項: issue 2330 はスパイダー名、 issue 2329 はミドルウェア・メソッドの処理順序、 issue 2327 は複数値(multi-valued)のHTTPヘッダーをリストとして取得します。

その他の変更
  • 組み込みのスパイダー・テンプレートの start_urls から www. を削除 (issue 2299)

Scrapy 1.2.0 (2016-10-03)

新機能
  • 新しい FEED_EXPORT_ENCODING 設定は、アイテムをファイルに書き込むときに使用されるエンコーディングをカスタマイズします。 これは、JSON出力で \uXXXX エスケープをオフにするために使用できます。 これは、XMLまたはCSV出力にUTF-8以外のものが必要な場合にも便利です。(issue 2034)

  • startproject コマンドは、プロジェクト名に基づいてデフォルトのディレクトリを上書きするオプションの宛先ディレクトリをサポートするようになりました。(issue 2005)

  • 新しい SCHEDULER_DEBUG 設定は、リクエストのシリアル化エラーをログに記録します(issue 1610)

  • JSONエンコーダーが set インスタンスのシリアル化をサポートするようになりました(issue 2058)

  • application/json-amazonui-streamingTextResponse として解釈する(issue 1503).

  • シェルツール( shellinspect_response) を使用すると、デフォルトで scrapy がインポートされます (issue 2248)

バグ修正
  • DefaultRequestHeaders ミドルウェアは、UserAgentミドルウェアの前に実行されるようになりました( issue 2088 )。 警告:これは技術的に後方互換性がありません。 ただし、これはバグ修正と見なされます。

  • .scrapy データ・ディレクトリを使用するHTTPキャッシュ拡張機能とプラグインは、プロジェクトの外部で機能するようになりました (issue 1581) 。 警告:これは技術的に後方互換性がありません。 ただし、これはバグ修正と見なされます。

  • Selector は、 responsetext の両方を渡すことを許可しなくなりました (issue 2153)

  • scrapy parse で間違ったコールバック名のロギングを修正 (issue 2169)

  • 奇妙なgzip解凍バグの修正 (issue 1606)

  • CrawlSpiderscrapy parse とともに使用する場合の選択されるコールバックの修正 (issue 2225)

  • スパイダーがアイテムを生成しない場合の無効なJSONおよびXMLファイルの修正 (issue 872)

  • ログの警告を回避するために flush() fpr StreamLogger を実装 (issue 2125)

リファクタリング
テストと動作要件

Scrapyの新しい動作要件基準はDebian 8 "Jessie" です。 以前はUbuntu 12.04 Precise でした。 つまりこれは、 Twisted 14.0, pyOpenSSL 0.14, lxml 3.4 (メイン)パッケージで、かつ最低でも表記のバージョン以上で継続的インテグレーション・テストを実行するということです。

Scrapyは、これらのパッケージの古いバージョンで非常にうまく機能する可能性があります(たとえば、コードベースにはまだ古いTwistedバージョンのスイッチがあります)が、保証されていません(テストされていないため)。

文書

Scrapy 1.1.4 (2017-03-03)

  • パッケージの修正:setup.pyでサポートされていないTwistedバージョンを禁止します。

Scrapy 1.1.3 (2016-09-22)

バグ修正
  • ImagesPipelineFilesPipeline のサブクラスのクラス属性は1.1.1以前と同じように機能します (issue 2243, 修正 issue 2198)

文書

Scrapy 1.1.2 (2016-08-18)

バグ修正
  • 欠落している IMAGES_STORE_S3_ACL 設定を導入して、S3に画像をアップロードするときに ImagesPipeline のデフォルトのACLポリシーを上書きします(Scrapy 1.1.0以降、デフォルトのACLポリシーは "public-read" ではなく "private" であることに注意してください)

  • IMAGES_EXPIRES 値が90に戻されました(デグレは1.1.1で発生しました)

Scrapy 1.1.1 (2016-07-13)

バグ修正
  • HTTPSプロキシーへのCONNECTリクエストに "Host" ヘッダーを追加 (issue 2069)

  • レスポンス・クラスを選択するときにレスポンス `` body``を使用します (issue 2001, 修正 issue 2000)

  • 間違ったnetlocでURLを正規化することに失敗しないでください (issue 2038, 修正 issue 2010)

  • HttpCompressionMiddleware (と SitemapSpider) で小修正:

  • IPアドレスホストに対して証明書を検証するときに例外をキャッチ(および警告付きで無視) (issue 2094, 修正 issue 2092)

  • カスタマイズのためのレガシー・クラス属性の使用に関して、 FilesPipelineImagesPipeline の下位互換性を再度作成します (issue 1989, 修正 issue 1985)

新機能
  • プロジェクト・フォルダの外で genspider を有効にする (issue 2052)

  • HTTPS CONNECT TunnelError をデフォルトで再試行 (issue 1974)

文書
  • 辞書式順序での FEED_TEMPDIR 設定 (commit 9b3c72c)

  • 概要で慣用的な .extract_first() を使用 (issue 1994)

  • 著作権表示年を更新 (commit c2c8036)

  • エラーバックに関する情報と例を追加 (issue 1995)

  • ダウンローダー・ミドルウェアの例で "url" 変数使用 (issue 2015)

  • 文法修正 (issue 2054, issue 2120)

  • スパイダー・コールバックでのBeautifulSoupの使用に関する新しいFAQ項目 (issue 2048)

  • ScrapyがPython3を搭載したWindowsで機能しないことに関する注記を追加 (issue 2060)

  • プル・リクエストで完全なタイトルを使う事を奨励する (issue 2026)

テスト
  • Travis CI と Pin pytest-cov py.test要件を2.2.1にアップグレードします (issue 2095)

Scrapy 1.1.0 (2016-05-11)

この1.1リリースには、多くの興味深い機能とバグ修正が含まれています:

  • Scrapy1.1はPython3のベータサポートがあります( Twisted >= 15.5 が必要です)。 詳細といくつかの制限については、 Python 3 のベータ・サポート を参照してください。

  • ホットな新機能:

    • Item loaderは今や入れ子になったローダーをサポートします (issue 1467)

    • FormRequest.from_response が改良されました (issue 1382, issue 1137)

    • 設定 AUTOTHROTTLE_TARGET_CONCURRENCY を追加し AutoThrottle 文書を改善しました (issue 1324)

    • 本文をunicodeとして取得するために response.text を追加しました (issue 1730)

    • アノニマス S3 接続 (issue 1358)

    • ダウンローダー・ミドルウェアでのDeferreds (issue 1473) 。 これにより robots.txt 処理が向上します (issue 1471)

    • HTTPキャッシュ処理は今やRFC2616に厳密に従います。そして設定 HTTPCACHE_ALWAYS_STOREHTTPCACHE_IGNORE_RESPONSE_CACHE_CONTROLS が追加されました (issue 1151)

    • セレクターは parsel ライブラリに抽出されました (issue 1409) 。 つまり、ScrapyなしでScrapyセレクターを使用でき、Scrapyをアップグレードせずにセレクター・エンジンをアップグレードすることもできます。

    • HTTPSダウンローダーは、TLS 1.0を強制する代わりに、デフォルトでTLSプロトコル・ネゴシエーションを実行するようになりました。 あなたは 新しい DOWNLOADER_CLIENT_TLS_METHOD を使用してSSL/TLSメソッドを設定することもできます。

  • 以下のバグ修正には注意が必要な場合があります:

    • デフォルトでは、不正なリクエスト(HTTP 400)を再試行しないでください (issue 1289) 。 古い動作が必要な場合は、 400 「400」を RETRY_HTTP_CODES にセットしてください。

    • シェル・ファイルの引数処理を修正しました (issue 1710, issue 1550) 。 scrapy shell index.html を実行しようとすると、URL URL http://index.html ロードしようとします。ローカル・ファイルをロードするには、 scrapy shell ./index.html を使用してください。

    • Robots.txtコンプライアンスは、新しく作成されたプロジェクトに対してデフォルトで有効になりました (issue 1724) 。 Scrapyは、robots.txtがダウンロードされるのを待ってから、クロールを続行します (issue 1735) 。この動作を無効にする場合は、新しいプロジェクトを作成した後、 settings.py ファイルの ROBOTSTXT_OBEY を更新します。

    • エクスポータは、デフォルトでbyteではなくunicodeで動作するようになりました (issue 1080) 。 PythonItemExporter を使用する場合は、コードを更新して、現在非推奨となっているバイナリモードを無効にすることをお勧めします。

    • ドットを含むXMLノード名を有効なものとして受け入れます (issue 1533)

    • (FilesPipeline または ImagesPipeline を使用して)ファイルまたは画像をS3にアップロードする場合、デフォルトのACLポリシーが "public" ではなく "private" になりました。 警告:後方互換性がありません! FILES_STORE_S3_ACL を使用して変更できます。

    • 特に非ASCII文字を含むURLの場合、より正確な出力のために canonicalize_url() を再実装しました (issue 1947) 。これにより、以前のScrapyバージョンと比較してリンク抽出器の出力が変更される可能性があります。 これにより、1.1より前の実行でまだ保持されている可能性のある一部のキャッシュ・エントリが無効になる場合もあります。 警告:後方互換性がありません!

その他の改善点とバグ修正の詳細については、以下を読み進めてください。

Python 3 のベータ・サポート

私たちはScrapyをPython3で実行するために懸命に取り組んできました( hard at work to make Scrapy run on Python 3 )。 その結果、Python 3.3と3.4と3.5でスパイダーを実行できるようになりました( Twisted >= 15.5 が必要)。一部の機能はまだ欠落しています(一部は移植されない可能性があります)。

ほとんどすべての組み込み拡張機能/ミドルウェアが機能することが期待されています。けれども、我々はPython3ではいくつかの制限があることを認識しています:

  • ScrapyはPython3を搭載したWindowsでは機能しません

  • 電子メール送信はサポートされていません

  • FTPダウンロード処理はサポートされていません

  • Telnetコンソールはサポートされていません

追加の新機能と拡張機能
  • Scrapyにコーディング規範 ( Code of Conduct ) が追加されました (issue 1681)

  • コマンドライン・ツールでzsh補完できるようになりました (issue 934)

  • scrapy shell の改良:

    • bpythonをサポートし、 SCRAPY_PYTHON_SHELL を介して優先Pythonシェルを構成します (issue 1100, issue 1444)

    • スキーム無しのURLをサポート (issue 1498) 警告: 後方互換性がありません!

    • 相対ファイル・パスのサポートを復活させます (issue 1710, issue 1550)

  • デフォルトのチェック間隔を変更するために MEMUSAGE_CHECK_INTERVAL_SECONDS 設定を追加 (issue 1282)

  • ダウンロード・ハンドラーは、スキームを使用して最初のリクエストで遅延読み込みされるようになりました (issue 1390, issue 1421)

  • HTTPSダウンロード・ハンドラーはTLS1.0を強制しなくなりました。 代わりに、OpenSSLの SSLv23_method()/TLS_method() が使用され、リモート・ホストと可能な限り最高のTLSプロトコル・バージョンのネゴシエーションを試みることができます (issue 1794, issue 1629)

  • RedirectMiddleware は、スパイダー属性または Requestmeta キーの handle_httpstatus_list からステータス・コードをスキップするようになりました (issue 1334, issue 1364, issue 1447)

  • フォームの送信:

    • <button> 要素でも機能するようになりました (issue 1469)

    • 空の文字列が値のない送信ボタンに使用されるようになりました (issue 1472)

  • 辞書風な設定には、キーごとの優先順位があります (issue 1135issue 1149issue 1586)

  • 非ASCII電子メール送信 (issue 1662)

  • 関連する設定が設定されていない場合、 CloseSpiderSpiderState 拡張機能が無効になるようになりました (issue 1723, issue 1725)

  • ExecutionEngine.close メソッド追加 (issue 1423)

  • CrawlerRunner.create_crawler メソッド追加 (issue 1528)

  • スケジューラの優先度キューは、 SCHEDULER_PRIORITY_QUEUE を介してカスタマイズできるようになりました (issue 1822)

  • リンク抽出器で .pps リンクがデフォルトで無視されるようになりました (issue 1835)

  • FTPおよびS3フィード・ストレージの一時データ・フォルダーは、新しい FEED_TEMPDIR 設定を使用してカスタマイズできます (issue 1847)

  • FilesPipelineImagesPipeline の設定がクラス属性ではなくインスタンス属性になり、スパイダー固有の動作が可能になりました (issue 1891)

  • JsonItemExporter は、開始と終了の角括弧(square bracket)を独自の行(出力ファイルの最初と最後の行)でフォーマットするようになりました (issue 1950)

  • 利用可能な場合、 botocoreS3FeedStorageS3DownloadHandlerS3FilesStore に使用されます (issue 1761, issue 1883)

  • 大量の文書の更新と関連する修正 (issue 1291, issue 1302, issue 1335, issue 1683, issue 1660, issue 1642, issue 1721, issue 1727, issue 1879)

  • その他のリファクタリングと最適化と整理 (issue 1476, issue 1481, issue 1477, issue 1315, issue 1290, issue 1750, issue 1881)

非推奨と削除
  • to_bytesto_unicode を追加し、str_to_unicodeunicode_to_str 関数を非推奨にした (issue 778)

  • isbinarytext の使用を置き換えるために、 binary_is_text が導入されました(ただし、逆の戻り値で) (issue 1851)

  • optional_features セットは削除されました (issue 1359)

  • --lsprof コマンドライン・オプションが削除されました (issue 1689) 。 警告:後方互換性はありません。 しかし、ユーザー・コードを壊すことはありません。

  • 以下のデータ型は非推奨です (issue 1720):

    • scrapy.utils.datatypes.MultiValueDictKeyError

    • scrapy.utils.datatypes.MultiValueDict

    • scrapy.utils.datatypes.SiteNode

  • 以前にバンドルされていた scrapy.xlib.pydispatch ライブラリは非推奨になり、 pydispatcher に置き換えられました。

再配置
バグ修正
  • Scrapyは、 HTTP 400 Bad Request レスポンスを受け取ったリクエストを再試行しなくなりました (issue 1289) 。 警告:後方互換性がありません!

  • http_proxy configの空のパスワードをサポート (issue 1274)

  • application/x-jsonTextResponse として解釈します (issue 1333)

  • 複数の値を持つlink rel属性をサポート (issue 1201)

  • <base> タグがある場合の scrapy.http.FormRequest.from_response を修正 (issue 1564)

  • TEMPLATES_DIR 処理修正 (issue 1575)

  • FormRequest に関する様々な修正 (issue 1595, issue 1596, issue 1597)

  • _monkeypatches をより堅牢にします (issue 1634)

  • アイテムに文字列以外のフィールドがある XMLItemExporter のバグを修正しました (issue 1738)

  • macOSでのstartprojectコマンドの修正 (issue 1635)

  • 文字列以外のアイテム型の PythonItemExporter とCSVExporterを修正しました (issue 1737)

  • ロギング関係の様々な修正 (issue 1294, issue 1419, issue 1263, issue 1624, issue 1654, issue 1722, issue 1726 and issue 1303)

  • utils.template.render_templatefile() 内のバグを修正 (issue 1212)

  • robots.txt からのサイト・マップの抽出では、大文字と小文字が区別されなくなりました (issue 1902)

  • 同じリモート・ホストに複数のプロキシを使用すると、HTTPS+CONNECTトンネルが混同される可能性があります (issue 1912)

Scrapy 1.0.7 (2017-03-03)

  • パッケージの修正:setup.pyでサポートされていないTwistedバージョンを禁止します。

Scrapy 1.0.6 (2016-05-04)

  • 修正: RetryMiddlewareは、非標準のHTTPステータ・スコードに対して堅牢になりました (issue 1857)

  • 修正: ファイル・ストレージHTTPキャッシュが間違った変更時刻をチェックしていた (issue 1875)

  • 文書: Sphinx 1.4以降のサポート (issue 1893)

  • 文書: セレクターの例の一貫性 (issue 1869)

Scrapy 1.0.5 (2016-02-04)

  • 修正: [バックポート] LinkExtractorsの偽のリンクを無視 (修正 issue 907, commit 108195e)

  • テスト: 'pytest' を使用するようにbuildbot makefileを変更 (commit 1f3d90a)

  • 文書: チュートリアルとメディア・パイプラインのタイプミスを修正 (commit 808a9eacommit 803bd87)

  • 文書: 設定の文書のDOWNLOADER_MIDDLEWARES_BASEにAjaxCrawlMiddlewareを追加 (commit aa94121)

Scrapy 1.0.4 (2015-12-30)

  • Twistedバージョンに応じて、 xlib/tx フォルダーを無視します (commit 7dfa979)

  • 新しいtravis-ciインフラで実行 (commit 6e42f0b)

  • スペル修正 (commit 823a1cc)

  • xmliter正規表現のノード名をエスケープします (commit da3c155)

  • ドットありのxmlノード名をテスト (commit 4418fc3)

  • テスト: テストで、壊れているバージョンのPillowを使用禁止 (commit a55078c)

  • log on versionコマンドを無効にする。 closes #1426 (commit 86fc330)

  • log on startproject コマンド無効 (commit db4c9fe)

  • PyPIダウンロード統計バッジを追加 (commit df2b944)

  • PRが scrapy/scrapyブランチから作成されている場合は、Travisでテストを2回実行しないでください (commit a83ab41)

  • Python 3移植ステータス・バッジをREADMEに追加 (commit 73ac80d)

  • RFPDupeFilterの永続性を修正 (commit 97d080e)

  • テスト: dupefilterの永続性が機能していないことを示すテスト (commit 97f2fb3)

  • file:// スキーム・ハンドラーの明示的なファイル・クローズ (commit d9b4850)

  • シェルでdupefilterを無効にします (commit c0d0734)

  • 文書: サイドバーに表示されるtoctreeにキャプションを追加 (commit aa239ad)

  • 文書: pywin32はすでに依存関係として宣言されているため、インストール手順から削除しました。 (commit 10eb400)

  • Conda for Windowsおよびその他のOSの使用に関するインストール注記を追加 (commit 1c3600a)

  • 些細な文法の問題を修正 (commit 7f4ddd5)

  • 文書のタイプミスを修正 (commit b71f677)

  • 今やバージョン1が存在します (commit 5456c0e)

  • もう一つの無効なxpathエラーを修正 (commit 0a1366e)

  • ValueErrorを修正: 無効なXPath: selectors.rstの //div/[id="not-exists"]/text() (commit ca8d60f)

  • タイプミス修正 (commit 7067117)

  • downloader-middleware.rst と exceptions.rst 内のタイプミス修正。middlware → middleware (commit 32f115c)

  • Debianの互換性に関するメモをUbuntuインストール節に追加 (commit 23fda69)

  • macOSインストール代替回避策をvirtualenvに置き換え (commit 98b63ee)

  • インストール手順については、Homebrewのホームページを参照 (commit 1925db1)

  • サポートされている最も古いtoxバージョンを寄稿文書に追加 (commit 5d10d6d)

  • 注意: すでに python>=2.7.9 に含まれているpipに関するインストール文書に注意してください (commit 85c980e)

  • 文書のUbuntuインストール節にPython以外の依存関係を追加 (commit fbd010d)

  • 文書にmacOSインストール節追加 (commit d8f4cba)

  • 文書(ENH): rtdテーマへのパスを明示的に指定 (commit de73b1a)

  • 些細な修正: scrapy.Spider 文書の文法 (commit 1ddcc7b)

  • 一般的な慣行のサンプル・コードをコメントと一致させます (commit 1b85bcf)

  • nextcall反復呼び出し(heartbeats) (commit 55f7104)

  • Twisted 15.4.0 とバックポート修正の互換性 (commit b262411)

  • pin pytest to 2.7.3 (commit a6535c2)

  • mgedmin/patch-1からのプル・リクエスト #1512 をマージします (commit 8876111)

  • mgedmin/patch-2からのプル・リクエスト #1513 をマージします (commit 5d4daf8)

  • タイプミス (commit f8d0682)

  • リスト・フォーマットの修正 (commit 5f83a93)

  • queuelibに最近変更を加えた後のScrapyスキュー・テストを修正 (commit 3365c01)

  • rweindl/patch-1からのプル・リクエスト #1475 をマージします (commit 2d688cd)

  • tutorial.rstを更新 (commit fbc1f25)

  • rhoekman/patch-1からのプル・リクエスト #1449 をマージします (commit 7d6538c)

  • 文法的小変更 (commit 8752294)

  • versionコマンドにopensslバージョンを追加 (commit 13c45ac)

Scrapy 1.0.3 (2015-08-11)

Scrapy 1.0.2 (2015-08-06)

Scrapy 1.0.1 (2015-07-01)

  • FTPClientに渡す前にリクエスト・パスをunquoteします。すでにパスはエスケープされています (commit cc00ad2)

  • MANIFEST.in にテスト/ソース配布を含める (commit eca227e)

  • 文書: SelectJmes文書修正 (commit b8567bc)

  • 文書: UbuntuとArchlinuxをWindowsサブセクションの外に持ってくる (commit 392233f)

  • 文書: Ubuntuパッケージからバージョン・サフィックスを削除 (commit 5303c66)

  • 文書: 1.0のリリース日を更新 (commit c89fa29)

Scrapy 1.0.0 (2015-06-19)

このメジャーリリースには、多くの新機能とバグ修正が含まれています。 更新された overview を確認して、磨かれた チュートリアル とともに変更の一部を確認してください。

スパイダーで辞書を返すためのサポート

スパイダーからスクレイピングされたデータを収集するために、スクレイピーアイテムを宣言して返す必要はなくなりました。代わりに、明示的な辞書を返すことができるようになりました。

化石版

class MyItem(scrapy.Item):
    url = scrapy.Field()

class MySpider(scrapy.Spider):
    def parse(self, response):
        return MyItem(url=response.url)

新版

class MySpider(scrapy.Spider):
    def parse(self, response):
        return {'url': response.url}
スパイダー毎の設定 (GSoC 2014)

前回のGoogle Summer of Code プロジェクトでは、設定の入力に使用されるメカニズムの重要な再設計が完了し、特定の設定を上書きする明示的な優先順位が導入されました。その目標の延長として、単一のスパイダー専用に機能する設定に新しいレベルの優先度を含め、プロジェクト設定を再定義できるようにしました。

あなたのスパイダーで custom_settings クラス変数を定義して使用を開始します:

class MySpider(scrapy.Spider):
    custom_settings = {
        "DOWNLOAD_DELAY": 5.0,
        "RETRY_ENABLED": False,
    }

設定の作成について詳しくは、 設定 をご覧ください

Pythonロギング

Scrapy 1.0は、Twistedロギングから離れ、デフォルトのロギング・システムとしてPython組み込みのものをサポートするようになりました。 ロギング関数を呼び出すための古いカスタム・インターフェースのほとんどについて下位互換性を維持していますが、PythonロギングAPIに完全に切り替えるように警告が表示されます。

旧版

from scrapy import log
log.msg('MESSAGE', log.INFO)

新版

import logging
logging.info('MESSAGE')

スパイダーを使用したロギングは変わりませんが、 log() メソッドに加えて、スパイダーがログ・イベントを発行するために作成されたカスタム logger にアクセスできます:

class MySpider(scrapy.Spider):
    def parse(self, response):
        self.logger.info('Response received')

詳細については、ロギング文書をご覧ください: ロギング(logging)

クローラーAPIリファクタリング (GSoC 2014)

前回のGoogle Summer of Codeのもう1つのマイル・ストーンは、内部APIのリファクタリングであり、よりシンプルで簡単な使用法を模索していました。 コアAPI で新しいコア・インターフェースを確認してください。

これらの変更に直面する一般的な状況は、スクリプトからScrapyを実行しているときです。 新しいAPIを使用してSpiderを手動で実行する方法の簡単な例を以下に示します:

from scrapy.crawler import CrawlerProcess

process = CrawlerProcess({
    'USER_AGENT': 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)'
})
process.crawl(MySpider)
process.start()

この機能はまだ開発中であり、安定した状態に達するまではAPIが変更される可能性があることに注意してください。

Scrapyを実行するスクリプトの例をもっと見る: よくある例

モジュールの再配置

Scrapyの一般的な構造の改善を試み、モジュールが大幅に再配置されました。主な変更点は、さまざまなサブ・パッケージを新しいプロジェクトに分割し、 scrapy.contribscrapy.contrib_exp の両方をトップ・レベルのパッケージに分解することでした。非推奨のモジュールをインポートすると、新しい場所を示す警告が表示されるため、内部再配置間で下位互換性が維持されています。

再配置全リスト

括り出されたパッケージ

注釈

これらの拡張機能には、いくつかの小さな変更が加えられました。一例として、一部の設定名が変更されました。新しい使用法を理解するには、新しい各リポジトリの文書を確認してください。

古い場所

新しい場所

scrapy.commands.deploy

scrapyd-client (他の選択肢はこちら: スパイダーのデプロイ)

scrapy.contrib.djangoitem

scrapy-djangoitem

scrapy.webservice

scrapy-jsonrpc

scrapy.contrib_expscrapy.contrib を廃止

古い場所

新しい場所

scrapy.contrib_exp.downloadermiddleware.decompression

scrapy.downloadermiddlewares.decompression

scrapy.contrib_exp.iterators

scrapy.utils.iterators

scrapy.contrib.downloadermiddleware

scrapy.downloadermiddlewares

scrapy.contrib.exporter

scrapy.exporters

scrapy.contrib.linkextractors

scrapy.linkextractors

scrapy.contrib.loader

scrapy.loader

scrapy.contrib.loader.processor

scrapy.loader.processors

scrapy.contrib.pipeline

scrapy.pipelines

scrapy.contrib.spidermiddleware

scrapy.spidermiddlewares

scrapy.contrib.spiders

scrapy.spiders

  • scrapy.contrib.closespider

  • scrapy.contrib.corestats

  • scrapy.contrib.debug

  • scrapy.contrib.feedexport

  • scrapy.contrib.httpcache

  • scrapy.contrib.logstats

  • scrapy.contrib.memdebug

  • scrapy.contrib.memusage

  • scrapy.contrib.spiderstate

  • scrapy.contrib.statsmailer

  • scrapy.contrib.throttle

scrapy.extensions.*

複数形の名前変更とモジュールの統合

古い場所

新しい場所

scrapy.command

scrapy.commands

scrapy.dupefilter

scrapy.dupefilters

scrapy.linkextractor

scrapy.linkextractors

scrapy.spider

scrapy.spiders

scrapy.squeue

scrapy.squeues

scrapy.statscol

scrapy.statscollectors

scrapy.utils.decorator

scrapy.utils.decorators

クラス名変更

古い場所

新しい場所

scrapy.spidermanager.SpiderManager

scrapy.spiderloader.SpiderLoader

Settings renames

古い場所

新しい場所

SPIDER_MANAGER_CLASS

SPIDER_LOADER_CLASS

変更ログ

新機能と拡張

非推奨と削除

  • htmlparserリンク抽出器を非推奨とする (issue 1205)

  • FeedExporterから非推奨コードを削除 (issue 1155)

  • leftover for.15 互換性 (issue 925)

  • CONCURRENT_REQUESTS_PER_SPIDERサポートの終了 (issue 895)

  • 古いエンジン・コードを削除 (issue 911)

  • SgmlLinkExtractor を非推奨とする (issue 777)

再配置

  • exporters/__init__.py を exporters.py へ移動 (issue 1242)

  • 基底クラス群をそれぞれのパッケージへ移動 (issue 1218, issue 1233)

  • モジュール再配置 (issue 1181, issue 1210)

  • SpiderManager から SpiderLoader へ名前変更 (issue 1166)

  • djangoitem 削除 (issue 1177)

  • scrapy deploy コマンド削除 (issue 1102)

  • contrib_exp 利用解消 (issue 1134)

  • ルート・フォルダーからbinフォルダー削除。修正: #913 (issue 914)

  • jsonrpcベースのwebservice削除 (issue 859)

  • テスト・ケースをプロジェクト・ルート・ディレクトリの下に移動 (issue 827, issue 841)

  • 設定内の再配置されたパスの後方非互換性を修正 (issue 1267)

文書

バグ修正

  • アイテムの他重継承修正 (issue 353, issue 1228)

  • ItemLoader.load_item: フィールド達のコピーを反復処理します (issue 722)

  • Deferredの未処理エラーを修正(RobotsTxtMiddleware) (issue 1131, issue 1197)

  • DOWNLOAD_TIMEOUTをintとして強制的に読み取る (issue 954)

  • scary.utils.misc.load_objectは完全なトレース・バックを出力する必要があります (issue 902)

  • ".local" ホスト・ネームのバグを修正 (issue 878)

  • 有効な拡張機能、ミドルウェア、パイプライン情報が印刷されなくなった問題の修正 (issue 879)

  • metaでfalseに設定された場合のdont_merge_cookiesの不正な動作を修正 (issue 846)

進行中のPython3サポート

  • twisted.conchが利用できない場合はscrapy.telnetを無効にします (issue 1161)

  • ajaxcrawl.pyのPython3構文エラーを修正 (issue 1162)

  • urllibのpython3互換性を高める変更 (issue 1121)

  • assertItemsEqualは、Python 3でassertCountEqualに名前が変更されました。 (issue 1070)

  • 存在すればunittest.mockをインポートします (issue 1066)

  • 非推奨のcgi.parse_qslを更新して、6つのparse_qslを使用するようにしました (issue 909)

  • Python3対応移植のデグレを防ぐ (issue 830)

  • PY3:Python 3にMutableMappingを使用 (issue 810)

  • PY3: six.BytesIO と six.moves.cStringIO を使用 (issue 803)

  • PY3: fix xmlrpclib と email のインポートを修正 (issue 801)

  • PY3: robotparser と urlparse に six を使用します (issue 800)

  • PY3: six.iterkeys と six.iteritems と tempfile を使用 (issue 799)

  • PY3: has_keyの修正とsix.moves.configparserの使用 (issue 798)

  • PY3: six.moves.cPickle の使用 (issue 797)

  • PY3: Python3でいくつかのテストを実行できるようにします (issue 776)

テスト

  • py3-ignoresから不要行を削除 (issue 1243)

  • テストの収集中のpytestからの残りの警告を修正しました (issue 1206)

  • travisでビルドの文書を追加 (issue 1234)

  • テスト: 非推奨のモジュールからテストを収集しないでください。 (issue 1165)

  • 警告を防ぐためにテストにservice_identityパッケージをインストール (issue 1168)

  • テストで非推奨の設定APIを修正しました (issue 1152)

  • POSTメソッドを使用し、ボディが指定されていないWebクライアントのテストを追加 (issue 1089)

  • py3-ignores.txtでコメントをサポート (issue 1044)

  • 一部のアサートを最新化する (issue 835)

  • selector.__repr__ テスト (issue 779)

コードのリファクタリング

  • CSVFeedSpiderの整理: iterate_spider_outputを使用 (issue 1079)

  • 不要なチェックをscrapy.utils.spider.iter_spider_outputから削除 (issue 1078)

  • Pydispatch pep8 (issue 992)

  • walk_modules()から未使用の 'load=False' パラメーターを削除しました (issue 871)

  • 一貫性を保つために、 SpiderState 拡張機能で job_dir ヘルパーを使用してください。 (issue 805)

  • "sflo" ローカル変数の名前を、分かりやすい "log_observer" に変更します (issue 775)

Scrapy 0.24.6 (2015-04-20)

  • Python2の下でunicode_escapeを使用して無効なxpathをエンコード (commit 07cb3e5)

  • IPythonシェル・スコープの問題を修正し、IPythonユーザー構成をロード (commit 2c8e573)

  • 文書の些細なタイプミスを修正 (commit d694019)

  • 些細なタイプミスを修正 (commit f92fa83)

  • データの抽出で、 sel.xpath() 呼び出しを response.xpath() に変換 (commit c2c6d15)

Scrapy 0.24.5 (2015-02-25)

  • Twisted 15.0.0の新しい _getEndpoint エージェント・シグネチャをサポート (commit 540b9bc)

  • 文書: さらにいくつかの参照が修正されました (commit b4c454b)

  • 文書: 参照を修正 (commit e3c1260)

  • t.i.b.ThreadedResolver は今や新スタイルのクラス (commit 9e13f42)

  • S3DownloadHandler: 引用符で囲まれた パス/クエリ・パラメータ を含むリクエストの認証を修正 (commit cdb9a0b)

  • mailsenderに関する文書の変数タイプを修正 (commit bb3a848)

  • item_countの代わりにitems_scrapedをリセットします (commit edb07a4)

  • 投稿のためにどの文書を読むべきかについての暫定的な注意メッセージ (commit 7ee6f7a)

  • mitmproxy 0.10.1 には netlib 0.10.1 も必要です (commit 874fcdd)

  • mitmproxy 0.10.1 を >0.11 として固定すると、テストでは機能しません (commit c6b21f0)

  • 外部URLに対してではなく、ローカルで解析コマンドをテストします (commit c3a6628)

  • HTTPDownloadHandlerで接続プールを閉じる際のTwistedの問題にパッチを適用 (commit d0bf957)

  • 動的アイテム・クラスに関する文書を更新 (commit eeb589a)

  • Lazar-T/patch-3 からのプル・リクエスト #943 をマージ (commit 5fdab02)

  • タイプミス (commit b0ae199)

  • Twistedにはpywin32が必要です。 #937 を閉じます (commit 5cb0cfb)

  • install.rst 更新 (commit 781286b)

  • Lazar-T/patch-1 からのプル・リクエスト #928 をマージ (commit b415d04)

  • ピリオド(fullstop)の代わりにコンマ(comma) (commit 627b9ba)

  • jsma/patch-1 からのプル・リクエスト #885 をマージ (commit de909ad)

  • request-response.rst を更新 (commit 3f3263d)

  • SgmlLinkExtractor - Unicodeが存在する <area> タグを解析するための修正 (commit 49b40f0)

Scrapy 0.24.4 (2014-08-09)

  • pemファイルはmockserverによって使用され、scrapyベンチによって必要とされます (commit 5eddc68)

  • scrapyベンチには scrapy.tests* が必要です (commit d6cb999)

Scrapy 0.24.3 (2014-08-09)

  • 0.24のpy3でtravis-ci時間を無駄にする必要はありません (commit 8e080c1)

  • インストールの文書を更新 (commit 1d0c096)

  • Scrapyフレームワーク用のtrove classifierがあります! (commit 4c701d7)

  • w3libバージョンが言及されている他の場所を更新します (commit d109c13)

  • w3lib要件を1.8.0に更新します (commit 39d2ce5)

  • w3lib.html.replace_entities() を使って下さい (remove_entities() は非推奨になりました) (commit 180d3ad)

  • set zip_safe=False (commit a51ee8b)

  • テストパッケージを出荷しない (commit ee3b371)

  • sparky.batはもう必要ありません (commit c3861cf)

  • setup.pyを最新化する (commit 362e322)

  • ヘッダーは文字列以外の値を処理できません (commit 94a5c65)

  • ftpテスト・ケースを修正 (commit a274a7f)

  • travis-ciビルドは完了するのに合計50分ほどかかります (commit ae1e2cc)

  • shell.rstのタイプミスを更新 (commit e49c96a)

  • シェルの結果の奇妙なインデントを削除 (commit 1ca489d)

  • 説明の改善、ソースとしてのブログ投稿の明確化、仕様にXPath文字列関数へのリンクの追加 (commit 65c8f05)

  • UserTimeoutError と ServerTimeouterror の名前変更 #583 (commit 037f6ab)

  • セレクターの文書にいくつかのxpathのヒントを追加 (commit 2d103e0)

  • https://github.com/scrapy/w3lib/pull/23 のためのアカウントのテストを修正 (commit f8d366a)

  • get_func_args最大再帰修正 #728 (commit 81344ea)

  • #560 に従って入出力プロセッサの例を更新 (commit f7c4ea8)

  • チュートリアルのPython文法を修正 (commit db59ed9)

  • トンネリング・プロキシー(tunneling proxy)のテスト・ケースを追加 (commit f090260)

  • トンネリングを使用しているときにプロキシ認証ヘッダーをリモート・ホストにリークするバグを修正 (commit d8793af)

  • MIMEタイプが "application/xml" のXHTMLドキュメントからリンクを抽出 (commit ed1f376)

  • roysc/patch-1からのプル・リクエスト #793 をマージ (commit 91a1106)

  • commands.rst内のタイプミスを修正 (commit 743e1e2)

  • settings.overrides.setdefaultのより良いテスト・ケース (commit e22daaf)

  • http 1.1の定義に従ってCRLFをライン・マーカーとして使用する (commit 5ec430b)

Scrapy 0.24.2 (2014-07-08)

  • 非推奨のsettings.overridesおよびsettings.defaults属性をプロキシーするために可変マッピングを使用します (commit e5e8133)

  • python3はまだサポートされていません (commit 3cd6146)

  • Python互換バージョンセットをDebianパッケージに更新します (commit fa5d76b)

  • 文書: リリース・ノートの書式を修正 (commit c6a9e20)

Scrapy 0.24.1 (2014-06-27)

  • 非推奨のCrawlerSettingsを修正し、.defaults属性との下位互換性を高めます (commit 8e3f20a)

Scrapy 0.24.0 (2014-06-26)

機能強化
  • Scrapyのトップレベルの名前空間改善 (issue 494, issue 684)

  • レスポンスにセレクター・ショートカットを追加 (issue 554, issue 690)

  • 新しいlxmlベースのLinkExtractorを追加して、メンテナンスされていないSgmlLinkExtractorを置き換えます (issue 559, issue 761, issue 763)

  • 設定APIの整理: スパイダー毎の設定の一部 GSoC プロジェクト (issue 737)

  • テンプレートにUTF8エンコーディング・ヘッダーを追加 (issue 688, issue 762)

  • Telnetコンソールはデフォルトで127.0.0.1にバインドするようになりました (issue 699)

  • Debian/Ubuntuのインストール手順を更新 (issue 509, issue 549)

  • lxml XPath評価でスマート文字列を無効にする (issue 535)

  • ファイルシステム・ベースのキャッシュをhttpキャッシュ・ミドルウェアのデフォルトとして復元 (issue 541, issue 500, issue 571)

  • Scrapyシェルで現在のクローラーを公開 (issue 557)

  • CSVとXMLエクスポーターを比較するテスト・スイートを改善 (issue 570)

  • offsite/filtered 統計と、新 offsite/domains 統計 (issue 566)

  • CrawlSpiderのジェネレーターとしてprocess_linksをサポート (issue 555)

  • DupeFilterの詳細ログと新しい統計カウンター (issue 553)

  • MailSender.send() に mimetype パラメーターを追加 (issue 602)

  • ファイル・パイプライン・ログ・メッセージを一般化 (issue 622)

  • エンコードできないコード・ポイントをSGMLLinkExtractorのhtmlエンティティに置き換え (issue 565)

  • SEP文書をrst書式に変換 (issue 629, issue 630, issue 638, issue 632, issue 636, issue 640, issue 635, issue 634, issue 639, issue 637, issue 631, issue 633, issue 641, issue 642)

  • FormRequestのclickdataのnrインデックスのテストと文書化 (issue 646, issue 645)

  • 他のコンポーネントと同様にダウンローダー・ハンドラーを無効にできるようにします (issue 650)

  • リダイレクトが多すぎるためにリクエストが破棄されたときにログに記録する (issue 654)

  • スパイダー・コールバックによって処理されない場合は、エラー・レスポンスをログに記録 (issue 612, issue 656)

  • コンテンツ・タイプ・チェックをhttp圧縮mwに追加 (issue 193, issue 660)

  • ppaの最新のpypiを使用してpypyテストを実行します (issue 674)

  • trialの代わりにpytestを使用してテスト・スイートを実行します (issue 679)

  • 文書をビルドし、tox環境でリンク切れをチェック (issue 687)

  • scarp.version_infoを整数のタプルにします (issue 681, issue 692)

  • ファイル名拡張子からエクスポーターの出力形式を推測 (issue 546, issue 659, issue 760)

  • url_is_from_any_domain() で大文字と小文字を区別しないドメインをサポート (issue 693)

  • プロジェクトおよびスパイダー・テンプレートのpep8警告を削除 (issue 698)

  • request_fingerprint 関数のテストと文書化 (issue 597)

  • GSoCプロジェクトの per-spider settings (スパイダーごとの設定) のSEP-19を更新 (issue 705)

  • 規約が失敗した場合、終了コードをゼロ以外に設定 (issue 727)

  • ダウンロード・コンポーネントとしてインスタンス化されるクラスを制御する設定を追加 (issue 738)

  • item_dropped シグナルでレスポンスを渡します (issue 724)

  • scrapy check 規約(contract)コマンドを改善 (issue 733, issue 752)

  • spider.closed() ショートカットの文書化 (issue 719)

  • request_scheduled シグナルの文書化 (issue 746)

  • セキュリティ問題を報告するときの注記を追加 (issue 697)

  • evelDB httpキャッシュ・ストレージ・バックエンドを追加 (issue 626, issue 500)

  • scrapy list コマンドのスパイダー・リスト出力をソート (issue 742)

  • 複数の文書の拡張強化と修正 (issue 575, issue 587, issue 590, issue 596, issue 610, issue 617, issue 618, issue 627, issue 613, issue 643, issue 654, issue 675, issue 663, issue 711, issue 714)

バグ修正
  • RegexLinkExtractorでリンクを作成するときにunicode URL値をエンコード (issue 561)

  • ItemLoaderプロセッサのNone値を無視 (issue 556)

  • SGMLLinkExtractorとHtmlParserLinkExtractorに内部タグがある場合のリンク・テキストを修正 (issue 485, issue 574)

  • 非推奨のクラスのサブクラス化に関する誤ったチェックを修正 (issue 581, issue 584)

  • inspect.stack() の失敗によって引き起こされたエラーを処理 (issue 582)

  • 存在しないエンジン属性への参照を修正 (issue 593, issue 594)

  • type()の動的itemclassの使用例を修正 (issue 603)

  • lucasdemarchi/codespellを使用してタイプミスを修正 (issue 628)

  • SgmlLinkExtractorのattrs引数のデフォルト値がタプルになるように修正 (issue 661)

  • サイトマップ・リーダーのXXEの欠陥を修正 (issue 676)

  • フィルタリングされた開始リクエストをサポートするようにエンジンを修正 (issue 707)

  • ホスト名のないURLのオフサイト・ミドルウェア・ケースを修正 (issue 745)

  • TestsuiteはもうPILを必要としません (issue 585)

Scrapy 0.22.2 (released 2014-02-14)

  • 存在しないengine.slotsへの参照を修正。 #593 をクローズ (commit 13c099a)

  • downloaderMW文書のタイプミス(spiderMW文書をコピった半端物) (commit 8ae11bf)

  • タイプミス修正 (commit 1346037)

Scrapy 0.22.1 (released 2014-02-08)

  • localhost666は特定の状況下で解決できます (commit 2ec2279)

  • inspect.stackの失敗をテスト (commit cc3eda3)

  • inspect.stack() が失敗した場合の処理 (commit 8cb44f9)

  • 非推奨クラスのサブクラス化に関する誤ったチェックを修正。 #581 をクローズ (commit 46d98d6)

  • 文書: 最後のスパイダーの例の4スペース・インデント (commit 13846de)

  • HtmlParserLinkExtractorを修正し、 #485 マージ後にテストします (commit 368a946)

  • BaseSgmlLinkExtractor: リンクに内部タグがある場合に欠落していたスペースを修正 (commit b566388)

  • BaseSgmlLinkExtractor: 内部タグ付きのリンクの単体テストを追加 (commit c1cb418)

  • BaseSgmlLinkExtractor: unknown_endtag() を修正して、終了タグが開始タグと一致する場合にのみ current_link=None を設定するようにしました (commit 7e4d627)

  • Travis-CIビルドのテストを修正 (commit 76c7e20)

  • 暗号化できないコードポイントをhtmlエンティティに置き換えます。修正 #562 と #285 (commit 5f87b17)

  • RegexLinkExtractor: リンクを作成するときにURL unicode値をエンコードします (commit d0ee545)

  • チュートリアルのクロール出力を最新の出力に更新 (commit 8da65de)

  • クローラー参照でシェル関連文書を更新し、実際のシェル出力を修正 (commit 875b9ab)

  • PEP8な些細な編集 (commit f89efaf)

  • Scrapyシェルで現在のクローラーを公開 (commit 5349cec)

  • 未使用のreインポートとPEP8な些細な編集 (commit 387f414)

  • ItemLoaderを使用するときは、Noneの値を無視します (commit 0632546)

  • 文書: デフォルト値のHTTPCACHE_STORAGEのタイプミスを修正しました。これは、Dbmではなくファイルシステムになりました (commit cde9a8c)

  • Ubuntuのセットアップ手順をリテラル・コードとして表示 (commit fb5c9c5)

  • Ubuntuでのインストール手順を更新 (commit 70fb105)

  • stray-leone/patch-1からのプル・リクエスト #550 をマージ (commit 6f70b6a)

  • Scrapy Ubuntuパッケージのバージョンを変更 (commit 725900d)

  • 0.22.0のリリース日を修正 (commit af0219a)

  • news.rstのタイプミスを修正し、(まだリリースされていない)ヘッダーを削除 (commit b7f58f4)

Scrapy 0.22.0 (released 2014-01-17)

機能強化
  • [ 後方互換性なし ] HTTPCacheMiddlewareバックエンドをファイルシステムに切り替えました (issue 541) 。 古いバックエンドを復元するには、 HTTPCACHE_STORAGEscrapy.contrib.httpcache.DbmCacheStorage に設定します

  • CONNECTメソッドを使用して https:// URLをプロキシーします (issue 392, issue 397)

  • googleによって定義されているajaxクロール可能なページをクロールするミドルウェアを追加 (issue 343)

  • scrapy.spider.BaseSpider を scrapy.spider.Spider に名前変更 (issue 510, issue 519)

  • セレクターはデフォルトでEXSLT名前空間を登録します (issue 472)

  • セレクターの名前変更と同様にアイテム・ローダーを統合する (issue 461)

  • RFPDupeFilter クラスを簡単にサブクラス化できるようにします (issue 533)

  • テスト・カバレッジと今後のPython3サポートを改善 (issue 525)

  • 設定とミドルウェアのスタートアップ情報をINFOレベルに出力 (issue 520)

  • get_func_args ユーティリティでパーシャル(partial)をサポート (issue 506, issue:504)

  • toxを介して個々にテストを実行できるようにする (issue 503)

  • リンク抽出器によって無視される拡張機能更新 (issue 498)

  • ファイル/画像/サムネイル のパスを取得するミドルウェア・メソッドを追加 (issue 490)

  • オフサイト・ミドルウェア・テストを改善 (issue 478)

  • RefererMiddlewareによって設定されたデフォルトのRefererヘッダーをスキップする方法を追加 (issue 475)

  • デフォルトの Accept-Encoding ヘッダーで x-gzip を送信しない (issue 469)

  • 設定を使用したhttpエラー処理の定義のサポート (issue 466)

  • レガシーが見つかった場合は常に最新のPythonイディオムを使用してください (issue 497)

  • 文書の改善と修正 (issue 527, issue 524, issue 521, issue 517, issue 512, issue 505, issue 502, issue 489, issue 465, issue 460, issue 425, issue 536)

修正
  • CrawlSpiderテンプレートのセレクター・クラスのインポートを更新 (issue 484)

  • engine.slots への存在しない参照を修正 (issue 464)

  • TextResponse以外のインスタンスで body_as_unicode() を呼び出そうとしないでください (issue 462)

  • XPathItemLoaderをサブクラス化するときに警告します。以前は、インスタンス化についてのみ警告していました。 (issue 523)

  • XPathSelectorをサブクラス化するときに警告します。以前は、インスタンス化についてのみ警告していました。 (issue 537)

  • メモリ統計の複数の修正 (issue 531, issue 530, issue 529)

  • FormRequest.from_response() のURLのオーバーライドを修正 (issue 507)

  • pip 1.5でのテスト・ランナーの修正 (issue 513)

  • スパイダー名がunicodeの場合のログ・エラーを修正 (issue 479)

Scrapy 0.20.2 (released 2013-12-09)

  • セレクターの変更に伴いCrawlSpiderテンプレートを更新 (commit 6d1457d)

  • チュートリアルのメソッド名を修正しました。 GH-480 をクローズ ( commit b4fc359 )

Scrapy 0.20.1 (released 2013-11-28)

  • include_package_dataは、公開されたソースからwheelを構築するために必要です (commit 5ba1ad5)

  • process_parallelは、内部遅延で障害をリークしていました。 #458 をクローズ (commit 419a780)

Scrapy 0.20.0 (released 2013-11-08)

機能強化
  • CSSセレクターを含む新セレクターAPI (issue 395 and issue 426),

  • リクエスト/レスポンスのURL/ボディ属性は不変になりました(それらの変更は長い間非推奨でした)

  • ITEM_PIPELINES が(リストではなく)辞書として定義されるようになりました

  • サイトマップ・スパイダーは代替URLを取得できます (issue 360)

  • Selector.remove_namespaces() は、要素の属性から名前空間を削除するようになりました。 (issue 416)

  • Python 3.3以降への道を開いた (issue 435, issue 436, issue 431, issue 452)

  • ネストをサポートするネイティブPythonの型を使用する新しいアイテム・エクスポーター (issue 366)

  • 設定で定義された同時実行性と一致するようにHTTP1.1プール・サイズを調整します (commit b43b5f575)

  • sparky.mail.MailSenderは、TLS経由で接続するか、STARTTLSを使用してアップグレードできるようになりました (issue 327)

  • ImagesPipelineから機能が除外された新しいFilesPipeline (issue 370, issue 409)

  • 画像処理にはPILではなくPillowをお勧めします (issue 317)

  • Ubuntu QuantalおよびRaring用のDebianパッケージを追加しました (commit 86230c0)

  • モック・サーバー(テストに使用)はHTTPSリクエストをリッスンできます (issue 410)

  • 複数のコア・コンポーネントからマルチ・スパイダー・サポートを削除 (issue 422, issue 421, issue 420, issue 419, issue 423, issue 418)

  • Travis-CIは、 w3libqueuelib のPythonパッケージの開発バージョンに対してScrapyの変更をテストするようになりました。

  • 継続的インテグレーション・テストにpypy2.1を追加 (commit ecfa7431)

  • Pylintedとpep8と、ソースから古いスタイルの例外を削除 (issue 430, issue 432)

  • パラメトリック・インポートにはimportlibを使用します (issue 445)

  • XmlItemExporterに影響するPython2.7.5で導入されたデグレを処理 (issue 372)

  • SIGINTでのクロール・シャットダウンのバグ修正 (issue 450)

  • FormRequest.from_response で reset 型の入力を送信しないでください (commit b326b87)

  • リクエストのerrbackで例外が発生したときにダウンロード・エラーを無視しないでください (commit 684cfc0)

バグ修正
  • Django 1.6でのテストを修正 (commit b6bed44c)

  • HTTP1.1ダウンロード・ハンドラーを使用して切断時にミドルウェアを再試行するための多くのバグ修正

  • Twistedリリース間の不整合を修正 (issue 406)

  • Scrapyシェルのバグを修正 (issue 418, issue 407)

  • setup.pyの不正な変数名を修正 (issue 429)

  • チュートリアルの参照を修正 (issue 387)

  • リクエスト・レスポンス文書群の改善 (issue 391)

  • ベスト・プラクティス文書の改善 (issue 399, issue 400, issue 401, issue 402)

  • django統合ドキュメントを改善 (issue 404)

  • bindaddress リクエスト・メタの文書化 (commit 37c24e01d7)

  • Request クラス文書の改善 (issue 226)

その他
  • Python 2.6のサポートを終了しました (issue 448)

  • インストールの依存関係として cssselect pythonパッケージを追加

  • libxml2とマルチ・セレクターのバックエンド・サポートを削除します。今後は lxml が必要になります。

  • Twistedの最小バージョンが10.0.0に増加し、Twisted8.0のサポートが削除されました。

  • テストスイートを実行するには、 mock Pythonライブラリが必要になります (issue 390)

謝辞

このリリースに貢献してくれたすべての人に感謝します!

コミット数でソートされた貢献者のリスト:

69 Daniel Graña <dangra@...>
37 Pablo Hoffman <pablo@...>
13 Mikhail Korobov <kmike84@...>
 9 Alex Cepoi <alex.cepoi@...>
 9 alexanderlukanin13 <alexander.lukanin.13@...>
 8 Rolando Espinoza La fuente <darkrho@...>
 8 Lukasz Biedrycki <lukasz.biedrycki@...>
 6 Nicolas Ramirez <nramirez.uy@...>
 3 Paul Tremberth <paul.tremberth@...>
 2 Martin Olveyra <molveyra@...>
 2 Stefan <misc@...>
 2 Rolando Espinoza <darkrho@...>
 2 Loren Davie <loren@...>
 2 irgmedeiros <irgmedeiros@...>
 1 Stefan Koch <taikano@...>
 1 Stefan <cct@...>
 1 scraperdragon <dragon@...>
 1 Kumara Tharmalingam <ktharmal@...>
 1 Francesco Piccinno <stack.box@...>
 1 Marcos Campal <duendex@...>
 1 Dragon Dave <dragon@...>
 1 Capi Etheriel <barraponto@...>
 1 cacovsky <amarquesferraz@...>
 1 Berend Iwema <berend@...>

Scrapy 0.18.4 (released 2013-10-10)

  • IPythonは名前空間の更新を拒否します。修正 #396 (commit 3d32c4f)

  • シェルコマンドのリクエストを置き換えるAlreadyCalledErrorを修正しました。 #407 をクローズ (commit b1d8919)

  • start_requestsの怠惰と早期ハングを修正 (commit 89faf52)

Scrapy 0.18.3 (released 2013-10-03)

  • 開始リクエストの遅延評価のデグレを修正 (commit 12693a5)

  • フォーム: リセット入力を送信しない (commit e429f63)

  • ユニット・テストのタイムアウトを増やして、travisの誤検知の失敗を減らします (commit 912202e)

  • jsonエクスポーターのバックポート・マスターの修正 (commit cfc2d46)

  • sdist tarballを生成する前に権限を修正してumaskを設定します (commit 06149e0)

Scrapy 0.18.2 (released 2013-09-03)

  • scrapy check コマンドの修正と後方互換性のあるマルチ・クローラー・プロセスのバックポート (issue 339)

Scrapy 0.18.1 (released 2013-08-27)

  • チェリー・ピックの変更によって追加された余分なインポートを削除 (commit d20304e)

  • twisted pre 11.0.0でのクロール・テストを修正 (commit 1994f38)

  • py26は長さゼロのフィールドをフォーマットできません{} (commit abf756f)

  • バインドされていないレスポンスでPotentiaDataLossエラーをテストします (commit b15470d)

  • content-lengthまたはTransfer-Encodingのないレスポンスを適切なレスポンスとして扱います (commit c4bf324)

  • http11ハンドラーが有効になっていない場合はResponseFailedを含めないでください (commit 6cbe684)

  • 新しいHTTPクライアントは、ResponseFailed例外で失われた接続をラップ(wrap)します。修正 #373 (commit 1a20bba)

  • travis-ciビルド・マトリックスを制限 (commit 3b01bb8)

  • peterarenot/patch-1からのプル・リクエスト #375 をマージ (commit fa766d7)

  • 正しいフォルダを参照するように修正 (commit 3283809)

  • UbuntuリリースをサポートするためにQuantal&Raringを追加 (commit 1411923)

  • http1クライアントへのアップグレード後に特定の接続エラーを再試行しなかった再試行ミドルウェアを修正し、 GH-373をクローズ (commit bb35ed0)

  • Python 2.7.4および2.7.5でXmlItemExporterを修正 (commit de3e451)

  • 0.18リリース・ノートの些細な更新 (commit c45e5f1)

  • 寄稿者リストの形式を修正 (commit 0b60031)

Scrapy 0.18.0 (released 2013-08-09)

  • pypiでテストする方法を含む、Toxを使用したテスト・スイートの実行に対する多くの改善

  • AJAXクロール可能なURLのGETパラメーターを処理 (commit 3fe2a32)

  • lxmlリカバー・オプションを使用してサイトマップをパースします (issue 347)

  • バグ修正: Cookieがnetlocではなくホスト名でマージされる (issue 352)

  • フラグ設定を使用した HttpCompressionMiddleware の無効化をサポート (issue 359)

  • XMLFeedSpideriternodes パーサーを使用してxml名前空間をサポートします (issue 12)

  • dont_cache リクエスト・メタ・フラグをサポート (issue 19)

  • バグ修正: Python 2.7.4の変更により scrapy.utils.gz.gunzip が壊れた (commit 4dc76e)

  • バグ修正: SgmlLinkExtractor のurlエンコード (issue 24)

  • バグ修正: TakeFirst プロセッサは0(ゼロ)値を破棄すべきではありません (issue 59)

  • xmlエクスポーターでネストされたアイテムをサポートする (issue 66)

  • クッキー処理性能の改善 (issue 77)

  • 重複フィルタリングされたリクエストを1回ログだけ記録します (issue 105)

  • リダイレクション・ミドルウェアをステータス・ミドルウェアとメタ・ベース・ミドルウェアに分割 (issue 78)

  • デフォルトのダウンローダー・ハンドラーとしてHTTP1.1を使用します (issue 109issue 318)

  • FormRequest.from_response でのxpathフォーム選択のサポート (issue 185)

  • バグ修正: SgmlLinkExtractor のunicodeデコード・エラー (issue 199)

  • バグ修正: pypiインタープリターでのシグナル・ディスパッチ (issue 205)

  • リクエストの遅延と同時実行処理を改善 (issue 206)

  • RFC2616キャッシュ・ポリシーを HttpCacheMiddleware に追加 (issue 212)

  • エンジンによってログに記録されるメッセージのカスタマイズを許可 (issue 214)

  • DjangoItem の複数の改善 (issue 217, issue 218, issue 221)

  • setuptoolsエントリ・ポイントを使用してScrapyコマンドを拡張します (issue 260)

  • スパイダーの allowed_domains 値の設定/タプルを許可する (issue 261)

  • settings.getdict をサポート (issue 269)

  • 内部の scrapy.core.scraper スロット処理を簡素化 (issue 271)

  • Item.copy 追加 (issue 290)

  • アイドル状態のダウンローダー・スロットを収集する (issue 297)

  • ftp:// スキームのダウンローダー・ハンドラー追加 (issue 329)

  • ダウンローダー・ベンチマーク・ウェブサーバーとスパイダー・ツールを追加 ベンチマーキング

  • (ディスク上の)永続的なキューを、Scrapyが依存する別のプロジェクト( queuelib )に移動しました

  • 外部ライブラリを使用してScrapyコマンドを追加 (issue 260)

  • scrapy コマンドライン・ツールに --pdb オプションを追加

  • XPathSelector.remove_namespaces を追加しました。これにより、便利にXML文書からすべての名前空間を削除できます(名前空間のないXPathを操作するため)。 セレクター に記載されています。

  • スパイダー規約のいくつかの改善

  • meta-refreshhtmlタグのリダイレクトを処理するMetaRefreshMiddldewareという名前の新しいデフォルトのミドルウェア、

  • MetaRefreshMiddldewareとRedirectMiddlewareには、 #62 に対処するための異なる優先順位があります

  • スパイダーにfrom_crawlerメソッド追加

  • モック・サーバーによるシステムテストを追加

  • macOS互換性のさらなる改善(Alex Cepoiに感謝)

  • シングルトンとマルチ・スパイダーのサポートに対するさらにいくつかの整理(Nicolas Ramirezに感謝)

  • カスタム・ダウンロード・スロットをサポート

  • "shell" コマンドに --spider オプション追加。

  • Scrapyの起動時にオーバーライドされた設定をログに記録する

このリリースに貢献してくれたすべての人に感謝します。コミット数でソートされた貢献者のリストは以下のとおりです:

130 Pablo Hoffman <pablo@...>
 97 Daniel Graña <dangra@...>
 20 Nicolás Ramírez <nramirez.uy@...>
 13 Mikhail Korobov <kmike84@...>
 12 Pedro Faustino <pedrobandim@...>
 11 Steven Almeroth <sroth77@...>
  5 Rolando Espinoza La fuente <darkrho@...>
  4 Michal Danilak <mimino.coder@...>
  4 Alex Cepoi <alex.cepoi@...>
  4 Alexandr N Zamaraev (aka tonal) <tonal@...>
  3 paul <paul.tremberth@...>
  3 Martin Olveyra <molveyra@...>
  3 Jordi Llonch <llonchj@...>
  3 arijitchakraborty <myself.arijit@...>
  2 Shane Evans <shane.evans@...>
  2 joehillen <joehillen@...>
  2 Hart <HartSimha@...>
  2 Dan <ellisd23@...>
  1 Zuhao Wan <wanzuhao@...>
  1 whodatninja <blake@...>
  1 vkrest <v.krestiannykov@...>
  1 tpeng <pengtaoo@...>
  1 Tom Mortimer-Jones <tom@...>
  1 Rocio Aramberri <roschegel@...>
  1 Pedro <pedro@...>
  1 notsobad <wangxiaohugg@...>
  1 Natan L <kuyanatan.nlao@...>
  1 Mark Grey <mark.grey@...>
  1 Luan <luanpab@...>
  1 Libor Nenadál <libor.nenadal@...>
  1 Juan M Uys <opyate@...>
  1 Jonas Brunsgaard <jonas.brunsgaard@...>
  1 Ilya Baryshev <baryshev@...>
  1 Hasnain Lakhani <m.hasnain.lakhani@...>
  1 Emanuel Schorsch <emschorsch@...>
  1 Chris Tilden <chris.tilden@...>
  1 Capi Etheriel <barraponto@...>
  1 cacovsky <amarquesferraz@...>
  1 Berend Iwema <berend@...>

Scrapy 0.16.5 (released 2013-05-30)

  • Scrapyデプロイが新しいエンドポイントにリダイレクトされるときにリクエスト・メソッドに従います (commit 8c4fcee)

  • 不正確なダウンローダー・ミドルウェアの文書を修正。 refs #280 (commit 40667cb)

  • 文書: 現在利用できなくなったdiveintopython.orgへのリンクを削除。 #246 をクローズ (commit bd58bfa)

  • 不正なhtml5ドキュメントでフォーム・ノードを検索します (commit e3d6945)

  • リストの代わりにタイプミスのラベル付け属性タイプboolを修正 (commit a274276)

Scrapy 0.16.4 (released 2013-01-23)

  • 文書のスペルミスを修正 (commit 6d2b3aa)

  • 拡張機能の無効化に関する文書を追加。 refs #132 (commit c90de33)

  • エラー・メッセージの書式を修正しました。 log.err() はクールな書式をサポートしておらず、エラーが発生した場合、メッセージは "ERROR: Error processing %(item)s" でした。 (commit c16150c)

  • lintおよび画像パイプライン・エラーのロギングの改善 (commit 56b45fc)

  • 文書のタイプミスを修正 (commit 243be84)

  • 文書トピックを追加: 幅広いクロールと一般的な慣行 (commit 1fbb715)

  • スパイダーが明示的に指定されていない場合のScrapy parseコマンドのバグを修正。 #209 をクローズ (commit c72e682)

  • docs/topics/commands.rst を更新 (commit 28eac7a)

Scrapy 0.16.3 (released 2012-12-07)

  • ダウンロード遅延を使用する場合の同時実行制限を削除し、リクエスト間の遅延が強制されるようにします (commit 487b9b5)

  • 画像パイプラインが失敗したときにエラーの詳細を追加 (commit 8232569)

  • macOS互換性を改善 (commit 8dcf8aa)

  • setup.py: README.rstを使用してlong_descriptionにデータを入力します (commit 7b5310d)

  • 文書: ClientFormへの廃止された参照を削除 (commit 80f9bb6)

  • デフォルトのストレージ・バックエンドの正しい文書 (commit 2aa491b)

  • 文書: FAQから壊れたproxyhubリンクを削除 (commit bdf61c4)

  • SpiderOpenCloseLoggingの例の文書のタイプミスを修正 (commit 7184094)

Scrapy 0.16.2 (released 2012-11-09)

Scrapy 0.16.1 (released 2012-10-26)

  • 0.16リリースの前に間違ったマージの後に壊れていたLogStats拡張機能を修正 (commit 8c780fd)

  • scarp.conf.settingsの下位互換性が向上しました (commit 3403089)

  • 拡張機能からクローラー統計にアクセスする方法に関する拡張文書 (commit c4da0b5)

  • .hgtagsを削除しました(Scrapyがgitを使用するようになったため、不要になりました) (commit d52c188)

  • 最初のヘッダーの下のダッシュを修正 (commit fa4f7f9)

  • リリース・ノートの0.16.0にリリース日を設定 (commit e292246)

Scrapy 0.16.0 (released 2012-10-18)

Scrapyの変更:

  • 追加された スパイダー規約(contract) は、形式的/再現可能な方法でスパイダーをテストするためのメカニズムです。

  • runspider コマンドにオプション -o-t を追加しました

  • AutoThrottle拡張機能 を文書化し、デフォルトでインストールされる拡張機能に追加しました。あなたはいまだ AUTOTHROTTLE_ENABLED でそれを有効にする必要があります

  • 主要な統計コレクションのリファクタリング: グローバル/スパイダーごとの統計の分離を削除し、統計関連の信号( stats_spider_opened など)を削除しました。統計がはるかにシンプルになり、Stats Collector APIとシグナルで下位互換性が維持されます。

  • スパイダー・ミドルウェアに process_start_requests() メソッドを追加した

  • Signalsシングルトンを削除しました。これで、Crawler.signals属性を介してシグナルにアクセスできるようになります。詳細については、シグナルのドキュメントを参照してください。

  • StatsCollectorシングルトンを削除しました。 Crawler.stats属性を介して統計にアクセスできるようになりました。 詳細については、統計コレクションのドキュメントを参照してください。

  • コアAPI について文書化した

  • libxml2 に代わり、 今や lxml がデフォルトのセレクター・バックエンドです

  • FormRequest.from_response() を移植して、 ClientForm の代わりに lxml を使用する

  • モジュール削除: scrapy.xlib.BeautifulSoupscrapy.xlib.ClientForm

  • SitemapSpider: 間違ったコンテンツ・タイプを主張(advertise)する場合、つまり、.xml および .xml.gz で終わるサイトマップURLのサポートが追加されました (commit 10ed28b)

  • StackTraceDump拡張機能: trackrefライブ参照もダンプします (commit fe2ce93)

  • ネストされたアイテムがJSONおよびJSONLinesエクスポーターで完全にサポートされるようになりました

  • スパイダーごとに複数のCookieセッションをサポートするための cookiejar リクエスト・メタ・キーを追加しました

  • エンコーディング検出コードを w3lib.encoding に分離し、そのモジュールを使用するためにScrapyコードを移植しました

  • Python 2.5 のサポートを終了しました。https://blog.scrapinghub.com/2012/02/27/scrapy-0-15-dropping-support-for-python-2-5/ 参照

  • Twisted 2.5 のサポートを終了した

  • リファラー・ミドルウェアを制御するために REFERER_ENABLED 設定を追加しました

  • デフォルトのユーザーエージェントを Scrapy/VERSION (+http://scrapy.org) に変更しました

  • scrapy.contrib.linkextractors.image から HTMLImageLinkExtractor クラスを削除(文書化されていない)

  • スパイダーごとの設定を削除しました(複数のクローラーオブジェクトをインスタンス化することで置き換えられます)

  • USER_AGENT スパイダー属性はもはや動作しません。代わりに user_agent 属性を使って下さい。

  • DOWNLOAD_TIMEOUT スパイダー属性はもはや動作しません。代わりに download_timeout 属性を使って下さい。

  • エンコーディングの自動検出が w3lib ライブラリに移動されたため、 ENCODING_ALIASES 設定が削除されました

  • DjangoItem をメインの投稿に昇格

  • LogFormatterメソッドは、遅延フォーマットをサポートするために、(文字列ではなく)辞書を返すようになりました (issue 164, commit dcef7b0)

  • ダウンローダー・ハンドラー(DOWNLOAD_HANDLERS 設定)は、 __init__ メソッドの最初の引数として設定を受け取るようになりました

  • メモリ使用量のカウントを(より移植性の高い) resource モジュールに置き換え、 scrapy.utils.memory モジュールを削除しました

  • シグナル削除した: scrapy.mail.mail_sent

  • TRACK_REFS 設定を削除し、 trackrefs が常に有効になりました

  • DBMがHTTPキャッシュ・ミドルウェアのデフォルトのストレージ・バックエンドになりました

  • (レベルごとの)ログ・メッセージの数がScrapy統計(統計名: log_count/LEVEL )で追跡されるようになりました

  • 受信したレスポンスの数がScrapy統計(統計名: response_received_count )で追跡されるようになりました

  • scrapy.log.started 属性を削除した

Scrapy 0.14.4

  • サポートされているUbuntuディストリビューションに追加されました (commit b7e46df)

  • https://groups.google.com/forum/#!topic/scrapy-users/qgVBmFybNAQ/discussionで報告されたjson-rpcWebサービスのバグを修正しました。 また、extras/scrapy-ws.pyからサポートされなくなった 'run' コマンドも削除されました

  • content-type http equivのメタ・タグ属性は、任意の順序にすることができます。 #123 (commit 0cb68af)

  • "import Image" をより標準的な "from PIL import Image" に置き換えます。 #88 をクローズ (commit 4d17048)

  • trialステータスを bin/runtests.sh 終了値として返します。 #118 (commit b7b2e7f)

Scrapy 0.14.3

  • pydispatchライセンスを含めるのを忘れていました。 #118 (commit fd85f9c)

  • testsuiteが使用するeggファイルをソース配布に含めます。 #118 (commit c897793)

  • 高度な機能と見なされる可能性のあるgenspiderコマンドとの混同を避けるために、プロジェクト・テンプレートのdocstringを更新します。 refs #107 (commit 2548dcc)

  • グーグル・ディレクトリがシャットダウンされることについての注記を docs/topics/firebug.rst に追加 (commit 668e352)

  • 空のときにスロットを破棄しないでください。必要に応じて再度リサイクルするために、別の辞書に保存してください。 (commit 8e9f607)

  • libxml2でサポートされているセレクターでのunicode xpathの処理に失敗しないでください (commit b830e95)

  • リクエスト・オブジェクトの文書の些細な間違いを修正 (commit bf3c9ee)

  • リンク抽出器の文書の些細な欠陥を修正 (commit ba14f38)

  • Scrapyでのsqliteサポートに関連するいくつかの廃止済のコードの残りを削除 (commit 0665175)

Scrapy 0.14.2

  • チェックサムを計算する前に、ファイルの先頭を指すバッファを移動します。 refs #92 (commit 6a5bef2)

  • 画像を永続化する前に、画像のチェックサムを計算します。 #92 をクローズ (commit 9817df1)

  • キャッシュされた障害でリークしている参照を削除 (commit 673a120)

  • MemoryUsage拡張機能のバグを修正した: get_engine_status() は正確に1つの引数を取ります(0個しか与えられていない) (commit 11133e9)

  • http圧縮ミドルウェアのstruct.errorを修正。 #87 をクローズ (commit 1423140)

  • ajaxクロールはunicode URLに対して拡張されていませんでした (commit 0de3fb4)

  • start_requests イテレータ・エラーをキャッチします。 refs #83 (commit 454a21d)

  • libxml2 XPathSelector の速度向上 (commit 2fbd662)

  • 最近の変更に応じてバージョン管理文書を更新 (commit 0a070f5)

  • scrapyd: 文書のリンク修正 (commit 2b4e4c3)

  • extras/makedeb.py: gitからバージョンを取得しなくなりました (commit caffe0e)

Scrapy 0.14.1

  • extras/makedeb.py: gitからバージョンを取得しなくなりました (commit caffe0e)

  • バージョンを0.14.1に上げました (commit 6cb9e1c)

  • チュートリアル・ディレクトリへの参照を修正 (commit 4b86bd6)

  • 文書: Request.replace() から重複したコールバック引数を削除 (commit 1aeccdd)

  • scrapyd文書の書式を修正 (commit 8bf19e6)

  • 実行中のすべてのスレッドのスタックをダンプし、StackTraceDump拡張機能によってダンプされたエンジン・ステータスを修正します (commit 14a8e6e)

  • boto画像のアップロードでSSLを無効にする理由についてのコメントを追加 (commit 5223575)

  • S3への並列接続が多すぎるとSSLハンドシェイクがハングします (commit 63d583d)

  • dmozサイトの変更に従うようにチュートリアルを変更 (commit bcb3198)

  • Twisted>=11.1.0 での _disconnectedDeferred AttributeError 例外を回避します (commit 98f3f87)

  • スパイダーがオート・スロットルの最大同時実行性を設定できるようにする (commit 175a4b5)

Scrapy 0.14

新機能と新設定
  • AJAX crawleable urls (AJAXクロール可能URL)をサポート

  • リクエストをディスクに保存し、クロールを一時停止および再開できる新しい永続スケジューラ (r2737)

  • スクレイピングされたアイテムをファイルにダンプするためのショートカットである scrapy crawl-o オプションを追加しました(または - を使用した標準出力)

  • Scrapyd schedule.json apiにカスタム設定を渡すためのサポートが追加されました (r2779, r2783)

  • chunked transfer encoding (チャンク転送エンコーディング) をサポートするための新しい ChunkedTransferMiddleware (デフォルトで有効) (r2769)

  • S3ダウンローダー・ハンドラーにboto 2.0サポートを追加 (r2763)

  • フィードのエクスポートでサポートされる形式に marshal を追加しました (r2744)

  • リクエストのエラー・バックで、問題のあるリクエストが failure.request 属性で受信されるようになりました (r2738)

  • ドメイン/IPごとの同時実行制限をサポートするための大きなダウンローダーのリファクタリング (r2732)
  • 組み込みのキャッシュDNSリゾルバーを追加 (r2728)

  • Amazon AWS関連のコンポーネント/拡張機能(SQSスパイダー・キュー、SimpleDB統計コレクター)を別のプロジェクトに移動しました: [scaws](https://github.com/scrapinghub/scaws) (r2706, r2714)

  • scrapydのスパイダー・キューを移動した: scrapy.spiderqueue から scrapyd.spiderqueue へ (r2708)

  • scrapydのsqliteユーティリティを移動した: scrapy.utils.sqlite から scrapyd.sqlite へ (r2781)

  • start_requests() メソッドでイテレータを返すための実際のサポート。 スパイダーがアイドル状態になっているクロール中にイテレーターが消費されるようになりました (r2704)

  • リダイレクト・ミドルウェアをすばやく有効/無効にする REDIRECT_ENABLED 設定を追加 (r2697)

  • 再試行ミドルウェアをすばやく有効/無効にする RETRY_ENABLED 設定を追加 (r2694)

  • スパイダーを手動で閉じるための CloseSpider 例外を追加 (r2691)

  • HTML5 meta charset 宣言のサポートを追加することによるエンコーディング検出の改善 (r2690)

  • スパイダーを閉じる前に、すべてのダウンロードが終了してスパイダーによって処理されるのを待つように、スパイダーを閉じる動作をリファクタリングしました (r2688)

  • SitemapSpider を追加(Spiders pageの文書参照) (r2658)

  • 基本的な統計(クロールされたページやスクレイピングされたアイテムなど)を定期的にログに記録するための LogStats 拡張機能が追加されました (r2657)

  • gzip圧縮されたレスポンスの処理をより堅牢にします (#319, r2643) 。これで、Scrapyは、 IOError で失敗するのではなく、gzip圧縮されたレスポンスから可能な限り解凍しようとします。

  • メモリ・デバッグ情報をダンプするための統計を使用するための簡略化された !MemoryDebugger 拡張機能 (r2639)

  • スパイダーを編集するための新しいコマンドを追加しました: scrapy edit (r2636) と、 -e フラグをそれを使用する genspider コマンドに追加しました (r2653)

  • アイテムのデフォルトの表現をきれいに印刷される辞書に変更しました。 (r2631) 。これにより、Scraped行とDropped行の両方について、デフォルトの場合にログが読みやすくなるため、デフォルトのログが改善されます。

  • spider_error シグナル追加 (r2628)

  • COOKIES_ENABLED 設定追加 (r2625)

  • 統計がScrapyログにダンプされるようになりました( STATS_DUMP 設定のデフォルト値が True に変更されました)。これは、ScrapyユーザーがScrapyの統計とそこで収集されるデータをより認識できるようにするためです。

  • ダウンロード遅延と最大同時リクエストを動的に調整するためのサポートが追加されました (r2599)

  • 新しいDBM HTTPキャッシュ・ストレージ・バックエンドを追加 (r2576)

  • Scrapyd へ listjobs.json API を追加 (r2571)

  • CsvItemExporter: join_multivalued パラメーター追加 (r2578)

  • xmliter_lxml に名前空間のサポートを追加 (r2552)

  • COOKIES_DEBUG をより良くし、それを文書化することにより、Cookieミドルウェアを改善しました (r2579)

  • ScrapydおよびLink抽出器のいくつかの改善

コードの再配置と削除
  • 過去に混乱を招くことが多かったため、マージされたアイテムの通過(pass)とアイテムのスクレイプの概念について以下の変更 (r2630) :
    • 元のitem_scrapedシグナルが削除されました

    • 元のitem_passedシグナルはitem_scrapedに名前が変更されました

    • 古いログ行の Scraped Item... は削除されました

    • 古いログ行の Passed Item...Scraped Item... に名前変更され、 DEBUG レベルに降格されました

  • Scrapyコードの一部を2つの新しいライブラリに分散させることにより、Scrapyコードベースを削減しました:
    • w3lib ( scrapy.utils.{http,markup,multipart,response,url} からの幾つかの関数がこの中に入りました r2584)

    • scrapely (scrapy.contrib.ibl からこの中に入りました r2586)

  • 未使用関数削除: scrapy.utils.request.request_info() (r2577)

  • examples/googledir からgoogledirプロジェクトを削除しました。 GitHubで利用可能な dirbot と呼ばれる新しいサンプル・プロジェクトがあります: https://github.com/scrapy/dirbot

  • Scrapyアイテムのデフォルト・フィールド値のサポートを削除 (r2616)

  • 実験的な crawlspider v2 を削除 (r2632)

  • アーキテクチャを簡素化するためにスケジューラ・ミドルウェアを削除しました。 重複フィルターは、以前と同じ重複フィルター・クラスを使用して、スケジューラー自体で実行されるようになりました( DUPEFILTER_CLASS 設定) (r2640)

  • scrapy crawl コマンドにURLを渡すためのサポートを削除しました(代わりに scrapy parse を使用してください) (r2704)

  • 非推奨の実行キュー(Execution Queue)を削除 (r2704)

  • 削除された(文書化されていない)(scrapy.contrib.spidercontextからの)スパイダー・コンテキスト拡張 (r2780)

  • CONCURRENT_SPIDERS 設定を削除しました(代わりにscrapyd maxprocを使用してください) (r2789)

  • コア・コンポーネントの属性の名前が変更されました: downloader.sites → downloader.slots、 scraper.sites → scraper.slots (r2717, r2718)

  • 設定の名前を CLOSESPIDER_ITEMPASSED から CLOSESPIDER_ITEMCOUNT に変更しました (r2655) 。下位互換性は維持されます。

Scrapy 0.12

#NNN形式の番号は古い課題トラッカー(issue tracker)(Trac)の参照チケット番号なので、もはや利用できません。

新機能と改善点
  • 渡されたアイテムは、 item_passeditem 引数で送信されるようになりました (#273)

  • バグ・レポートに役立つ scrapy version コマンドにverboseオプションを追加しました (#298)

  • HTTPキャッシュがデフォルトでプロジェクト・データ・ディレクトリに保存されるようになりました (#279)

  • プロジェクト用データ保存ディレクトリ追加 (#276, #277)

  • Scrapyプロジェクトのファイル構成について文書化(コマンドライン・ツール文書参照)

  • XPathセレクター用の新しいlxmlバックエンド (#147)

  • スパイダー毎の設定 (#245)

  • Scrapyコマンドのエラーを通知するための終了コードをサポートします (#248)

  • scrapy shell コマンドに -c 引数を追加した

  • libxml2 をオプションにしました (#260)

  • deploy コマンド (#261)

  • CLOSESPIDER_PAGECOUNT 設定を追加 (#253)

  • CLOSESPIDER_ERRORCOUNT 設定を追加 (#254)

Scrapydの変更
  • Scrapydはスパイダーごとに1つのプロセスを使用するようになりました

  • スパイダーの実行ごとに1つのログファイルを保存し、スパイダーごとに最新の5つのログを保持してローテーションします(デフォルト)

  • 最小限のWebUIが追加され、デフォルトでは http://localhost:6800 が有効です。

  • 現在のプロジェクトのScrapydサーバを起動するために scrapy server コマンドが用意されました

設定の変更
  • HTTPキャッシュミドルウェアを有効にするための HTTPCACHE_ENABLED 設定(デフォルトではFalse)を追加

  • HTTPCACHE_EXPIRATION_SECS セマンティクスを変更しました: ゼロは「期限切れにならない」ことを意味します。

非推奨/廃止された機能
  • Scrapydサーバーを起動する server コマンドを優先して、 runserver コマンドは非推奨になりました。Scrapydの変更も参照して下さい。

  • Scrapyd `` schedule.json`` APIの使用を優先して、queue コマンドが非推奨になりました。Scrapydの変更も参照して下さい。

  • !LxmlItemLoader(メインの投稿に昇格したことのない実験的な投稿)を削除しました

Scrapy 0.10

#NNN形式の番号は古い課題トラッカー(issue tracker)(Trac)の参照チケット番号なので、もはや利用できません。

新機能と改善点
  • Scrapyクローラーを実稼働環境に展開するための scrapyd と呼ばれる新しいScrapyサービス(#218)(ドキュメントあり)

  • 独自の画像パイプラインをサブクラス化する必要がない簡略化された画像パイプラインの使用法 (#217)

  • ScrapyシェルにデフォルトでScrapyログが表示されるようになりました (#206)

  • 共通ベース・コードのリファクタリングされた実行キューと "spider queues" と呼ばれる着脱可能なバックエンド (#220)

  • デフォルトで利用可能な新しい(SQLiteベースの)永続スパイダー・キュー (#198) 。サーバー・モードでScrapyを起動し、スパイダーの実行をスケジュールできます。

  • Scrapyコマンドライン・ツールとそのすべての利用可能なサブ・コマンドの文書を追加(文書が利用可能)

  • 着脱可能なバックエンドを備えたフィード・エクスポーター (#197) (文書が利用可能)

  • 遅延(deferred)シグナル (#193)

  • アイテム・パイプラインに2つの新しいメソッド open_spider() と、 deferredサポート付きの close_spider() を追加しました (#195)

  • スパイダーごとのデフォルトのリクエスト・ヘッダーのオーバーライドのサポート (#181)

  • デフォルトのSpiderManagerを、同様の機能を持つがTwisted Pluginsに依存しないものに置き換えました (#186)

  • 二つのパッケージに分割さDebianパッケージ - ライブラリとサービス (#187)

  • Scrapyログ機能リファクタリング (#188)

  • 異なる実行間で永続的なスパイダー・コンテキストを維持するための新しい拡張機能 (#203)

  • リダイレクトを回避するための dont_redirect request.meta キーを追加 (#233)

  • 再試行を回避するための dont_retry request.metaキーを追加 (#234)

コマンドライン・ツールの変更
  • 古い scrapy-ctl.py を置き換える新しい scrapy コマンド (#199) 。プロジェクト毎に一つの scrapy-ctl.py ではなく、グローバルな scrapy コマンドが1つだけになりました。Windowsからより便利に実行するための scrapy.bat スクリプトを追加しました。

  • コマンドライン・ツールにbash補完を追加 (#210)

  • コマンド startrunserver に名前変更 (#209)

API変更
  • Requestオブジェクトの urlbody 属性は今や読み取り専用です (#230)

  • Request.copy()Request.replace() は、それらの callbackerrback 属性もコピーするようになりました (#231)

  • scrapy.contrib から UrlFilterMiddleware を削除しました(デフォルトでは既に無効になっています)

  • オフサイト・ミドルウェアは、allowed_domains属性を持たないスパイダーからのリクエストを除外しません (#225)

  • Spider Manager の load() メソッドを削除。今やスパイダーは __init__ メソッドそれ自身によってロードされるます。

  • Scrapyマネージャーを変更しました(今や "Crawler" といわれます):
    • scrapy.core.manager.ScrapyManager クラスは scrapy.crawler.Crawler に名前変更しました。

    • scrapy.core.manager.scrapymanager シングルトンは scrapy.project.crawler に移動しました。

  • モジュール移動: scrapy.contrib.spidermanager から scrapy.spidermanager

  • SpiderManager シングルトンが scrapy.spider.spiders から scrapy.project.crawler シングルトンの spiders 属性に移動しました。

  • 統計収集クラス群を移動した: (#204)
    • scrapy.stats.collector.StatsCollector から scrapy.statscol.StatsCollector

    • scrapy.stats.collector.SimpledbStatsCollector から scrapy.contrib.statscol.SimpledbStatsCollector

  • コマンドごとのデフォルト設定が、コマンド・オブジェクト・クラスの default_settings 属性で指定されるようになりました (#201)

  • Itemパイプライン process_item() メソッドの引数を (spider, item) から (item, spider) に変更しました
    • 後方互換性の維持(非推奨警告付き)

  • scrapy.core.signals モジュールを scrapy.signals へ移動した
    • 後方互換性の維持(非推奨警告付き)

  • scrapy.core.exceptions モジュールを scrapy.exceptions へ移動した
    • 後方互換性の維持(非推奨警告付き)

  • BaseSpiderhandles_request() クラス・メソッド追加

  • scrapy.log.exc() 関数を削除 (代わりに scrapy.log.err() を使ってください)

  • scrapy.log.msg() 関数の component 引数を削除

  • scrapy.log.log_level 属性を削除

  • Spider Manager と Item Pipeline Manager に from_settings() クラス・メソッドを追加

設定の変更
  • !HttpCacheMiddlewareの特定のスキームを無視するための HTTPCACHE_IGNORE_SCHEMES 設定を追加 (#225)

  • 使用するスパイダー・キューを定義する SPIDER_QUEUE_CLASS 設定を追加 (#220)

  • KEEP_ALIVE 設定を追加 (#220)

  • SERVICE_QUEUE 設定を削除 (#220)

  • COMMANDS_SETTINGS_MODULE 設定を削除 (#201)

  • REQUEST_HANDLERS の名前を DOWNLOAD_HANDLERS に変更し、(関数の代わりに)ダウンロード・ハンドラー・クラスを作成しました

Scrapy 0.9

#NNN形式の番号は古い課題トラッカー(issue tracker)(Trac)の参照チケット番号なので、もはや利用できません。

新機能と改善点
  • scrapy.mailにSMTP-AUTHサポートを追加。

  • 新設定追加: MAIL_USER, MAIL_PASS (r2065 | #149)

  • 新しいscrapy-ctlviewコマンドを追加 - Scrapyで見られるように、ブラウザーでURLを表示します (r2039)

  • Scrapyプロセスを制御するためのWebサービスが追加されました(これにより、Webコンソールも非推奨になります。 (r2053 | #167)

  • 本番システムの為に、Scrapyをサービスとして実行するためのサポート (r1988, r2054, r2055, r2056, r2057 | #168)

  • ラッパー帰納(wrapper induction)ライブラリを追加しました(文書は現在ソースコードでのみ利用可能です)。 (r2011)

  • 簡素化および改善されたレスポンスのエンコーディングのサポート (r1961, r1969)

  • LOG_ENCODING 設定追加 (r1956, 文書あり)

  • RANDOMIZE_DOWNLOAD_DELAY 設定を追加(デフォルトで有効) (r1923, 文書あり)

  • MailSender はもはや入出力ブロッキングしません (r1955 | #146)

  • Linkextractors と 新しい Crawlspider は今や相対ベースタグURLを処理するようになりました (r1960 | #148)

  • アイテムローダーとプロセッサのいくつかの改善 (r2022, r2023, r2024, r2025, r2026, r2027, r2028, r2029, r2030)

  • telnetコンソールに変数を追加するためのサポートが追加されました (r2047 | #165)

  • コールバックなしのリクエストのサポート (r2050 | #166)

API変更
  • Spider.domain_name から Spider.name へ変更 (SEP-012, r1975)

  • Response.encoding は今やエンコーディングを検知します (r1961)

  • HttpErrorMiddleware は今やNoneを返すか、または例外を引き起こします (r2006 | #157)

  • scrapy.command モジュール群の再配置 (r2035, r2036, r2037)

  • スクラップするためのフィード・スパイダーのための ExecutionQueue を追加 (r2034)

  • ExecutionEngine シングルトンを削除 (r2039)

  • botoとスレッドを使用するために S3ImagesStore (画像パイプライン)を移植しました (r2033)

  • モジュール移動: scrapy.management.telnetscrapy.telnet へ (r2047)

デフォルト設定の変更
  • デフォルトの SCHEDULER_ORDERDFO に変更しました (r1939)

Scrapy 0.8

#NNN形式の番号は古い課題トラッカー(issue tracker)(Trac)の参照チケット番号なので、もはや利用できません。

新機能
  • DEFAULT_RESPONSE_ENCODING 設定追加 (r1809)

  • FormRequest.from_response() メソッドに dont_click 引数追加 (r1813, r1816)

  • FormRequest.from_response() メソッドに clickdata` 引数追加 (r1802, r1803)

  • HTTPプロキシー (HttpProxyMiddleware) サポートの追加 (r1781, r1785)

  • オフサイト・スパイダー・ミドルウェアは、リクエストを除外するときにメッセージをログに記録するようになりました (r1841)

後方互換性のない変更
  • scrapy.utils.response.get_meta_refresh() シグネチャを変更した (r1804)

  • scrapy.item.ScrapedItem class を非推奨削除。代わりに scrapy.item.Item を使って下さい (r1838)

  • scrapy.xpath モジュールを非推奨削除。代わりに scrapy.selector を使って下さい。 (r1836)

  • core.signals.domain_open シグナルを非推奨削除。代わりに core.signals.domain_opened を使って下さい (r1822)

  • log.msg() は今や spider 引数を受け入れます (r1822)
    • 古いドメイン引数は非推奨になり、0.9で削除される予定です。 スパイダーの場合は、常に spider 引数を使用し、スパイダーへの参照を渡す必要があります。 本当に文字列を渡したい場合は、代わりに component 引数を使用してください。

  • コア・シグナル domain_opened, domain_closed, domain_idle を変更した

  • ドメインの代わりにスパイダーを使用するようにアイテム・パイプラインを変更しました
    • process_item() アイテム・パイプライン・メソッドの domain 引数が spider に変更され、新しいシグネチャは次のようになります: process_item(spider, item) (r1827 | #105)

    • (Scrapy 0.8で動作するように)コードをすばやく移植するには、以前に domain を使用していたあなたは、 spider.domain_name を使用するだけです。

  • ドメインの代わりにスパイダーを使用するようにStatsAPIを変更しました (r1849 | #113)
    • StatsCollector は、そのメソッド( set_valueinc_value など)で(ドメインではなく)スパイダーへの参照を受け取るように変更されました。

    • StatsCollector.iter_spider_stats() メソッドを追加

    • StatsCollector.list_domains() メソッドを削除

    • また、Statsシグナルの名前が変更され、(ドメインではなく)スパイダーへの参照を渡すようになりました。 変更の概要は以下のとおりです:

    • (Scrapy 0.8で動作するように)コードをすばやく移植するには、以前に domain を使用していたあなたは spider.domain_name を使用するだけです。 spider_stats には、 domain_stats とまったく同じデータが含まれています。

  • CloseDomain 拡張機能が scrapy.contrib.closespider.CloseSpider に移動しました (r1833)
    • 以下の設定は名前を変更しました:
      • CLOSEDOMAIN_TIMEOUT から CLOSESPIDER_TIMEOUT

      • CLOSEDOMAIN_ITEMCOUNT から CLOSESPIDER_ITEMCOUNT

  • 削除 SCRAPYSETTINGS_MODULE 環境変数を非推奨のため削除。代わりに SCRAPY_SETTINGS_MODULE を使ってください。 (r1840)

  • 名前変更 設定: REQUESTS_PER_DOMAINCONCURRENT_REQUESTS_PER_SPIDER へ (r1830, r1844)

  • 名前変更 設定: CONCURRENT_DOMAINSCONCURRENT_SPIDERS へ (r1830)

  • HTTPキャッシュ・ミドルウェアのリファクタリング

  • HTTPキャッシュミドルウェアは大幅にリファクタリングされましたが、削除されたドメイン・セクター化(sectorization)を除いて同じ機能を保持しています。 (r1843 )

  • 名前変更 例外 DontCloseDomainDontCloseSpider へ (r1859 | #120)

  • 名前変更 エクステンション: DelayedCloseDomainSpiderCloseDelay へ (r1861 | #121)

  • 削除 scrapy.utils.markup.remove_escape_chars 関数を廃止。代わりに scrapy.utils.markup.replace_escape_chars を使ってください (r1865)

Scrapy 0.7

Scrapyの最初のリリース。

Scrapyへの貢献

重要

https://docs.scrapy.org/en/master/contributing.html で、この文書の最新バージョンを読んでいることを再確認してください

Scrapyに貢献する方法はたくさんあります。 それらのいくつかを次に示します:

  • Scrapyについてのブログ。Scrapyの使用方法を世界中に伝えましょう。これは、より多くの例により新規参入者を助け、Scrapyプロジェクトの可視性を高めるのに役立ちます。

  • 以下の「バグの報告」(Reporting bugs)で詳述されているガイドラインに従うようにして、バグを報告し、 issue tracker で機能をリクエストします。

  • 新しい機能やバグ修正のためのパッチを上げてください。パッチの作成方法と送信方法の詳細については、下記の パッチを書く と 「パッチの送信」(Submitting patch) をお読みください。

  • Scrapy subreddit に参加して、Scrapyの改善方法に関するアイデアを共有してください。私たちは常に提案を受け入れています。

  • Stack Overflow でScrapyの質問に答えてください。

バグの報告

注釈

セキュリティの問題は scrapy-security@googlegroups.comにのみ 報告してください。これは信頼できるScrapy開発者のみが利用できるプライベートメーリングリストであり、そのアーカイブは公開されていません。

よく書かれたバグレポートは非常に役立ちます。よって、新しいバグを報告するときは以下のガイドラインに留意してください。

  • 最初に FAQ(よくある質問と回答) をチェックして、よく知られている質問で問題が解決されていないかどうかを確認してください

  • あなたがScrapyの使用に関する一般的な質問がある場合は、 Stack Overflow (scrapy タグ付け) で質問してください。

  • open issues をチェックして、問題がすでに報告されているかどうかを確認します。報告されている場合は、そのレポートを閉じないで、チケットの履歴とコメントを確認してください。追加の有用な情報がある場合は、コメントを残すか、修正を含めて プル・リクエスト を送信することを検討してください。

  • scrapy-users リストと Scrapy subreddit を検索して、そこで議論されているか、表示されているものがバグかどうかわからないかどうかを確認します。 #scrapy IRCチャンネルで質問することもできます。

  • 完全で再現可能な特定のバグレポート を作成します。テストケースが小さければ小さいほど良いです。他の開発者にはバグを再現するプロジェクトがないため、再現に必要なすべての関連ファイルを含めてください。たとえば、問題を示す「最小限の、完全な、検証可能な例」を作成するStackOverflowのガイド(Minimal, Complete, and Verifiable example)を参照してください。

  • 完全で再現可能な例を提供する最も素晴らしい方法は、Scrapyテスト・スイートに失敗したテスト・ケースを追加するプル・リクエストを送信することです( パッチの送信 参照)。これは、自分で問題を解決する意図がない場合でも役立ちます。

  • scrapy version -v の出力を含めると、バグに取り組んでいる開発者は、それが発生したバージョンとプラットフォームを正確に知ることができます。これは、バグを再現したり、すでに修正されているかどうかを知るのに非常に役立ちます。

パッチを書く

パッチが適切に作成されるほど、パッチが受け入れられる可能性が高くなり、マージが早くなります。

適切なパッチは以下のようにすべきです:

  • 特定の変更に必要な最小限のコードが含まれています。小さなパッチは、確認とマージが簡単です。したがって、複数の変更(またはバグ修正)を行っている場合は、変更ごとに1つのパッチを提出することを検討してください。複数の変更を1つのパッチにまとめないでください。大きな変更については、パッチ・キュー(patch queue)の使用を検討してください。

  • すべての単体テストに合格させます。以下の「テストの実行」(Running tests)を参照してください。

  • 修正されたバグまたは追加された新しい機能をチェックする1つ(または複数)のテスト・ケースを含めます。以下の「テストの作成」(Writing tests)を参照してください。

  • パブリック(文書化された)APIを追加または変更する場合は、同じパッチに文書ントの変更を含めてください。以下の「文書ポリシー」(Documentation policies)を参照してください。

  • プライベートAPIを追加する場合は、 docs/conf.py` ``coverage_ignore_pyobjects 変数に正規表現を追加して、ドキュメント・カバレッジ・チェックから新しいプライベートAPIを除外してください。

    あなたのプライベートAPIが適切にスキップされているかどうかを確認するには、次のように文書カバレッジ・レポートを生成します:

    tox -e docs-coverage
    
  • 非推奨のコードを削除する場合は、最初に、非推奨を導入したリリースから少なくとも1年(12か月)が経過していることを確認してください。 非推奨に関するポリシー 参照。

パッチの送信

パッチを送信する最良の方法は、GitHubでプルリクエスト(pull request)を発行することです。オプションで最初に新しい問題を作成します。

修正された機能または新しい機能(それが何であるか、なぜ必要なのかなど)を忘れずに説明してください。含める情報が多いほど、コア開発者がパッチを理解し、受け入れやすくなります。

パッチを作成する前に新しい機能(またはバグ修正)について議論することもできますが、引数を説明し、主題にいくつかの追加の考えを入れたことを示す準備ができているパッチを用意しておくことは常に良いことです。適切な出発点は、GitHubでプル・リクエストを送信することです。それはあなたのアイデアを説明するのに十分単純であり、アイデアが検証され有用であることが証明された後、文書/テストを後で残すことができます。または、 Scrapy subreddit で会話を開始して、最初にアイデアについて話し合うこともできます。

しばしば、解決したい問題に対する既存のプル・リクエストが存在することがありますが、何らかの理由で停止します。多くの場合、プル・リクエストは正しい方向にありますが、変更はScrapyメンテナによってリクエストされ、元のプル・リクエストの作成者にはそれらに対処する時間がありませんでした。この場合、このプルリ・クエストを選択することを検討してください。元のプル・リクエストからのすべてのコミットと、発生した問題に対処するための追加の変更を含む新しいプル・リクエストを開きます。そうすることは非常に役立ちます。元の作者のコミットが認識されるやいなや、彼/彼女のそのコミットを取り込むことは失礼とはみなされません。

既存のプルリクエストをローカル・ブランチにプルするには、 git fetch upstream pull/$PR_NUMBER/head:$BRANCH_NAME_TO_CREATE を実行します(「upstream」をscrapyリポジトリのリモート名に、「$ PR_NUMBER」をプル・リクエストのID、びローカルに作成するブランチの名前を含む $BRANCH_NAME_TO_CREATE )。 https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/checking-out-pull-requests-locally#modifying-an-inactive-pull-request-locally も参照してください。

GitHubプル・リクエストを作成するときは、タイトルを短く、しかし説明的なものにしてください。例えば、バグ #411:"Scrapy hangs if an exception raises in start_requests" の場合 "Fix for #411" より "Fix hanging when exception occurs in start_requests (#411)" が好ましいです。完全なタイトルを使用すると、issue trackerを簡単に確認できます。

最後に、機能的な変更とは別のコミットで、審美的な変更( PEP 8 対応、未使用のインポートの削除など)を維持するようにしてください。これにより、プル・リクエストの確認が容易になり、マージされる可能性が高くなります。

コーディング・スタイル

Scrapyに含めるコードを記述するときは、これらのコーディング規則に従ってください:

  • 特に指定がない限り、 PEP 8 に従ってください。

  • コードの可読性を向上させるためであれば、79文字より長い行を使用しても構いません。

  • 貢献するコードにあなたの名前を入れないでください。gitは、コードの作成者を識別するのに十分なメタ・データを提供します。セットアップ手順については、 https://help.github.com/en/github/using-git/setting-your-username-in-git を参照してください。

文書ポリシー

APIメンバー(クラス、メソッドなど)のリファレンス文書については、docstringsを使用し、Sphinx文書が autodoc 拡張を使用してdocstringを引用することを確認してください。APIリファレンス文書はdocstringの規則( PEP 257 )に準拠し、IDEにフレンドリである必要があります。つまりそれは簡潔な要点と例で書く必要があります。

チュートリアルやトピックなどの他の種類のドキュメントは、 docs/ ディレクトリ内のファイルでカバーする必要があります。これには、APIメンバーに固有の文書が含まれますが、それはAPIリファレンス文書を超える解説内容のものです。

いずれにせよ、docstringで何かが網羅されている場合、 docs/ ディレクトリ内のファイルにdocstringを複製するのではなく、 autodoc 拡張を使用してdocstringを文書に取り込みます。

新機能または変更された機能を対象とする文書の更新では、Sphinxの versionaddedversionchanged ディレクティブを使用する必要があります。 バージョンとして VERSION を使用します。対応するリリースの直前の実際のバージョンに置き換えます。 Scrapyの新しいメジャーバージョンまたはマイナーバージョンをリリースする際、我々はこれらのディレクティブのうち、3年以上経過しているディレクティブを削除します。

非推奨の機能に関する文書は、新しい読者が遭遇しないように削除する必要があります。非推奨への追加と非推奨の削除については、 リリース・ノート に記載されています。

テスト

テストは、 Twisted ユニットテスト フレームワーク を使用して実装されます。 テストを実行するには、 tox が必要です。

テストを実行する

全てのテストを実行するには:

tox

特定のテスト(たとえば tests/test_loader.py)を実行するには、次を使用します:

tox -- tests/test_loader.py

特定の tox 環境でテストを実行するには、 tox.ini からの環境名で -e <name> を使用します。たとえば、Python 3.6でテストを実行するときは次の通りです:

tox -e py36

環境のコンマ区切りリストを指定し、 toxのパラレルモード を使用して、複数の環境でテストを並行して実行することもできます:

tox -e py36,py38 -p auto

コマンドライン・オプションを pytest に渡すには、 tox の呼び出しで -- の後に追加します。 -- を使用すると、 tox.ini で定義されているデフォルトの位置引数がオーバーライドされるため、これらのデフォルトの位置引数( scrapy tests )も -- の後に含める必要があります:

tox -- scrapy tests -x  # stop after first failure

pytest-xdist プラグインを使用することもできます。たとえば、すべてのCPUコアを使用してPython 3.6 tox 環境ですべてのテストを実行するには次のようにします:

tox -e py36 -- scrapy tests -n auto

カバレッジ・レポートを表示するには、 coverage をインストール( pip install coverage )して実行します:

coverage report

htmlまたはxmlレポートなどのオプションについては、 coverage --help の出力を参照してください。

テストを書く

すべての機能(新機能やバグ修正を含む)に期待どおりに動作することを確認するテストケースを含める必要があります。パッチをより早く受け入れてもらいたい場合は、パッチのテストを含めてください。

Scrapyはユニット・テストを使用します。ユニット・テストは tests/ ディレクトリにあります。それらのモジュール名は通常、テストしているモジュールの完全なパスに似ています。たとえば、アイテム・ローダーのコードは次の通りです:

scrapy.loader

そして、それらのユニットテストは以下です:

tests/test_loader.py

バージョン管理とAPIの安定性

バージョン管理

Scrapyのバージョンは3つの数字から成ります。 A.B.C

  • A はメジャーバージョンです。これはめったに変更されず、非常に大きな変更を示します。

  • B はリリース番号です。 これには、下位互換性を損なう可能性がある、機能や事柄を含む多くの変更が含まれますが、これらのケースを最小限に抑えるよう努めています。

  • C はバグ修正リリース番号です。

後方非互換性は リリースノート で明示的に言及してあります。アップグレードする前に特別な注意が必要な場合があります。

開発リリースは3番号のバージョンには従わず、通常、接尾辞付きの dev バージョンとしてリリースされます。例: 1.3dev

注釈

Scrapy 0.* シリーズでは、Scrapyは奇数番号のバージョンは開発リリース(odd-numbered versions for development releases)でしたた。これはScrapy 1.0以降には適用されません。

Scrapy 1.0からは、すべてのリリースは本番環境対応と見なすべきです。

例えば:

  • (製品で使っても安全な) 1.1 シリーズの 1.1.1 は最初のバグ修正リリース

APIの安定性

APIの安定性は、 1.0 リリースの主要な目標の1つでした。

単一のダッシュ( _ )で始まるメソッドまたは関数はプライベートであり、安定版として信頼してはいけません。

また、安定版は完全を意味するものではないことに注意してください。安定版APIは新しいメソッドや機能を拡張できますが、既存のメソッドは依然として同じように機能し続ける必要があります。

非推奨に関するポリシー

非推奨のScrapy機能のサポートは、少なくとも1年間維持することを目指しています。

たとえば、2020年6月15日にリリースされたScrapyバージョンで当該機能が非推奨になった場合、その機能は2021年6月14日以前にリリースされたバージョンでは引き続き機能するべきです。

そして1年後の新しいScrapyリリースは、その非推奨機能のサポートを削除する可能性があります。

Scrapyリリースで削除されたすべての非推奨機能は、 リリース・ノート に明示的に記載されています。

リリース・ノート

直近のScrapyバージョンの変更点をご覧ください。

Scrapyへの貢献

Scrapyプロジェクトに貢献する方法を学びます。

バージョン管理とAPIの安定性

Scrapyのバージョン管理とAPIの安定性を理解します。