Scrapy 1.2 ドキュメント¶
このドキュメントには、Scrapyについて知っておくべきすべてが含まれています。
ヘルプ¶
トラブルですか? 私達が助けます!
- FAQ を試してください – いくつかのよくある質問への答えがあります.
- 具体的な情報をお探しですか? 索引 か モジュール索引 を試してください.
- StackOverflow using the scrapy tag で質問するか, 答えを探してください.
- archives of the scrapy-users mailing list, か post a question で情報を探してください.
- #scrapy IRC channel で質問してください.
- Scrapy のバグは 私達の issue tracker に報告してください.
最初のステップ¶
Scrapy について¶
Scrapyは, Webサイトのクロール, データマイニング, 情報処理, アーカイブなどの幅広い有用なアプリケーションに使用できる構造化データを抽出するためのアプリケーションフレームワークです.
Scrapyはもともと Webスクレイピング 用に設計されていましたが, API( Amazon Associates Web Services のような)または汎用Webクローラーとしてデータを抽出するためにも使用できます.
スパイダーの作成例¶
Scrapy がもたらすものを示すために、Scrapy Spiderの一例を、スパイダーを実行する最も簡単な方法を使って説明します.
ここでは、ページングを追っていきながらウェブサイト 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 {
'text': quote.css('span.text::text').extract_first(),
'author': quote.xpath('span/small/text()').extract_first(),
}
next_page = response.css('li.next a::attr("href")').extract_first()
if next_page is not None:
next_page = response.urljoin(next_page)
yield scrapy.Request(next_page, callback=self.parse)
quotes_spider.py
のような名前をつけ, 上記のコードをテキストファイルに保存し,
runspider
コマンドで実行してください:
scrapy runspider quotes_spider.py -o quotes.json
実行完了後, quotes.json
ファイルに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": "Groucho Marx",
"text": "\u201cOutside of a dog, a book is man's best friend. Inside of a dog it's too dark to read.\u201d"
},
{
"author": "Steve Martin",
"text": "\u201cA day without sunshine is like, you know, night.\u201d"
},
...]
今何が起きたの?¶
scrapy runspider quotes_spider.py
コマンドが実行されると, Scrapyはその内部のSpider定義を探して, クローラ・エンジンを通して実行しました.
クロールが開始されると start_urls
で定義されたURL(この場合はユーモアカテゴリの引用符のURLのみ)にリクエストを行い,
デフォルトのコールバックメソッドである parse
に, Response オブジェクトを引数として渡します.
parse
コールバックの内部では, CSSセレクタを使用して引用要素をループし,
抽出されたテキストと作成者でPythonディクテーションを生成し, 次のページへのリンクを探し, コールバックと同じ
parse
メソッドを使用して次のリクエストをスケジュールします.
ここで、Scrapyの主な利点を1つ: リクエストはスケジュールされ, 非同期に処理されます. つまり, Scrapyはリクエストが処理されるのを待つ必要はなく, その間に別のリクエストを送信したり, 他の処理を行うことができます. これは, リクエストが失敗した場合や, 処理中にエラーが発生した場合でも, 他のリクエストが続行できることを意味します.
これにより、非常に高速なクロールが可能になります(同時に複数の同時要求をフォールトトレラントな方法で送信できます) また, Scrapyを使用すると, いくつかの設定 でクロールの公平性を制御できます. ドメインごとまたはIPごとに並行要求の量を制限し, 自動的にこれらを把握しようとする 自動調整拡張機能を使用する など, 各要求のダウンロード遅延を設定するなどの作業を行うことができます.
注釈
これは フィードのエクスポート を使用してJSONファイルを生成し, エクスポート形式(XMLやCSVなど)やストレージバックエンド (例えば, FTP または Amazon S3) を簡単に変更できます. アイテムパイプライン 作成してアイテムをデータベースに格納することもできます.
他には?¶
YScrapyを使用してウェブサイトからアイテムを抽出して保存する方法を見てきましたが, これはごく表面的なものです. Scrapyは, スクレイピングを簡単かつ効率的にするための多くの強力な機能を提供します:
- 拡張CSSセレクタとXPath式を使用してHTML / XMLソースからデータを 選択して抽出する 組み込みサポート, 正規表現を使用して抽出するヘルパーメソッド.
- CSSやXPath式を試してデータを集める インタラクティブシェルコンソール (IPython対応). スパイダーの作成やデバッグに非常に便利です.
- 複数の形式(JSON、CSV、XML)で フィードのエクスポートを生成 し, 複数のバックエンド(FTP, S3, ローカルファイルシステム)に格納するための組み込みサポート.
- 外国語、非標準、壊れたエンコーディング宣言を処理するための強力なエンコーディングサポートと自動検出.
- 強力な拡張性サポートにより, シグナル と明確に定義されたAPI (ミドルウェア, 拡張機能, そして パイプライン) を使用して独自の機能を作成することができます.
- さまざまな組み込み拡張機能とハンドリング用ミドルウェア:
- cookie と session の操作
- 圧縮, 認証, キャッシングなどのHTTP機能
- user-agent の操作
- robots.txt
- クロールする深度制限
- などなど
- Scrapyプロセス内で動作するPythonコンソールにフックするための Telnet コンソール , クローラのイントロスペクションとデバッグ.
- さらに, サイトマップ やXML / CSVフィードからサイトをクロールするための再利用可能なスパイダー, スクラップしたアイテムに関連付けられた画像を(またはその他のメディア) 自動的にダウンロードするメディアパイプライン, キャッシングDNSリゾルバなど, 他にも機能がたくさんあります!
次は?¶
次のステップは, Scrapy をインストール し, チュートリアルに従って 本格的なScrapyプロジェクトを作成し, コミュニティに参加する 方法を学びます. あなたの興味に感謝!
インストールガイド¶
Scrapy のインストール¶
Scrapy は Python 2.7 と Python 3.3 以上で実行できます (Python 3 がまだサポートされていない Windows を除いて).
Pythonパッケージのインストールに慣れている場合は, PyPIからScrapyとその依存関係をインストールすることができます:
pip install Scrapy
専用のvirtualenv にScrapyをインストールして、システムパッケージとの衝突を避けることを強くお勧めします
詳細およびプラットフォームの詳細については, 以下を参照してください.
知りたいこと¶
crapyは純粋な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パッケージに依存しています. 以下の プラットフォーム固有のガイド を確認してください.
これらの依存関係に関連する問題が発生した場合は, それぞれのインストール手順を参照してください:
仮想環境を使用する(推奨)¶
TL;DR: すべてのプラットフォームで仮想環境内にScrapyをインストールすることをお勧めします.
Pythonパッケージは、グローバル(a.k.aシステム全体)またはユーザスペースにインストールできます。私たちは、Scrapyをシステム全体にインストールすることはお勧めしません.
代わりに、いわゆる “仮想環境” (virtualenv) 内にScrapyをインストールすることをお勧めします.
Virtualenvsを使用すると, 既にインストールされているPythonシステムパッケージと競合することなく(システムツールやスクリプトの一部が壊れる可能性があります),
pip
( sudo
などはありません) でパッケージをインストールできます
仮想環境を使い始めるには, virtualenvのインストール手順 を参照してください. グローバルにインストールするには(グローバルにインストールすると実際に役立ちます), 以下を実行してください:
$ [sudo] pip install virtualenv
`ユーザーガイド`_を確認し virtualenv 環境を作成してください.
注釈
もし Linux または OS X を使用している場合, virtualenvwrapper という virtualenv をかんたんに作成できるツールがあります.
一度 virtualenv を作成すれば, 他の Python パッケージと同様に pip
でインストールすることができます.
(あらかじめインストールする必要のあるPython以外の依存関係は platform-specific guides
を参照してください).
Python virtualenvsはデフォルトでPython 2を使用するように、またはデフォルトでPython 3を使用するように作成できます.
- Python 3で Scrapy をインストールしたい場合は, Python 3 の virtualenv にインストールしてください.
- また, Python 2 で Scrapy をインストールしたい場合は, Python 2 の virtualenv にインストールしてください.
プラットフォーム別インストール手順¶
Windows¶
https://www.python.org/downloads/ から, Python 2.7 をインストールします
Python実行可能ファイルと追加のスクリプトへのパスを含めるには, 環境変数の
PATH
を調整する必要があります.PATH
に Python のディレクトリパスを追加してください:C:\Python27\;C:\Python27\Scripts\;
PATH
PATHを更新するにはコマンドプロンプトを開き, 以下を実行します:c:\python27\python.exe c:\python27\tools\scripts\win_add2path.py
コマンドプロンプトウィンドウを閉じてから再度開いて変更を有効にし, 次のコマンドを実行して Python のバージョンを確認します:
python --version
pywin32 は http://sourceforge.net/projects/pywin32/ からインストールしてください.
環境に合ったアーキテクチャ(win32またはamd64)をダウンロードしてください.
(バージョン 2.7.9 以下の Python が必要な限り) pip で https://pip.pypa.io/en/latest/installing/ からインストールしてください.
pip
が正しくインストールされていることを確認するために, コマンドプロンプトを開き, 以下を実行します:pip --version
この時点でPython 2.7と
pip
パッケージマネージャが動作しているはずです. Scrapyをインストールしましょう:pip install Scrapy
注釈
Python 3はWindowsではサポートされていません. これは、Scrapyのコア要件である Twisted が Windows 上での Python 3 をサポートしていないためです.
Ubuntu 12.04 以上¶
Scrapyは現在, lxml, twisted, pyOpenSSLの最近の十分なバージョンでテストされており, 最近のUbuntuディストリビューションと互換性があります. しかし, Ubuntuの以前のバージョンもサポートしてはいますが, Ubuntu 12.04 のように, TLS接続の潜在的な問題があります.
注釈
Ubuntuで提供されている python-scrapy
パッケージは使用しないでください. 更新が遅く, 最新の Scrapy に追いつくのが遅くなります.
Ubuntu(またはUbuntuベース)システムにscrapyをインストールするには, これらの依存関係をインストールする必要があります:
sudo apt-get install python-dev python-pip libxml2-dev libxslt1-dev zlib1g-dev libffi-dev libssl-dev
python-dev
,zlib1g-dev
,libxml2-dev
とlibxslt1-dev
はlxml
に必要です.libssl-dev
とlibffi-dev
はcryptography
に必要です.
Python 3 に Scrapy をインストールする場合は, Python 3 開発ヘッダーも必要です:
sudo apt-get install python3 python3-dev
これらをインストールした後に, virtualenv の中で,
pip
で Scrapy をインストールすることができます:
pip install scrapy
注釈
同じ non-python 依存関係を使って Debian Wheezy(7.0)以上で Scrapy をインストールすることができます.
Mac OS X¶
Scrapy の依存関係をビルドするのには、Cコンパイラと開発ヘッダーが必要です. OS X では, これらは通常, Apple の Xcode 開発ツールによって提供されます. Xcode コマンドラインツールをインストールするには, ターミナルウィンドウを開き, 以下を実行します:
xcode-select --install
pip
がシステムパッケージを更新しない 既知の問題 があります.
Scrapy とその依存関係を正常にインストールするために, この問題に対処する必要があります.
これに対するいくつかの解決策があります:
(推奨) システムの Python を 使用しないでください . システムの残りの部分と競合しない新しいバージョンをインストールしてください. homebrew のパッケージマネージャを使ってインストールを行う方法は次のとおりです:
http://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をインストールする.
この方法は, 上記の OS X の問題の回避策ですが, 依存関係を管理するための全体的な良い方法であり, 最初の方法を補完することができます.
virtualenv は Python で仮想環境を作成するために使用できるツールです. 開始するには http://docs.python-guide.org/en/latest/dev/virtualenvs/ のようなマニュアルを読むことをオススメします.
これらの回避策のいずれかを実行すると, Scrapy をインストールすることができます:
pip install Scrapy
Anaconda¶
Anacondaを使用することは、virtualenvを使用して pip
でインストールする代わりの方法です.
注釈
Windowsユーザーの場合、または pip
でインストールする際に問題が発生した場合は, この方法で Scrapy をインストールすることをお勧めします.
もし, Anaconda または Miniconda がすでにインストールされている場合, conda-forge コミュニティには Linux, Windows そして OS X のための最新パッケージが有ります.
conda
を用いてインストールするには, 以下を実行してください:
conda install -c conda-forge scrapy
Scrapy チュートリアル¶
このチュートリアルでは, Scrapyが既にシステムにインストールされていると仮定します. もしまだインストールしていない場合は, インストールガイド を参照してください.
ここでは, 有名な著者からの引用を掲載しているウェブサイト quotes.toscrape.com からデータを集めてきます.
このチュートリアルでは, これらのタスクについて説明します:
- 新しい Scrapy を作成する.
- サイトをクロールし, データを集めるための スパイダー を作成する.
- コマンドラインを使用してスクラップしたデータをエクスポートする.
- 再帰的にリンクをたどるためにスパイダーを更新する.
- スパイダーの引数を使用する
Scrapy は Python で書かれています. 言語に慣れていない場合は, 言語がどのようなものかを知ることで, Scrapyを最大限に活用することができるかもしれません.
でに他の言語に精通していて, Pythonを素早く学びたい場合は Dive Into Python 3 を読むことをお勧めします. あるいは, Python Tutorial を読むのもおすすめです.
あなたがプログラミングに慣れていなくてもPythonを使いたいのであれば, オンラインの本 Learn Python The Hard Way が役立ちます. また, 非プログラマーのためのこのPythonリソースのリスト も役立ちます.
プロジェクトの作成¶
スクレイピングを開始する前に, 新しい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
pipelines.py # project pipelines file
settings.py # project settings file
spiders/ # a directory where you'll later put your spiders
__init__.py
最初のスパイダー¶
Spiders are classes that you define and that Scrapy uses to scrape information
from a website (or a group of websites). They must subclass
scrapy.Spider
and define the initial requests to make, optionally how
to follow links in the pages, and how to parse the downloaded page content to
extract data.
This is the code for our first Spider. Save it in a file named
quotes_spider.py
under the tutorial/spiders
directory in your project:
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 = 'quotes-%s.html' % page
with open(filename, 'wb') as f:
f.write(response.body)
self.log('Saved file %s' % filename)
As you can see, our Spider subclasses scrapy.Spider
and defines some attributes and methods:
name
: identifies the Spider. It must be unique within a project, that is, you can’t set the same name for different Spiders.start_requests()
: must return an iterable of Requests (you can return a list of requests or write a generator function) which the Spider will begin to crawl from. Subsequent requests will be generated successively from these initial requests.parse()
: a method that will be called to handle the response downloaded for each of the requests made. The response parameter is an instance ofTextResponse
that holds the page content and has further helpful methods to handle it.The
parse()
method usually parses the response, extracting the scraped data as dicts and also finding new URLs to follow and creating new requests (Request
) from them.
スパイダーの実行方法¶
To put our spider to work, go to the project’s top level directory and run:
scrapy crawl quotes
This command runs the spider with name quotes
that we’ve just added, that
will send some requests for the quotes.toscrape.com
domain. You will get an output
similar to this:
... (omitted for brevity)
2016-09-20 14:48:00 [scrapy] INFO: Spider opened
2016-09-20 14:48:00 [scrapy] INFO: Crawled 0 pages (at 0 pages/min), scraped 0 items (at 0 items/min)
2016-09-20 14:48:00 [scrapy] DEBUG: Telnet console listening on 127.0.0.1:6023
2016-09-20 14:48:00 [scrapy] DEBUG: Crawled (404) <GET http://quotes.toscrape.com/robots.txt> (referer: None)
2016-09-20 14:48:00 [scrapy] DEBUG: Crawled (200) <GET http://quotes.toscrape.com/page/1/> (referer: None)
2016-09-20 14:48:01 [quotes] DEBUG: Saved file quotes-1.html
2016-09-20 14:48:01 [scrapy] DEBUG: Crawled (200) <GET http://quotes.toscrape.com/page/2/> (referer: None)
2016-09-20 14:48:01 [quotes] DEBUG: Saved file quotes-2.html
2016-09-20 14:48:01 [scrapy] INFO: Closing spider (finished)
...
Now, check the files in the current directory. You should notice that two new
files have been created: quotes-1.html and quotes-2.html, with the content
for the respective URLs, as our parse
method instructs.
注釈
If you are wondering why we haven’t parsed the HTML yet, hold on, we will cover that soon.
何が起こったのですか?¶
Scrapy schedules the scrapy.Request
objects
returned by the start_requests
method of the Spider. Upon receiving a
response for each one, it instantiates Response
objects
and calls the callback method associated with the request (in this case, the
parse
method) passing the response as argument.
start_requests メソッドを省略する¶
Instead of implementing a start_requests()
method
that generates scrapy.Request
objects from URLs,
you can just define a start_urls
class attribute
with a list of URLs. This list will then be used by the default implementation
of start_requests()
to create the initial requests
for your spider:
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 = 'quotes-%s.html' % page
with open(filename, 'wb') as f:
f.write(response.body)
The parse()
method will be called to handle each
of the requests for those URLs, even though we haven’t explicitly told Scrapy
to do so. This happens because parse()
is Scrapy’s
default callback method, which is called for requests without an explicitly
assigned callback.
データの抽出¶
The best way to learn how to extract data with Scrapy is trying selectors using the shell Scrapy shell. Run:
scrapy shell 'http://quotes.toscrape.com/page/1/'
注釈
Remember to always enclose urls in quotes when running Scrapy shell from
command-line, otherwise urls containing arguments (ie. &
character)
will not work.
On Windows, use double quotes instead:
scrapy shell "http://quotes.toscrape.com/page/1/"
You will see something like:
[ ... Scrapy log here ... ]
2016-09-19 12:09:27 [scrapy] 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
>>>
Using the shell, you can try selecting elements using CSS with the response object:
>>> response.css('title')
[<Selector xpath='descendant-or-self::title' data='<title>Quotes to Scrape</title>'>]
The result of running response.css('title')
is a list-like object called
SelectorList
, which represents a list of
Selector
objects that wrap around XML/HTML elements
and allow you to run further queries to fine-grain the selection or extract the
data.
To extract the text from the title above, you can do:
>>> response.css('title::text').extract()
['Quotes to Scrape']
There are two things to note here: one is that we’ve added ::text
to the
CSS query, to mean we want to select only the text elements directly inside
<title>
element. If we don’t specify ::text
, we’d get the full title
element, including its tags:
>>> response.css('title').extract()
['<title>Quotes to Scrape</title>']
The other thing is that the result of calling .extract()
is a list, because
we’re dealing with an instance of SelectorList
. When
you know you just want the first result, as in this case, you can do:
>>> response.css('title::text').extract_first()
'Quotes to Scrape'
As an alternative, you could’ve written:
>>> response.css('title::text')[0].extract()
'Quotes to Scrape'
However, using .extract_first()
avoids an IndexError
and returns
None
when it doesn’t find any element matching the selection.
There’s a lesson here: for most scraping code, you want it to be resilient to errors due to things not being found on a page, so that even if some parts fail to be scraped, you can at least get some data.
Besides the extract()
and
extract_first()
methods, you can also use
the re()
method to extract using regular
expressions:
>>> 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']
In order to find the proper CSS selectors to use, you might find useful opening
the response page from the shell in your web browser using view(response)
.
You can use your browser developer tools or extensions like Firebug (see
sections about スクレイピングにFirebugを使用する and スクレイピングにFireFoxを使用する).
Selector Gadget is also a nice tool to quickly find CSS selector for visually selected elements, which works in many browsers.
XPath: かんたんな紹介¶
Besides CSS, Scrapy selectors also support using XPath expressions:
>>> response.xpath('//title')
[<Selector xpath='//title' data='<title>Quotes to Scrape</title>'>]
>>> response.xpath('//title/text()').extract_first()
'Quotes to Scrape'
XPath expressions are very powerful, and are the foundation of Scrapy Selectors. In fact, CSS selectors are converted to XPath under-the-hood. You can see that if you read closely the text representation of the selector objects in the shell.
While perhaps not as popular as CSS selectors, XPath expressions offer more power because besides navigating the structure, it can also look at the content. Using XPath, you’re able to select things like: select the link that contains the text “Next Page”. This makes XPath very fitting to the task of scraping, and we encourage you to learn XPath even if you already know how to construct CSS selectors, it will make scraping much easier.
We won’t cover much of XPath here, but you can read more about using XPath with Scrapy Selectors here. To learn more about XPath, we recommend this tutorial to learn XPath through examples, and this tutorial to learn “how to think in XPath”.
引用と著者の抽出¶
Now that you know a bit about selection and extraction, let’s complete our spider by writing the code to extract the quotes from the web page.
Each quote in http://quotes.toscrape.com is represented by HTML elements that look like this:
<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>
Let’s open up scrapy shell and play a bit to find out how to extract the data we want:
$ scrapy shell 'http://quotes.toscrape.com'
We get a list of selectors for the quote HTML elements with:
>>> response.css("div.quote")
Each of the selectors returned by the query above allows us to run further queries over their sub-elements. Let’s assign the first selector to a variable, so that we can run our CSS selectors directly on a particular quote:
>>> quote = response.css("div.quote")[0]
Now, let’s extract title
, author
and the tags
from that quote
using the quote
object we just created:
>>> title = quote.css("span.text::text").extract_first()
>>> title
'“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").extract_first()
>>> author
'Albert Einstein'
Given that the tags are a list of strings, we can use the .extract()
method
to get all of them:
>>> tags = quote.css("div.tags a.tag::text").extract()
>>> tags
['change', 'deep-thoughts', 'thinking', 'world']
Having figured out how to extract each bit, we can now iterate over all the quotes elements and put them together into a Python dictionary:
>>> for quote in response.css("div.quote"):
... text = quote.css("span.text::text").extract_first()
... author = quote.css("small.author::text").extract_first()
... tags = quote.css("div.tags a.tag::text").extract()
... print(dict(text=text, author=author, tags=tags))
{'tags': ['change', 'deep-thoughts', 'thinking', 'world'], 'author': 'Albert Einstein', 'text': '“The world as we have created it is a process of our thinking. It cannot be changed without changing our thinking.”'}
{'tags': ['abilities', 'choices'], 'author': 'J.K. Rowling', 'text': '“It is our choices, Harry, that show what we truly are, far more than our abilities.”'}
... a few more of these, omitted for brevity
>>>
スパイダーのデータを抽出する¶
Let’s get back to our spider. Until now, it doesn’t extract any data in particular, just saves the whole HTML page to a local file. Let’s integrate the extraction logic above into our spider.
A Scrapy spider typically generates many dictionaries containing the data
extracted from the page. To do that, we use the yield
Python keyword
in the callback, as you can see below:
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').extract_first(),
'author': quote.css('span small::text').extract_first(),
'tags': quote.css('div.tags a.tag::text').extract(),
}
If you run this spider, it will output the extracted data with the log:
2016-09-19 18:57:19 [scrapy] 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] 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.”"}
スクレイピングしたデータの保存¶
The simplest way to store the scraped data is by using Feed exports, with the following command:
scrapy crawl quotes -o quotes.json
That will generate an quotes.json
file containing all scraped items,
serialized in JSON.
For historic reasons, Scrapy appends to a given file instead of overwriting its contents. If you run this command twice without removing the file before the second time, you’ll end up with a broken JSON file.
You can also used other formats, like JSON Lines:
scrapy crawl quotes -o quotes.jl
The JSON Lines format is useful because it’s stream-like, you can easily append new records to it. It doesn’t have the same problem of JSON when you run twice. Also, as each record is a separate line, you can process big files without having to fit everything in memory, there are tools like JQ to help doing that at the command-line.
In small projects (like the one in this tutorial), that should be enough.
However, if you want to perform more complex things with the scraped items, you
can write an Item Pipeline. A placeholder file
for Item Pipelines has been set up for you when the project is created, in
tutorial/pipelines.py
. Though you don’t need to implement any item
pipelines if you just want to store the scraped items.
リンクを追う¶
Let’s say, instead of just scraping the stuff from the first two pages from http://quotes.toscrape.com, you want quotes from all the pages in the website.
Now that you know how to extract data from pages, let’s see how to follow links from them.
First thing is to extract the link to the page we want to follow. Examining our page, we can see there is a link to the next page with the following markup:
<ul class="pager">
<li class="next">
<a href="/page/2/">Next <span aria-hidden="true">→</span></a>
</li>
</ul>
We can try extracting it in the shell:
>>> response.css('li.next a').extract_first()
'<a href="/page/2/">Next <span aria-hidden="true">→</span></a>'
This gets the anchor element, but we want the attribute href
. For that,
Scrapy supports a CSS extension that let’s you select the attribute contents,
like this:
>>> response.css('li.next a::attr(href)').extract_first()
'/page/2/'
Let’s see now our spider modified to recursively follow the link to the next page, extracting data from it:
import scrapy
class QuotesSpider(scrapy.Spider):
name = "quotes"
start_urls = [
'http://quotes.toscrape.com/page/1/',
]
def parse(self, response):
for quote in response.css('div.quote'):
yield {
'text': quote.css('span.text::text').extract_first(),
'author': quote.css('span small::text').extract_first(),
'tags': quote.css('div.tags a.tag::text').extract(),
}
next_page = response.css('li.next a::attr(href)').extract_first()
if next_page is not None:
next_page = response.urljoin(next_page)
yield scrapy.Request(next_page, callback=self.parse)
Now, after extracting the data, the parse()
method looks for the link to
the next page, builds a full absolute URL using the
urljoin()
method (since the links can be
relative) and yields a new request to the next page, registering itself as
callback to handle the data extraction for the next page and to keep the
crawling going through all the pages.
What you see here is Scrapy’s mechanism of following links: when you yield a Request in a callback method, Scrapy will schedule that request to be sent and register a callback method to be executed when that request finishes.
Using this, you can build complex crawlers that follow links according to rules you define, and extract different kinds of data depending on the page it’s visiting.
In our example, it creates a sort of loop, following all the links to the next page until it doesn’t find one – handy for crawling blogs, forums and other sites with pagination.
より多くの例とパターン¶
ここにコールバックを明示し, リンクをたどる別のスパイダーがあります. 今回は, 著者情報を集めます:
import scrapy
class AuthorSpider(scrapy.Spider):
name = 'author'
start_urls = ['http://quotes.toscrape.com/']
def parse(self, response):
# follow links to author pages
for href in response.css('.author+a::attr(href)').extract():
yield scrapy.Request(response.urljoin(href),
callback=self.parse_author)
# follow pagination links
next_page = response.css('li.next a::attr(href)').extract_first()
if next_page is not None:
next_page = response.urljoin(next_page)
yield scrapy.Request(next_page, callback=self.parse)
def parse_author(self, response):
def extract_with_css(query):
return response.css(query).extract_first().strip()
yield {
'name': extract_with_css('h3.author-title::text'),
'birthdate': extract_with_css('.author-born-date::text'),
'bio': extract_with_css('.author-description::text'),
}
This spider will start from the main page, it will follow all the links to the
authors pages calling the parse_author
callback for each of them, and also
the pagination links with the parse
callback as we saw before.
The parse_author
callback defines a helper function to extract and cleanup the
data from a CSS query and yields the Python dict with the author data.
Another interesting thing this spider demonstrates is that, even if there are
many quotes from the same author, we don’t need to worry about visiting the
same author page multiple times. By default, Scrapy filters out duplicated
requests to URLs already visited, avoiding the problem of hitting servers too
much because of a programming mistake. This can be configured by the setting
DUPEFILTER_CLASS
.
Hopefully by now you have a good understanding of how to use the mechanism of following links and callbacks with Scrapy.
As yet another example spider that leverages the mechanism of following links,
check out the CrawlSpider
class for a generic
spider that implements a small rules engine that you can use to write your
crawlers on top of it.
Also, a common pattern is to build an item with data from more than one page, using a trick to pass additional data to the callbacks.
スパイダー引数の使用¶
You can provide command line arguments to your spiders by using the -a
option when running them:
scrapy crawl quotes -o quotes-humor.json -a tag=humor
These arguments are passed to the Spider’s __init__
method and become
spider attributes by default.
In this example, the value provided for the tag
argument will be available
via self.tag
. You can use this to make your spider fetch only quotes
with a specific tag, building the URL based on the argument:
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').extract_first(),
'author': quote.css('span small a::text').extract_first(),
}
next_page = response.css('li.next a::attr(href)').extract_first()
if next_page is not None:
next_page = response.urljoin(next_page)
yield scrapy.Request(next_page, self.parse)
If you pass the tag=humor
argument to this spider, you’ll notice that it
will only visit URLs from the humor
tag, such as
http://quotes.toscrape.com/tag/humor
.
次のステップ¶
This tutorial covered only the basics of Scrapy, but there’s a lot of other features not mentioned here. Check the 他には? section in Scrapy について chapter for a quick overview of the most important ones.
You can continue from the section 基本概念 to know more about the command-line tool, spiders, selectors and other things the tutorial hasn’t covered like modeling the scraped data. If you prefer to play with an example project, check the 例 section.
例¶
学習する最善の方法は例を真似ることであり、Scrapyも例外ではありません. この理由から, quotesbot という名前のScrapyプロジェクトの例があります. こののプロジェクトを使用して、Scrapyについての詳細を学び、学ぶことができます. http://quotes.toscrape.com には2つのスパイダーがあり, 1つはCSSセレクターを使用し, もう1つはXPath式を使用します.
quotesbot プロジェクトは: https://github.com/scrapy/quotesbot で入手できます. 詳細はプロジェクトのREADMEにあります.
gitに精通している場合は, コードをチェックアウトすることができます. それ以外の場合は, ここ をクリックしてzipファイルとしてプロジェクトをダウンロードできます.
- Scrapy について
- Scrapy がどのようにしてあなたを手助けするかを理解する.
- インストールガイド
- コンピューターに Scraoy をインストールする方法.
- Scrapy チュートリアル
- 最初の Scrapy プロジェクトを作成する.
- 例
- あらかじめ作成された Scrapy プロジェクトで遊ぶことでさらに学ぶ.
基本概念¶
コマンドラインツール¶
バージョン 0.10 で追加.
ここでは, 「コマンド」または「Scrapyコマンド」と呼ばれるサブコマンドと区別するために, 「Scrapy ツール」と呼ばれる scrapy
コマンドラインツールを使用して Scrapy を制御します.
Scrapyツールは, 複数の目的で複数のコマンドを提供し, それぞれが異なる引数とオプションのセットを受け入れます.
( scrapy deploy
コマンドは 1.0 で廃止され, scrapyd-deploy
が採用されました. Deploying your project を参照してください.)
環境設定¶
Scrapy は標準的な以下の場所から scrapy.cfg
ファイルの設定パラメータを探します:
/etc/scrapy.cfg
またはc:\scrapy\scrapy.cfg
(system-wide),- グローバルセッティングのための
~/.config/scrapy.cfg
($XDG_CONFIG_HOME
) と~/.scrapy.cfg
($HOME
) (user-wide), - プロジェクトルート内にある
scrapy.cfg
(次のセクションを参照してください).
これらのファイルからの設定は, 表示された優先順位でマージされます. ユーザ定義の値はシステム全体のデフォルトよりも優先され, プロジェクト全体の設定は定義されている場合は他のすべての設定を上書きします.
また, Scrapy はいくつかの環境変数を理解し, 設定することができます. 現在, 以下のものが存在します:
SCRAPY_SETTINGS_MODULE
( 設定を指定する を参照してください)SCRAPY_PROJECT
SCRAPY_PYTHON_SHELL
( Scrapy シェル を参照してください)
Scrapyプロジェクトのデフォルト構造¶
コマンドラインツールとそのサブコマンドについて解説する前に, まずScrapyプロジェクトのディレクトリ構造について理解しておきましょう.
変更することはできますが, すべての Scrapy プロジェクトはデフォルトで同じファイル構造, もしくはこれに似た構造になっています:
scrapy.cfg
myproject/
__init__.py
items.py
pipelines.py
settings.py
spiders/
__init__.py
spider1.py
spider2.py
...
scrapy.cfg
ファイルが存在するディレクトリは,
プロジェクトルートディレクトリ と呼ばれます.
このファイルには、プロジェクト設定を定義するpythonモジュールの名前が含まれています。次に例を示します:
[settings]
default = myproject.settings
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_dir
は myproject
と同じになります.
次に, 新しいプロジェクトディレクトリ中に移動します:
cd project_dir
これで, scrapy
コマンドを使用してそこからプロジェクトを管理および制御する準備が整いました.
プロジェクトの制御¶
プロジェクトの中から scrapy
ツールを使用して, プロジェクトを制御および管理します.
例えば, 新しいスパイダーを作成するには:
scrapy genspider mydomain mydomain.com
一部のScrapyコマンド ( crawl
など) は, Scrapyプロジェクト内から実行する必要があります.
どのコマンドをプロジェクト内から実行する必要があるかについての詳細は,
以下の コマンドリファレンス を参照してください.
また、いくつかのコマンドは、プロジェクトの中から実行する際に, 少し違う振る舞いをすることがあります.
たとえば、フェッチされたURLが特定のスパイダーに関連付けられている場合,
fetch
コマンドは spider-overridden ビヘイビア(user-agent
属性を上書きする user_agent など)を使用します.
fetch
コマンドは, スパイダーがページをどのようにダウンロードしているかを確認するために使用されるため, 意図的に行っています.
利用可能なコマンド¶
このセクションでは, 使用可能な組み込みコマンドのリストと, 使用例を示します. それぞれのコマンドについての詳細は, 以下のコマンドでいつでも確認できます:
scrapy <command> -h
または, 使用可能なすべてのコマンドは, 以下で確認できます:
scrapy -h
コマンドは, アクティブなScrapyプロジェクトなしでのみ動作するコマンド(グローバルコマンド)と, プロジェクト内から実行するコマンドの動作が若干異なる場合があります(プロジェクトオーバーライド設定を使用するため).
グローバルコマンド:
プロジェクト下でのみ使用可能なコマンド:
startproject¶
- シンタックス:
scrapy startproject <project_name> [project_dir]
- プロジェクトに必要か: no
project_dir
ディレクトリ下に project_name
という名前の新しい Scrapy プロジェクトを作成します.
もし, project_dir
が指定されていない場合, プロジェクト名と同じ名前の project_dir
が作成されます.
使用例:
$ scrapy startproject myproject
genspider¶
- シンタックス:
scrapy genspider [-t template] <name> <domain>
- プロジェクトに必要か: no
プロジェクト内から呼び出された場合は, 現在のフォルダまたは現在のプロジェクトの``spiders`` フォルダに新しいスパイダーを作成します.
<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>
- プロジェクトに必要か: yes
スパイダーを使用してクロールを始める.
使用例:
$ scrapy crawl myspider
[ ... myspider starts crawling ... ]
check¶
- シンタックス:
scrapy check [-l] <spider>
- プロジェクトに必要か: yes
コントラクトチェックを実行する.
使用例:
$ 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
- プロジェクトに必要か: yes
現在のプロジェクトで使用可能なすべてのスパイダーを一覧表示します. 出力は, 1行に1つのスパイダーです.
使用例:
$ scrapy list
spider1
spider2
edit¶
- シンタックス:
scrapy edit <spider>
- プロジェクトに必要か: yes
EDITOR
設定で定義されたエディタを使用して, 指定されたスパイダーを編集します.
このコマンドは, 便利なショートカットとしてのみ提供されています. 開発者はもちろん, ツールやIDEを自由に選択して, スパイダーを作成・デバッグできます.
使用例:
$ scrapy edit spider1
fetch¶
- シンタックス:
scrapy fetch <url>
- プロジェクトに必要か: no
Scrapy ダウンローダーを使用してURLからダウンロードし, その内容を標準出力に書き出します.
このコマンドの興味深い点は, スパイダーがどのようにダウンロードするかをページから取得することです. たとえば, スパイダーがUser Agentを上書きする USER_AGENT
属性を持っている場合は, それを使用します.
このコマンドは, あなたのスパイダーが特定のページをどのようにフェッチするかを “見る” ために使うことができます.
プロジェクトの外で使用される場合は, スパイダーごとの特定の動作は適用されず, デフォルトのScrapyダウンローダ設定を使用します.
使用例:
$ 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>
- プロジェクトに必要か: no
Scrapyスパイダーがそれを “見る” ようにブラウザでURLを開きます. スパイダーは通常のユーザーとは違うページを表示することがあるので, スパイダーが何を見ているかを確認し, 期待通りのものかどうかを確認することができます.
使用例:
$ scrapy view http://www.example.com/some/page.html
[ ... browser starts ... ]
shell¶
- シンタックス:
scrapy shell [url]
- プロジェクトに必要か: no
指定されたURL(指定されている場合)またはURLが指定されていない場合は空のScrapyシェルを開始します.
また, UNIX形式のローカルファイルパスをサポートしています.
./
または ../
を接頭辞とした相対パス, もしくは絶対パスです.
詳細については, Scrapy シェル を参照してください.
使用例:
$ scrapy shell http://www.example.com/some/page.html
[ ... scrapy shell starts ... ]
parse¶
- シンタックス:
scrapy parse <url> [options]
- プロジェクトに必要か: yes
指定されたURLを取得し、それをスパイダーで処理・解析します. --callback
オプションで渡されたメソッドを使用します. 指定されていない場合は parse
メソッドを使用します.
サポートされているオプション:
--spider=SPIDER
: スパイダーの自動検出をバイパスし, 特定のスパイダーを強制的に使用する--a NAME=VALUE
: スパイダー引数を設定する(繰り返してもよい)--callback
または-c
: レスポンスを解析するためのコールバックとして使用するspiderメソッド--pipelines
: パイプラインを通じてアイテムを処理する--rules
または-r
:CrawlSpider
のルールを使用して, レスポンスの解析に使用するコールバック (i.e. spider メソッド) を検出する--noitems
: スクレイピングしたアイテムを表示しない--nolinks
: 抽出されたリンクを表示しない--nocolour
: 出力の色分けを行わない--depth
または-d
: 要求を再帰的に追跡する深さレベル(デフォルト:1)--verbose
または-v
: 各深度レベルの情報を表示する
使用例:
$ scrapy parse http://www.example.com/ -c parse_item
[ ... scrapy log lines crawling example.com spider ... ]
>>> STATUS DEPTH LEVEL 1 <<<
# Scraped Items ------------------------------------------------------------
[{'name': u'Example item',
'category': u'Furniture',
'length': u'12 cm'}]
# Requests -----------------------------------------------------------------
[]
settings¶
- シンタックス:
scrapy settings [options]
- プロジェクトに必要か: no
Scrapy設定の値を取得します.
プロジェクト内で使用されている場合はプロジェクト設定値が表示され, そうでない場合はその設定のデフォルトのScrapy値が表示されます.
使用例:
$ scrapy settings --get BOT_NAME
scrapybot
$ scrapy settings --get DOWNLOAD_DELAY
0
runspider¶
- シンタックス:
scrapy runspider <spider_file.py>
- プロジェクトに必要か: no
プロジェクトを作成せずに, Pythonファイルに含まれているスパイダーを実行します.
使用例:
$ scrapy runspider myspider.py
[ ... spider starts crawling ... ]
version¶
- シンタックス:
scrapy version [-v]
- プロジェクトに必要か: no
Scrapy のバージョンを表示します. -v
と一緒に使用すると, バグレポートに便利な Python, Twisted, そしてプラットフォームの情報も表示されます.
カスタムプロジェクトコマンド¶
COMMANDS_MODULE
設定を使用してカスタムプロジェクトコマンドを追加することができます.
コマンドの実装方法の例については, scrapy/コマンド の Scrapy コマンドを参照してください.
COMMANDS_MODULE¶
初期値: ''
(空文字列)
カスタムのScrapyコマンドを検索するためのモジュール. これは Scrapy プロジェクトのカスタムコマンドを追加するために使用されます.
例:
COMMANDS_MODULE = 'mybot.commands'
setup.pyエントリポイントを介してコマンドを登録する¶
注釈
これは実験的な機能なので注意してください.
scrapy.commands
ファイルのエントリポイントに, setup.py
セクションを追加することで, 外部ライブラリから Scrapy コマンドを追加することもできます.
次の例では, my_command
コマンドを追加しています:
from setuptools import setup, find_packages
setup(name='scrapy-mymodule',
entry_points={
'scrapy.commands': [
'my_command=my_scrapy_module.commands:MyCommand',
],
},
)
スパイダー¶
パイダーとは, クロールの実行方法(リンクをたどる方法)やページから構造化データを抽出する方法(アイテムのスクレイピングなど)を含む, 特定のサイト(またはサイトのグループ)のスクレイピング方法を定義するクラスです. 言い換えれば, スパイダー は, 特定のサイト(場合によってはサイトのグループ)のページをクロールして 解析するためのカスタム動作を定義する場所です.
スパイダーの場合, スクレイピングのライフサイクルは以下のようになります:
最初のURLをクロールする最初のリクエストを生成し, それらのリクエストからダウンロードされたレスポンスで呼び出されるコールバック関数を指定します.
実行する最初のリクエストは,
start_requests()
メソッドを呼び出すことによって取得されます. このメソッドは, デフォルトでstart_urls
で指定されたURLとRequest
のコールバック関数として呼ばれるparse
メソッドで,Request
を生成します.コールバック関数では, レスポンス(Webページ)を解析し, 抽出されたデータ,
Item
オブジェクト,Request
オブジェクト, またはこれらのオブジェクトの反復可能なものを返します これらのリクエストには, コールバックが含まれ, Scrapyによってダウンロードされ, その後指定されたコールバックによってリクエストが処理されます.コールバック関数では, セレクタ を使用してページの内容を解析します(ただし, BeautifulSoup, lxmlなどの任意のメカニズムを使用することもできます).
最後に, スパイダーから返されたアイテムは, 通常, データベース(一部の アイテムパイプライン 内)に永続化されるか, または フィードのエクスポート を使用してファイルに書き込まれます.
このサイクルはどんな種類のスパイダーにも(多かれ少なかれ)適用されますが, さまざまな種類のデフォルトのスパイダーが Scrapy にバンドルされています. これらのタイプについてはここで説明します.
scrapy.Spider¶
-
class
scrapy.spiders.
Spider
¶ これは最もシンプルなスパイダーで, 他のすべてのスパイダーが継承しなければならないものです(Scrapyにバンドルされたスパイダー, あなた自身で作成したスパイダーを含む). 特別な機能は提供しません.
start_urls
属性からリクエストを送信し, スパイダーのparse
メソッドを, レスポンス結果ごとに呼び出すstart_requests()
メソッドの実装を提供するだけです.-
name
¶ スパイダーの名前を定義する文字列. 名前は, スパイダーが Scrapy によってどのように配置(インスタンス化)されているか判別するために, ユニークでなければなりません. ただし, 同じスパイダーのインスタンスは一つだけ作成可能で, 複数インスタンス化することはできません. これは最も重要なスパイダー属性であり, 必須です.
スパイダーが単一のドメインをスクラップする場合, 一般的には, TLD の有無にかかわらず, ドメイン名と同じの名前を付けます. したがって, たとえば,
mywebsite.com
をクロールするスパイダーには,mywebsite
という名前をつけます.
注釈
Python 2 では, ASCIIのみでなければなりません.
-
allowed_domains
¶ このスパイダーがクロールできるドメインを含む文字列のオプションのリスト.
OffsiteMiddleware
が有効になっている場合, このリスト(またはそのサブドメイン)で指定された ドメイン名に属していないURLに対するリクエストは追跡されません.
-
start_urls
¶ 特定のURLが指定されていない場合, スパイダーがクロールを開始するURLのリスト. したがって, ダウンロードされる最初のページはここにリストされたページになります. 後続のURLは, 開始URLに含まれるデータから順番に生成されます.
-
custom_settings
¶ このスパイダーを実行するときにオーバーライドされるプロジェクトの設定の辞書. インスタンス化前に設定が更新されるため, クラス属性として定義する必要があります.
使用可能なビルトイン設定のリストについては, ビルトイン設定リファレンス を参照してください.
-
crawler
¶ この属性は, クラスを初期化した後の
from_crawler()
クラスメソッドによって設定され, このスパイダーインスタンスがバインドされているCrawler
オブジェクトへのリンクになります.クローラは, 単一エントリアクセス(エクステンション, ミドルウェア, シグナルマネージャなど)のために, プロジェクト内の多くのコンポーネントをカプセル化します. 詳細については クローラー API を参照してください.
-
logger
¶ スパイダーの
name
で作成された Python ロガー. スパイダーからのロギング で説明しているように, これを使ってログメッセージを送信することができます.
-
from_crawler
(crawler, *args, **kwargs)¶ これは Scrapy があなたのスパイダーを作成するために使用するクラスメソッドです.
デフォルトの実装は
__init__()
メソッドへのプロキシとして機能し, 与えられた引数 args と名前付き引数 kwargs を呼び出すので, これを直接オーバーライドする必要はないでしょう.それにもかかわらず, このメソッドは
crawler
とsettings
属性を新しいインスタンスに設定し, 後でスパイダのコード内でアクセスできるようにします.パラメータ:
-
start_requests
()¶ このメソッドは, スパイダーの最初のクロールリクエストで繰り返し可能な値を返す必要があります.
これは, 特定のURLが指定されずにスパイダーを開いてスクレイピングするときに, Scrapy によって呼び出されるメソッドです. 特定のURLが指定されている場合, 代わりに
make_requests_from_url()
がリクエストを作成するために使用されます. このメソッドはScrapyから1回だけ呼び出されるため, 安全にジェネレータとして実装することができます.デフォルトの実装では,
make_requests_from_url()
を使用して,start_urls
内の各URLのリクエストを生成します.ドメインのスクレイピングを開始するために使用されるリクエストを変更したい場合は, これをオーバーライドすることができます. たとえば, 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
-
make_requests_from_url
(url)¶ URLを受け取って,
Request
オブジェクト (またはRequest
オブジェクトのリスト) を返すメソッド. このメソッドは,start_requests()
メソッドで初期リクエストを作成するために使用され, 通常は URL をリクエストに変換するために使用されます.オーバーライドされない限り, このメソッドは, callback関数として
parse()
メソッドを使用し, パラメータを有効にしてリクエストを返します (詳細はRequest
クラスを参照してください).
-
parse
(response)¶ これは, リクエストがコールバックを指定していないときに, ダウンロードされたレスポンスを処理するために Scrapy に使用されるデフォルトのコールバックです.
parse
ソッドは, レスポンスを処理し, スクレイピングされたデータおよび/または, より多くのURLを返すことを担当します. その他のリクエストコールバックはSpider
クラスと同じ要件を持ちます.このメソッドおよび他のRequestコールバックは, イテレータブルな
Request
および/または,dict
または,Item
オブジェクトを返さなければなりません.パラメータ: response ( Response
) – パースするレスポンス
-
log
(message[, level, component])¶ スパイダーの
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').extract():
yield {"title": h3}
for url in response.xpath('//a/@href').extract():
yield scrapy.Request(url, callback=self.parse)
start_urls
の代わりに start_requests()
を直接使うことができます.
アイテム を使用することで多くの構造体にデータを与えることができます:
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').extract():
yield MyItem(title=h3)
for url in response.xpath('//a/@href').extract():
yield scrapy.Request(url, callback=self.parse)
スパイダーの引数¶
スパイダーは行動を変更する引数を受け取ることができます. スパイダー引数の一般的な用途の1つは, 開始URLを定義するか, サイトの特定のセクションにクロールを制限することですが, スパイダーの機能を構成するために使用できます.
スパイダーの引数は, -a
オプションを使用して crawl
コマンドに渡されます. 例えば:
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 = ['http://www.example.com/categories/%s' % category]
# ...
スパイダーの引数は, 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
¶ これは定期的なウェブサイトをクロールするために最も一般的に使用されるスパイダーです. 一連のルールを定義してリンクをたどるための便利なメカニズムを提供します. 特定のウェブサイトやプロジェクトには最適ではないかもしれませんが, いくつかのケースでは十分に一般的なので, より多くのカスタム機能のために必要に応じて上書きしたり, 独自のスパイダーを実装することができます.
Spiderから継承した属性(指定する必要がある)を除いて, このクラスは新しい属性をサポートします:
-
rules
¶ 1つ(または複数)の
Rule
オブジェクトのリストです. 各Rule
は, サイトをクロールするための特定の動作を定義します. Rules オブジェクトについては以下で説明します. 複数のルールが同じリンクに一致する場合, この属性で定義されている順序に従って, 最初のリンクが使用されます.
このスパイダーは, オーバーライド可能なメソッドも公開しています:
-
Rule¶
-
class
scrapy.spiders.
Rule
(link_extractor, callback=None, cb_kwargs=None, follow=None, process_links=None, process_request=None)¶ link_extractor
は, クロールされた各ページからリンクを抽出する方法を定義する Link Extractor オブジェクトです.callback
は抽出されたリンクごとに呼び出される, 呼び出し可能または文字列です(この場合, その名前を持つスパイダーオブジェクトのメソッドが使用されます). このコールバックは, 最初の引数としてレスポンスを受け取り,Item
オブジェクトおよび/またはRequest
オブジェクト(またはそれらのサブクラス)を含むリストを返す必要があります.警告
クロールスパイダールールを作成するときは,
CrawlSpider
はparse
メソッド自体を使用してロジックを実装するため,parse
メソッドをコールバックとして使用しないでください.parse
メソッドをオーバーライドすると, CrawlSpider が機能しなくなります.cb_kwargs
は, コールバック関数に渡すキーワード引数を含むdict
です.follow
は, このルールで抽出された各レスポンスからリンクをたどるかどうかを指定する bool 値です.callback
が None の場合,follow
のデフォルトはTrue
になります. それ以外の場合はFalse
にデフォルト設定されますprocess_links
は呼び出し可能です. 指定されたlink_extractor
を使用して各レスポンスから抽出されたリンクのリストごとに呼び出される文字列 (その名前のスパイダーオブジェクトのメソッドが使用されます)です. これは, 主にフィルタリングの目的で使用されます.process_request
は呼び出し可能です. このルールで抽出されたリクエストごとに呼び出され, リクエストを返す必要があります(リクエストをフィルタにかけるには, その名前を持つスパイダオブジェクトのメソッドが呼び出されます).
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 = (
# 'category.php' に一致するリンクを抽出する ('subsection.php' とは一致しません)
# そして, それらのリンクをたどります (なぜならコールバックはデフォルトで follow=True ではないからです).
Rule(LinkExtractor(allow=('category\.php', ), deny=('subsection\.php', ))),
# 'allow' と一致するリンクを抽出し, スパイダーの 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()').extract()
item['description'] = response.xpath('//td[@id="item_description"]/text()').extract()
return item
このスパイダーは, example.comのホームページをクロールし, カテゴリリンクとアイテムリンクを収集し,
後者を parse_item
メソッドで解析します.
各アイテムのレスポンスでは, XPathを使用してHTMLからいくつかのデータが抽出され,
Item
にそのデータをいれています.
XMLFeedSpider¶
-
class
scrapy.spiders.
XMLFeedSpider
¶ XMLFeedSpider は, XML フィードを特定のノード名で繰り返し解析するために設計されています. イテレーター は
iternodes
,xml
, 及びhtml
から選択することができます.xml
とhtml
のイテレーターは, 解析するために一度にDOM
全体を生成するので, パフォーマンス上の理由からiternode
イテレーターを使用することをお勧めします. しかし, イテレータとしてhtml
を使用すると, だめなマークアップで書かれたXML
を解析するときに便利です.イテレータとタグ名を設定するには, 次のクラス属性を定義する必要があります:
-
iterator
¶ 使用するイテレータを定義する文字列:
デフォルト:
'iternodes'
.
-
itertag
¶ 反復処理するノード(または要素)の名前の文字列.
例:
itertag = 'product'
-
namespaces
¶ このスパイダーで処理される, 文書で利用可能な名前空間を定義する
(prefix, uri)
タプルのリスト.prefix
とuri
は,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
を受け取ります. このメソッドをオーバーライドすることは必須です. そうしなければ, スパイダーが動作しません. このメソッドは,Item
オブジェクト,Request
オブジェクト, またはいずれかを含む iterable を返す必要があります.
-
process_results
(response, results)¶ このメソッドは, スパイダーから返された各結果(アイテムまたはリクエスト)に対して呼び出され, 結果をフレームワークコアに返す前に必要な最後の処理(たとえば, アイテムIDの設定)を実行するためのものです. これは結果のリストとそれらの結果を生み出したレスポンスを受け取ります. 結果のリスト(アイテムまたはレスポンス)を返す必要があります.
-
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.extract()))
item = TestItem()
item['id'] = node.xpath('@id').extract()
item['name'] = node.xpath('name').extract()
item['description'] = node.xpath('description').extract()
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ファイルの各ヘッダーのキーを使用(または検出)して, レスポンスと
dict
(各行を表す)を受け取ります. このスパイダーは, 事前処理と後処理の目的で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 を指定することもできます.
-
sitemap_rules
¶ タプル
(regex, callback)
のリスト:regex
は, サイトマップから抽出されたURLに一致する正規表現です.regex
は str かコンパイルされた正規表現オブジェクトのどちらかです.callback
は, 正規表現に一致するURLを処理するために使用するコールバックです.callback
は文字列(スパイダーメソッドの名前を示す)または呼び出し可能なものにすることができます.
例えば:
sitemap_rules = [('/product/', 'parse_product')]
ルールは順番に適用され, 一致する最初のルールのみが使用されます.
この属性を省略すると, サイトマップ内のすべてのURLが
parse
コールバックで処理されます.
-
sitemap_follow
¶ あなたが従うべきサイトマップの正規表現のリスト. これは, 他のサイトマップファイルを指す Sitemap index files を使用するサイトのみに適用されます.
デフォルトでは, すべてのサイトマップに従います.
-
sitemap_alternate_links
¶ 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
は無効化されています.
-
SitemapSpider の例¶
かんたんな例: サイトマップを利用して見つけたURLを, すべて parse
コールバックによって処理する:
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を処理する:
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 ファイルによって定義されたサイトマップと, 一部に /sitemap_shop
を含むURLのみを処理する:
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と他のURLのソースを結合する:
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 ...
セレクタ¶
When you’re scraping web pages, the most common task you need to perform is to extract data from the HTML source. There are several libraries available to achieve this:
- BeautifulSoup is a very popular web scraping library among Python programmers which constructs a Python object based on the structure of the HTML code and also deals with bad markup reasonably well, but it has one drawback: it’s slow.
- lxml is an XML parsing library (which also parses HTML) with a pythonic API based on ElementTree. (lxml is not part of the Python standard library.)
Scrapy comes with its own mechanism for extracting data. They’re called selectors because they “select” certain parts of the HTML document specified either by XPath or CSS expressions.
XPath is a language for selecting nodes in XML documents, which can also be used with HTML. CSS is a language for applying styles to HTML documents. It defines selectors to associate those styles with specific HTML elements.
Scrapy selectors are built over the lxml library, which means they’re very similar in speed and parsing accuracy.
This page explains how selectors work and describes their API which is very small and simple, unlike the lxml API which is much bigger because the lxml library can be used for many other tasks, besides selecting markup documents.
For a complete reference of the selectors API see Selector reference
セレクタの使用¶
セレクタの作成¶
Scrapy selectors are instances of Selector
class
constructed by passing text or TextResponse
object. It automatically chooses the best parsing rules (XML vs HTML) based on
input type:
>>> from scrapy.selector import Selector
>>> from scrapy.http import HtmlResponse
Constructing from text:
>>> body = '<html><body><span>good</span></body></html>'
>>> Selector(text=body).xpath('//span/text()').extract()
[u'good']
Constructing from response:
>>> response = HtmlResponse(url='http://example.com', body=body)
>>> Selector(response=response).xpath('//span/text()').extract()
[u'good']
For convenience, response objects expose a selector on .selector attribute, it’s totally OK to use this shortcut when possible:
>>> response.selector.xpath('//span/text()').extract()
[u'good']
セレクタの使用¶
To explain how to use the selectors we’ll use the Scrapy shell (which provides interactive testing) and an example page located in the Scrapy documentation server:
Here’s its HTML code:
<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>
First, let’s open the shell:
scrapy shell http://doc.scrapy.org/en/latest/_static/selectors-sample1.html
Then, after the shell loads, you’ll have the response available as response
shell variable, and its attached selector in response.selector
attribute.
Since we’re dealing with HTML, the selector will automatically use an HTML parser.
So, by looking at the HTML code of that page, let’s construct an XPath for selecting the text inside the title tag:
>>> response.selector.xpath('//title/text()')
[<Selector (text) xpath=//title/text()>]
Querying responses using XPath and CSS is so common that responses include two
convenience shortcuts: response.xpath()
and response.css()
:
>>> response.xpath('//title/text()')
[<Selector (text) xpath=//title/text()>]
>>> response.css('title::text')
[<Selector (text) xpath=//title/text()>]
As you can see, .xpath()
and .css()
methods return a
SelectorList
instance, which is a list of new
selectors. This API can be used for quickly selecting nested data:
>>> response.css('img').xpath('@src').extract()
[u'image1_thumb.jpg',
u'image2_thumb.jpg',
u'image3_thumb.jpg',
u'image4_thumb.jpg',
u'image5_thumb.jpg']
To actually extract the textual data, you must call the selector .extract()
method, as follows:
>>> response.xpath('//title/text()').extract()
[u'Example website']
If you want to extract only first matched element, you can call the selector .extract_first()
>>> response.xpath('//div[@id="images"]/a/text()').extract_first()
u'Name: My image 1 '
It returns None
if no element was found:
>>> response.xpath('//div[@id="not-exists"]/text()').extract_first() is None
True
A default return value can be provided as an argument, to be used instead of None
:
>>> response.xpath('//div[@id="not-exists"]/text()').extract_first(default='not-found')
'not-found'
Notice that CSS selectors can select text or attribute nodes using CSS3 pseudo-elements:
>>> response.css('title::text').extract()
[u'Example website']
Now we’re going to get the base URL and some image links:
>>> response.xpath('//base/@href').extract()
[u'http://example.com/']
>>> response.css('base::attr(href)').extract()
[u'http://example.com/']
>>> response.xpath('//a[contains(@href, "image")]/@href').extract()
[u'image1.html',
u'image2.html',
u'image3.html',
u'image4.html',
u'image5.html']
>>> response.css('a[href*=image]::attr(href)').extract()
[u'image1.html',
u'image2.html',
u'image3.html',
u'image4.html',
u'image5.html']
>>> response.xpath('//a[contains(@href, "image")]/img/@src').extract()
[u'image1_thumb.jpg',
u'image2_thumb.jpg',
u'image3_thumb.jpg',
u'image4_thumb.jpg',
u'image5_thumb.jpg']
>>> response.css('a[href*=image] img::attr(src)').extract()
[u'image1_thumb.jpg',
u'image2_thumb.jpg',
u'image3_thumb.jpg',
u'image4_thumb.jpg',
u'image5_thumb.jpg']
ネストセレクタ¶
The selection methods (.xpath()
or .css()
) return a list of selectors
of the same type, so you can call the selection methods for those selectors
too. Here’s an example:
>>> links = response.xpath('//a[contains(@href, "image")]')
>>> links.extract()
[u'<a href="image1.html">Name: My image 1 <br><img src="image1_thumb.jpg"></a>',
u'<a href="image2.html">Name: My image 2 <br><img src="image2_thumb.jpg"></a>',
u'<a href="image3.html">Name: My image 3 <br><img src="image3_thumb.jpg"></a>',
u'<a href="image4.html">Name: My image 4 <br><img src="image4_thumb.jpg"></a>',
u'<a href="image5.html">Name: My image 5 <br><img src="image5_thumb.jpg"></a>']
>>> for index, link in enumerate(links):
... args = (index, link.xpath('@href').extract(), link.xpath('img/@src').extract())
... print 'Link number %d points to url %s and image %s' % args
Link number 0 points to url [u'image1.html'] and image [u'image1_thumb.jpg']
Link number 1 points to url [u'image2.html'] and image [u'image2_thumb.jpg']
Link number 2 points to url [u'image3.html'] and image [u'image3_thumb.jpg']
Link number 3 points to url [u'image4.html'] and image [u'image4_thumb.jpg']
Link number 4 points to url [u'image5.html'] and image [u'image5_thumb.jpg']
正規表現でのセレクタの使用¶
Selector
also has a .re()
method for extracting
data using regular expressions. However, unlike using .xpath()
or
.css()
methods, .re()
returns a list of unicode strings. So you
can’t construct nested .re()
calls.
Here’s an example used to extract image names from the HTML code above:
>>> response.xpath('//a[contains(@href, "image")]/text()').re(r'Name:\s*(.*)')
[u'My image 1',
u'My image 2',
u'My image 3',
u'My image 4',
u'My image 5']
There’s an additional helper reciprocating .extract_first()
for .re()
,
named .re_first()
. Use it to extract just the first matching string:
>>> response.xpath('//a[contains(@href, "image")]/text()').re_first(r'Name:\s*(.*)')
u'My image 1'
相対XPathの操作¶
Keep in mind that if you are nesting selectors and use an XPath that starts
with /
, that XPath will be absolute to the document and not relative to the
Selector
you’re calling it from.
For example, suppose you want to extract all <p>
elements inside <div>
elements. First, you would get all <div>
elements:
>>> divs = response.xpath('//div')
At first, you may be tempted to use the following approach, which is wrong, as
it actually extracts all <p>
elements from the document, not only those
inside <div>
elements:
>>> for p in divs.xpath('//p'): # this is wrong - gets all <p> from the whole document
... print p.extract()
This is the proper way to do it (note the dot prefixing the .//p
XPath):
>>> for p in divs.xpath('.//p'): # extracts all <p> inside
... print p.extract()
Another common case would be to extract all direct <p>
children:
>>> for p in divs.xpath('p'):
... print p.extract()
For more details about relative XPaths see the Location Paths section in the XPath specification.
EXSLT拡張機能の使用¶
Being built atop lxml, Scrapy selectors also support some EXSLT extensions and come with these pre-registered namespaces to use in XPath expressions:
prefix | namespace | usage |
---|---|---|
re | http://exslt.org/regular-expressions | regular expressions |
set | http://exslt.org/sets | set manipulation |
正規表現¶
The test()
function, for example, can prove quite useful when XPath’s
starts-with()
or contains()
are not sufficient.
Example selecting links in list item with a “class” attribute ending with a digit:
>>> 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').extract()
[u'link1.html', u'link2.html', u'link3.html', u'link4.html', u'link5.html']
>>> sel.xpath('//li[re:test(@class, "item-\d$")]//@href').extract()
[u'link1.html', u'link2.html', u'link4.html', u'link5.html']
>>>
警告
C library libxslt
doesn’t natively support EXSLT regular
expressions so lxml‘s implementation uses hooks to Python’s re
module.
Thus, using regexp functions in your XPath expressions may add a small
performance penalty.
操作を設定する¶
These can be handy for excluding parts of a document tree before extracting text elements for example.
Example extracting microdata (sample content taken from http://schema.org/Product) with groups of itemscopes and corresponding itemprops:
>>> 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').extract()
... props = scope.xpath('''
... set:difference(./descendant::*/@itemprop,
... .//*[@itemscope]/*/@itemprop)''')
... print " properties:", props.extract()
... print
current scope: [u'http://schema.org/Product']
properties: [u'name', u'aggregateRating', u'offers', u'description', u'review', u'review']
current scope: [u'http://schema.org/AggregateRating']
properties: [u'ratingValue', u'reviewCount']
current scope: [u'http://schema.org/Offer']
properties: [u'price', u'availability']
current scope: [u'http://schema.org/Review']
properties: [u'name', u'author', u'datePublished', u'reviewRating', u'description']
current scope: [u'http://schema.org/Rating']
properties: [u'worstRating', u'ratingValue', u'bestRating']
current scope: [u'http://schema.org/Review']
properties: [u'name', u'author', u'datePublished', u'reviewRating', u'description']
current scope: [u'http://schema.org/Rating']
properties: [u'worstRating', u'ratingValue', u'bestRating']
>>>
Here we first iterate over itemscope
elements, and for each one,
we look for all itemprops
elements and exclude those that are themselves
inside another itemscope
.
XPathのヒント¶
Here are some tips that you may find useful when using XPath with Scrapy selectors, based on this post from ScrapingHub’s blog. If you are not much familiar with XPath yet, you may want to take a look first at this XPath tutorial.
条件内のテキストノードの使用¶
When you need to use the text content as argument to an XPath string function,
avoid using .//text()
and use just .
instead.
This is because the expression .//text()
yields a collection of text elements – a node-set.
And when a node-set is converted to a string, which happens when it is passed as argument to
a string function like contains()
or starts-with()
, it results in the text for the first element only.
Example:
>>> from scrapy import Selector
>>> sel = Selector(text='<a href="#">Click here to go to the <strong>Next Page</strong></a>')
Converting a node-set to string:
>>> sel.xpath('//a//text()').extract() # take a peek at the node-set
[u'Click here to go to the ', u'Next Page']
>>> sel.xpath("string(//a[1]//text())").extract() # convert it to string
[u'Click here to go to the ']
A node converted to a string, however, puts together the text of itself plus of all its descendants:
>>> sel.xpath("//a[1]").extract() # select the first node
[u'<a href="#">Click here to go to the <strong>Next Page</strong></a>']
>>> sel.xpath("string(//a[1])").extract() # convert it to string
[u'Click here to go to the Next Page']
So, using the .//text()
node-set won’t select anything in this case:
>>> sel.xpath("//a[contains(.//text(), 'Next Page')]").extract()
[]
But using the .
to mean the node, works:
>>> sel.xpath("//a[contains(., 'Next Page')]").extract()
[u'<a href="#">Click here to go to the <strong>Next Page</strong></a>']
//node[1] と (//node)[1] の違いに注意してください¶
//node[1]
selects all the nodes occurring first under their respective parents.
(//node)[1]
selects all the nodes in the document, and then gets only the first of them.
Example:
>>> 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).extract()
This gets all first <li>
elements under whatever it is its parent:
>>> xp("//li[1]")
[u'<li>1</li>', u'<li>4</li>']
And this gets the first <li>
element in the whole document:
>>> xp("(//li)[1]")
[u'<li>1</li>']
This gets all first <li>
elements under an <ul>
parent:
>>> xp("//ul/li[1]")
[u'<li>1</li>', u'<li>4</li>']
And this gets the first <li>
element under an <ul>
parent in the whole document:
>>> xp("(//ul/li)[1]")
[u'<li>1</li>']
クラス別にクエリを実行する場合は, CSSを使用することを検討してください¶
Because an element can contain multiple CSS classes, the XPath way to select elements by class is the rather verbose:
*[contains(concat(' ', normalize-space(@class), ' '), ' someclass ')]
If you use @class='someclass'
you may end up missing elements that have
other classes, and if you just use contains(@class, 'someclass')
to make up
for that you may end up with more elements that you want, if they have a different
class name that shares the string someclass
.
As it turns out, Scrapy selectors allow you to chain selectors, so most of the time you can just select by class using CSS and then switch to XPath when needed:
>>> 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').extract()
[u'2014-07-23 19:00']
This is cleaner than using the verbose XPath trick shown above. Just remember
to use the .
in the XPath expressions that will follow.
ビルトインセレクタリファレンス¶
-
class
scrapy.selector.
Selector
(response=None, text=None, type=None)¶ An instance of
Selector
is a wrapper over response to select certain parts of its content.response
is anHtmlResponse
or anXmlResponse
object that will be used for selecting and extracting data.text
is a unicode string or utf-8 encoded text for cases when aresponse
isn’t available. Usingtext
andresponse
together is undefined behavior.type
defines the selector type, it can be"html"
,"xml"
orNone
(default).If
type
isNone
, the selector automatically chooses the best type based onresponse
type (see below), or defaults to"html"
in case it is used together withtext
.If
type
isNone
and aresponse
is passed, the selector type is inferred from the response type as follows:"html"
forHtmlResponse
type"xml"
forXmlResponse
type"html"
for anything else
Otherwise, if
type
is set, the selector type will be forced and no detection will occur.-
xpath
(query)¶ Find nodes matching the xpath
query
and return the result as aSelectorList
instance with all elements flattened. List elements implementSelector
interface too.query
is a string containing the XPATH query to apply.注釈
For convenience, this method can be called as
response.xpath()
-
css
(query)¶ Apply the given CSS selector and return a
SelectorList
instance.query
is a string containing the CSS selector to apply.In the background, CSS queries are translated into XPath queries using cssselect library and run
.xpath()
method.注釈
For convenience this method can be called as
response.css()
-
extract
()¶ Serialize and return the matched nodes as a list of unicode strings. Percent encoded content is unquoted.
-
re
(regex)¶ Apply the given regex and return a list of unicode strings with the matches.
regex
can be either a compiled regular expression or a string which will be compiled to a regular expression usingre.compile(regex)
-
register_namespace
(prefix, uri)¶ Register the given namespace to be used in this
Selector
. Without registering namespaces you can’t select or extract data from non-standard namespaces. See examples below.
-
remove_namespaces
()¶ Remove all namespaces, allowing to traverse the document using namespace-less xpaths. See example below.
SelectorList オブジェクト¶
-
class
scrapy.selector.
SelectorList
¶ The
SelectorList
class is a subclass of the builtinlist
class, which provides a few additional methods.-
xpath
(query)¶ Call the
.xpath()
method for each element in this list and return their results flattened as anotherSelectorList
.query
is the same argument as the one inSelector.xpath()
-
css
(query)¶ Call the
.css()
method for each element in this list and return their results flattened as anotherSelectorList
.query
is the same argument as the one inSelector.css()
-
extract
()¶ Call the
.extract()
method for each element in this list and return their results flattened, as a list of unicode strings.
-
re
()¶ Call the
.re()
method for each element in this list and return their results flattened, as a list of unicode strings.
-
__nonzero__
()¶ returns True if the list is not empty, False otherwise.
-
HTMLレスポンスのセレクタの例¶
Here’s a couple of Selector
examples to illustrate several concepts.
In all cases, we assume there is already a Selector
instantiated with
a HtmlResponse
object like this:
sel = Selector(html_response)
Select all
<h1>
elements from an HTML response body, returning a list ofSelector
objects (ie. aSelectorList
object):sel.xpath("//h1")
Extract the text of all
<h1>
elements from an HTML response body, returning a list of unicode strings:sel.xpath("//h1").extract() # this includes the h1 tag sel.xpath("//h1/text()").extract() # this excludes the h1 tag
Iterate over all
<p>
tags and print their class attribute:for node in sel.xpath("//p"): print node.xpath("@class").extract()
XMLレスポンスのセレクタの例¶
Here’s a couple of examples to illustrate several concepts. In both cases we
assume there is already a Selector
instantiated with an
XmlResponse
object like this:
sel = Selector(xml_response)
Select all
<product>
elements from an XML response body, returning a list ofSelector
objects (ie. aSelectorList
object):sel.xpath("//product")
Extract all prices from a Google Base XML feed which requires registering a namespace:
sel.register_namespace("g", "http://base.google.com/ns/1.0") sel.xpath("//g:price").extract()
ネームスペースの削除¶
When dealing with scraping projects, it is often quite convenient to get rid of
namespaces altogether and just work with element names, to write more
simple/convenient XPaths. You can use the
Selector.remove_namespaces()
method for that.
Let’s show an example that illustrates this with GitHub blog atom feed.
First, we open the shell with the url we want to scrape:
$ scrapy shell https://github.com/blog.atom
Once in the shell we can try selecting all <link>
objects and see that it
doesn’t work (because the Atom XML namespace is obfuscating those nodes):
>>> response.xpath("//link")
[]
But once we call the Selector.remove_namespaces()
method, all
nodes can be accessed directly by their names:
>>> response.selector.remove_namespaces()
>>> response.xpath("//link")
[<Selector xpath='//link' data=u'<link xmlns="http://www.w3.org/2005/Atom'>,
<Selector xpath='//link' data=u'<link xmlns="http://www.w3.org/2005/Atom'>,
...
If you wonder why the namespace removal procedure isn’t always called by default instead of having to call it manually, this is because of two reasons, which, in order of relevance, are:
- Removing namespaces requires to iterate and modify all nodes in the document, which is a reasonably expensive operation to perform for all documents crawled by Scrapy
- There could be some cases where using namespaces is actually required, in case some element names clash between namespaces. These cases are very rare though.
アイテム¶
スクレイピングの主な目的は, 構造化されていないソース(通常はWebページ)から構造化データを抽出することです. Scrapy スパイダーは Python の dicts として抽出されたデータを返すことができます. Python の dicts は便利で親しみがありますが, 構造が欠けています. 特に, 多くのスパイダーを持つ大規模なプロジェクトでは, フィールド名の入力ミスを起こしたり, 矛盾したデータを返すことがよく起こります.
一般的な出力データフォーマットを定義するために, Scrapyは Item
クラスを提供しています.
Item
オブジェクトは, スクラップされたデータを収集するために使用される単純なコンテナです.
利用可能なフィールドを宣言するのに便利な構文を備えた
dictionary-like なAPIを提供します.
Various Scrapy components use extra information provided by Items:
exporters look at declared fields to figure out columns to export,
serialization can be customized using Item fields metadata, trackref
tracks Item instances to help finding memory leaks
(see trackref でメモリリークのデバッグをする), etc.
宣言項目¶
Items are declared using a simple class definition syntax and Field
objects. Here is an example:
import scrapy
class Product(scrapy.Item):
name = scrapy.Field()
price = scrapy.Field()
stock = scrapy.Field()
last_updated = scrapy.Field(serializer=str)
注釈
Those familiar with Django will notice that Scrapy Items are declared similar to Django Models, except that Scrapy Items are much simpler as there is no concept of different field types.
アイテムフィールド¶
Field
objects are used to specify metadata for each field. For
example, the serializer function for the last_updated
field illustrated in
the example above.
You can specify any kind of metadata for each field. There is no restriction on
the values accepted by Field
objects. For this same
reason, there is no reference list of all available metadata keys. Each key
defined in Field
objects could be used by a different component, and
only those components know about it. You can also define and use any other
Field
key in your project too, for your own needs. The main goal of
Field
objects is to provide a way to define all field metadata in one
place. Typically, those components whose behaviour depends on each field use
certain field keys to configure that behaviour. You must refer to their
documentation to see which metadata keys are used by each component.
It’s important to note that the Field
objects used to declare the item
do not stay assigned as class attributes. Instead, they can be accessed through
the Item.fields
attribute.
アイテムの操作¶
Here are some examples of common tasks performed with items, using the
Product
item declared above. You will
notice the API is very similar to the 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')]
その他の一般的なタスク¶
items をコピーする:
>>> product2 = Product(product)
>>> print product2
Product(name='Desktop PC', price=1000)
>>> product3 = product2.copy()
>>> print product3
Product(name='Desktop PC', price=1000)
items から dicts を作成する:
>>> dict(product) # create a dict from all populated values
{'price': 1000, 'name': 'Desktop PC'}
dicts から items を作成する:
>>> 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'
アイテムの拡張¶
You can extend Items (to add more fields or to change some metadata for some fields) by declaring a subclass of your original Item.
For example:
class DiscountedProduct(Product):
discount_percent = scrapy.Field(serializer=str)
discount_expiration_date = scrapy.Field()
You can also extend field metadata by using the previous field metadata and appending more values, or changing existing values, like this:
class SpecificProduct(Product):
name = scrapy.Field(Product.fields['name'], serializer=my_serializer)
That adds (or replaces) the serializer
metadata key for the name
field,
keeping all the previously existing metadata values.
Itemオブジェクト¶
-
class
scrapy.item.
Item
([arg])¶ Return a new Item optionally initialized from the given argument.
Items replicate the standard dict API, including its constructor. The only additional attribute provided by Items is:
-
fields
¶ A dictionary containing all declared fields for this Item, not only those populated. The keys are the field names and the values are the
Field
objects used in the Item declaration.
-
Fieldオブジェクト¶
-
class
scrapy.item.
Field
([arg])¶ The
Field
class is just an alias to the built-in dict class and doesn’t provide any extra functionality or attributes. In other words,Field
objects are plain-old Python dicts. A separate class is used to support the item declaration syntax based on class attributes.
アイテムローダー¶
アイテムローダーは, 集めてきた アイテム を投入するための便利なメカニズムを提供します. Items は独自の辞書型APIを使用して作成できますが, アイテムローダーは, スクレイピング処理からデータを取り込むためのより便利なAPIを提供しています.
言い換えれば, アイテム スクレイピングされたデータの コンテナ を提供し, アイテムローダーはそのコンテナを投入するためのメカニズムを提供します.
アイテムローダーは, スパイダー, またはソースフォーマット(HTML, XMLなど)のいずれかで, 維持する悪夢にうなされずに, さまざまなフィールド解析ルールを拡張および上書きするための 柔軟で効率的で簡単なメカニズムを提供するように設計されています.
アイテムローダーを使用したアイテムの設定¶
To use an Item Loader, you must first instantiate it. You can either
instantiate it with a dict-like object (e.g. Item or dict) or without one, in
which case an Item is automatically instantiated in the Item Loader constructor
using the Item class specified in the ItemLoader.default_item_class
attribute.
Then, you start collecting values into the Item Loader, typically using Selectors. You can add more than one value to the same item field; the Item Loader will know how to “join” those values later using a proper processing function.
Here is a typical Item Loader usage in a Spider, using the Product item declared in the Items chapter:
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()
By quickly looking at that code, we can see the name
field is being
extracted from two different XPath locations in the page:
//div[@class="product_name"]
//div[@class="product_title"]
In other words, data is being collected by extracting it from two XPath
locations, using the add_xpath()
method. This is the
data that will be assigned to the name
field later.
Afterwards, similar calls are used for price
and stock
fields
(the latter using a CSS selector with the add_css()
method),
and finally the last_update
field is populated directly with a literal value
(today
) using a different method: add_value()
.
Finally, when all data is collected, the ItemLoader.load_item()
method is
called which actually returns the item populated with the data
previously extracted and collected with the add_xpath()
,
add_css()
, and add_value()
calls.
入力および出力プロセッサ¶
An Item Loader contains one input processor and one output processor for each
(item) field. The input processor processes the extracted data as soon as it’s
received (through the add_xpath()
, add_css()
or
add_value()
methods) and the result of the input processor is
collected and kept inside the ItemLoader. After collecting all data, the
ItemLoader.load_item()
method is called to populate and get the populated
Item
object. That’s when the output processor is
called with the data previously collected (and processed using the input
processor). The result of the output processor is the final value that gets
assigned to the item.
Let’s see an example to illustrate how the input and output processors are called for a particular field (the same applies for any other field):
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)
So what happens is:
- Data from
xpath1
is extracted, and passed through the input processor of thename
field. The result of the input processor is collected and kept in the Item Loader (but not yet assigned to the item). - Data from
xpath2
is extracted, and passed through the same input processor used in (1). The result of the input processor is appended to the data collected in (1) (if any). - This case is similar to the previous ones, except that the data is extracted
from the
css
CSS selector, and passed through the same input processor used in (1) and (2). The result of the input processor is appended to the data collected in (1) and (2) (if any). - This case is also similar to the previous ones, except that the value to be collected is assigned directly, instead of being extracted from a XPath expression or a CSS selector. However, the value is still passed through the input processors. In this case, since the value is not iterable it is converted to an iterable of a single element before passing it to the input processor, because input processor always receive iterables.
- The data collected in steps (1), (2), (3) and (4) is passed through
the output processor of the
name
field. The result of the output processor is the value assigned to thename
field in the item.
It’s worth noticing that processors are just callable objects, which are called with the data to be parsed, and return a parsed value. So you can use any function as input or output processor. The only requirement is that they must accept one (and only one) positional argument, which will be an iterator.
注釈
Both input and output processors must receive an iterator as their first argument. The output of those functions can be anything. The result of input processors will be appended to an internal list (in the Loader) containing the collected values (for that field). The result of the output processors is the value that will be finally assigned to the item.
The other thing you need to keep in mind is that the values returned by input processors are collected internally (in lists) and then passed to output processors to populate the fields.
Last, but not least, Scrapy comes with some commonly used processors built-in for convenience.
アイテムローダーの宣言¶
Item Loaders are declared like Items, by using a class definition syntax. Here is an example:
from scrapy.loader import ItemLoader
from scrapy.loader.processors import TakeFirst, MapCompose, Join
class ProductLoader(ItemLoader):
default_output_processor = TakeFirst()
name_in = MapCompose(unicode.title)
name_out = Join()
price_in = MapCompose(unicode.strip)
# ...
As you can see, input processors are declared using the _in
suffix while
output processors are declared using the _out
suffix. And you can also
declare a default input/output processors using the
ItemLoader.default_input_processor
and
ItemLoader.default_output_processor
attributes.
入力および出力プロセッサの宣言¶
As seen in the previous section, input and output processors can be declared in the Item Loader definition, and it’s very common to declare input processors this way. However, there is one more place where you can specify the input and output processors to use: in the Item Field metadata. Here is an example:
import scrapy
from scrapy.loader.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', [u'Welcome to my', u'<strong>website</strong>'])
>>> il.add_value('price', [u'€', u'<span>1000</span>'])
>>> il.load_item()
{'name': u'Welcome to my website', 'price': u'1000'}
The precedence order, for both input and output processors, is as follows:
- Item Loader field-specific attributes:
field_in
andfield_out
(most precedence) - Field metadata (
input_processor
andoutput_processor
key) - Item Loader defaults:
ItemLoader.default_input_processor()
andItemLoader.default_output_processor()
(least precedence)
アイテムローダの再利用と拡張 を参照してください.
アイテムローダーコンテキスト¶
The Item Loader Context is a dict of arbitrary key/values which is shared among all input and output processors in the Item Loader. It can be passed when declaring, instantiating or using Item Loader. They are used to modify the behaviour of the input/output processors.
For example, suppose you have a function parse_length
which receives a text
value and extracts a length from it:
def parse_length(text, loader_context):
unit = loader_context.get('unit', 'm')
# ... length parsing code goes here ...
return parsed_length
By accepting a loader_context
argument the function is explicitly telling
the Item Loader that it’s able to receive an Item Loader context, so the Item
Loader passes the currently active context when calling it, and the processor
function (parse_length
in this case) can thus use them.
There are several ways to modify Item Loader context values:
By modifying the currently active Item Loader context (
context
attribute):loader = ItemLoader(product) loader.context['unit'] = 'cm'
On Item Loader instantiation (the keyword arguments of Item Loader constructor are stored in the Item Loader context):
loader = ItemLoader(product, unit='cm')
On Item Loader declaration, for those input/output processors that support instantiating them with an Item Loader context.
MapCompose
is one of them:class ProductLoader(ItemLoader): length_out = MapCompose(parse_length, unit='cm')
ItemLoader オブジェクト¶
-
class
scrapy.loader.
ItemLoader
([item, selector, response, ]**kwargs)¶ Return a new Item Loader for populating the given Item. If no item is given, one is instantiated automatically using the class in
default_item_class
.When instantiated with a selector or a response parameters the
ItemLoader
class provides convenient mechanisms for extracting data from web pages using selectors.パラメータ: - item (
Item
object) – The item instance to populate using subsequent calls toadd_xpath()
,add_css()
, oradd_value()
. - selector (
Selector
object) – The selector to extract data from, when using theadd_xpath()
(resp.add_css()
) orreplace_xpath()
(resp.replace_css()
) method. - response (
Response
object) – The response used to construct the selector using thedefault_selector_class
, unless the selector argument is given, in which case this argument is ignored.
The item, selector, response and the remaining keyword arguments are assigned to the Loader context (accessible through the
context
attribute).ItemLoader
instances have the following methods:-
get_value
(value, *processors, **kwargs)¶ Process the given
value
by the givenprocessors
and keyword arguments.Available keyword arguments:
パラメータ: re (str or compiled regex) – a regular expression to use for extracting data from the given value using extract_regex()
method, applied before processors例:
>>> from scrapy.loader.processors import TakeFirst >>> loader.get_value(u'name: foo', TakeFirst(), unicode.upper, re='name: (.+)') 'FOO`
-
add_value
(field_name, value, *processors, **kwargs)¶ Process and then add the given
value
for the given field.The value is first passed through
get_value()
by giving theprocessors
andkwargs
, 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 beNone
, 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', u'Color TV') loader.add_value('colours', [u'white', u'blue']) loader.add_value('length', u'100') loader.add_value('name', u'name: foo', TakeFirst(), re='name: (.+)') loader.add_value(None, {'name': u'foo', 'sex': u'male'})
-
replace_value
(field_name, value, *processors, **kwargs)¶ Similar to
add_value()
but replaces the collected data with the new value instead of adding it.
-
get_xpath
(xpath, *processors, **kwargs)¶ 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 thisItemLoader
.パラメータ: - xpath (str) – the XPath to extract data from
- re (str or compiled regex) – a regular expression to use for extracting data from the selected XPath region
例:
# 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 (.*)')
-
add_xpath
(field_name, xpath, *processors, **kwargs)¶ Similar to
ItemLoader.add_value()
but receives an XPath instead of a value, which is used to extract a list of unicode strings from the selector associated with thisItemLoader
.See
get_xpath()
forkwargs
.パラメータ: xpath (str) – the XPath to extract data from 例:
# 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 (.*)')
-
replace_xpath
(field_name, xpath, *processors, **kwargs)¶ Similar to
add_xpath()
but replaces collected data instead of adding it.
-
get_css
(css, *processors, **kwargs)¶ 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 thisItemLoader
.パラメータ: - css (str) – the CSS selector to extract data from
- re (str or compiled regex) – a regular expression to use for extracting data from the selected CSS region
例:
# 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 (.*)')
-
add_css
(field_name, css, *processors, **kwargs)¶ 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 thisItemLoader
.See
get_css()
forkwargs
.パラメータ: css (str) – the CSS selector to extract data from 例:
# 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 (.*)')
-
replace_css
(field_name, css, *processors, **kwargs)¶ Similar to
add_css()
but replaces collected data instead of adding it.
-
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_xpath
(xpath)¶ Create a nested loader with an xpath selector. The supplied selector is applied relative to selector associated with this
ItemLoader
. The nested loader shares theItem
with the parentItemLoader
so calls toadd_xpath()
,add_value()
,replace_value()
, etc. will behave as expected.
-
nested_css
(css)¶ Create a nested loader with a css selector. The supplied selector is applied relative to selector associated with this
ItemLoader
. The nested loader shares theItem
with the parentItemLoader
so calls toadd_xpath()
,add_value()
,replace_value()
, etc. will behave as expected.
-
get_collected_values
(field_name)¶ Return the collected values for the given field.
-
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_input_processor
(field_name)¶ 指定されたフィールドの入力プロセッサーを返します.
-
get_output_processor
(field_name)¶ Return the output processor for the given field.
ItemLoader
instances have the following attributes:-
default_item_class
¶ An Item class (or factory), used to instantiate items when not given in the constructor.
-
default_input_processor
¶ 指定されていないフィールドに使用するデフォルトの入力プロセッサー.
-
default_output_processor
¶ 特に指定のないフィールドに使用するデフォルト出力プロセッサ.
-
default_selector_class
¶ The class used to construct the
selector
of thisItemLoader
, if only a response is given in the constructor. If a selector is given in the constructor 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 constructor or one created from the response given in the constructor using thedefault_selector_class
. This attribute is meant to be read-only.
- item (
ネストされたローダー¶
When parsing related values from a subsection of a document, it can be useful to create nested loaders. Imagine you’re extracting details from a footer of a page that looks something like:
Example:
<footer>
<a class="social" href="http://facebook.com/whatever">Like Us</a>
<a class="social" href="http://twitter.com/whatever">Follow Us</a>
<a class="email" href="mailto:whatever@example.com">Email Us</a>
</footer>
Without nested loaders, you need to specify the full xpath (or css) for each value that you wish to extract.
Example:
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()
Instead, you can create a nested loader with the footer selector and add values relative to the footer. The functionality is the same but you avoid repeating the footer selector.
Example:
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')
# footer_loader.load_item() を実行する必要はない
loader.load_item()
You can nest loaders arbitrarily and they work with either xpath or css selectors. As a general guideline, use nested loaders when they make your code simpler but do not go overboard with nesting or your parser can become difficult to read.
アイテムローダの再利用と拡張¶
As your project grows bigger and acquires more and more spiders, maintenance becomes a fundamental problem, especially when you have to deal with many different parsing rules for each spider, having a lot of exceptions, but also wanting to reuse the common processors.
Item Loaders are designed to ease the maintenance burden of parsing rules, without losing flexibility and, at the same time, providing a convenient mechanism for extending and overriding them. For this reason Item Loaders support traditional Python class inheritance for dealing with differences of specific spiders (or groups of spiders).
Suppose, for example, that some particular site encloses their product names in
three dashes (e.g. ---Plasma TV---
) and you don’t want to end up scraping
those dashes in the final product names.
Here’s how you can remove those dashes by reusing and extending the default
Product Item Loader (ProductLoader
):
from scrapy.loader.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)
Another case where extending Item Loaders can be very helpful is when you have
multiple source formats, for example XML and HTML. In the XML version you may
want to remove CDATA
occurrences. Here’s an example of how to do it:
from scrapy.loader.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)
そしてそれは典型的な入力プロセッサを拡張する方法です.
As for output processors, it is more common to declare them in the field metadata, as they usually depend only on the field and not on each specific site parsing rule (as input processors do). See also: 入力および出力プロセッサの宣言.
There are many other possible ways to extend, inherit and override your Item Loaders, and different Item Loaders hierarchies may fit better for different projects. Scrapy only provides the mechanism; it doesn’t impose any specific organization of your Loaders collection - that’s up to you and your project’s needs.
使用可能な内蔵プロセッサ¶
Even though you can use any callable function as input and output processors,
Scrapy provides some commonly used processors, which are described below. Some
of them, like the MapCompose
(which is typically used as input
processor) compose the output of several functions executed in order, to
produce the final parsed value.
Here is a list of all built-in processors:
-
class
scrapy.loader.processors.
Identity
¶ The simplest processor, which doesn’t do anything. It returns the original values unchanged. It doesn’t receive any constructor arguments, nor does it accept Loader contexts.
Example:
>>> from scrapy.loader.processors import Identity >>> proc = Identity() >>> proc(['one', 'two', 'three']) ['one', 'two', 'three']
-
class
scrapy.loader.processors.
TakeFirst
¶ Returns the first non-null/non-empty value from the values received, so it’s typically used as an output processor to single-valued fields. It doesn’t receive any constructor arguments, nor does it accept Loader contexts.
Example:
>>> from scrapy.loader.processors import TakeFirst >>> proc = TakeFirst() >>> proc(['', 'one', 'two', 'three']) 'one'
-
class
scrapy.loader.processors.
Join
(separator=u' ')¶ Returns the values joined with the separator given in the constructor, which defaults to
u' '
. It doesn’t accept Loader contexts.When using the default separator, this processor is equivalent to the function:
u' '.join
Examples:
>>> from scrapy.loader.processors import Join >>> proc = Join() >>> proc(['one', 'two', 'three']) u'one two three' >>> proc = Join('<br>') >>> proc(['one', 'two', 'three']) u'one<br>two<br>three'
-
class
scrapy.loader.processors.
Compose
(*functions, **default_loader_context)¶ A processor which is constructed from the composition of the given functions. This means that each input value of this processor is passed to the first function, and the result of that function is passed to the second function, and so on, until the last function returns the output value of this processor.
By default, stop process on
None
value. This behaviour can be changed by passing keyword argumentstop_on_none=False
.Example:
>>> from scrapy.loader.processors import Compose >>> proc = Compose(lambda v: v[0], str.upper) >>> proc(['hello', 'world']) 'HELLO'
Each function can optionally receive a
loader_context
parameter. For those which do, this processor will pass the currently active Loader context through that parameter.The keyword arguments passed in the constructor are used as the default Loader context values passed to each function call. However, the final Loader context values passed to functions are overridden with the currently active Loader context accessible through the
ItemLoader.context()
attribute.
-
class
scrapy.loader.processors.
MapCompose
(*functions, **default_loader_context)¶ A processor which is constructed from the composition of the given functions, similar to the
Compose
processor. The difference with this processor is the way internal results are passed among functions, which is as follows:The input value of this processor is iterated and the first function is applied to each element. The results of these function calls (one for each element) are concatenated to construct a new iterable, which is then used to apply the second function, and so on, until the last function is applied to each value of the list of values collected so far. The output values of the last function are concatenated together to produce the output of this processor.
Each particular function can return a value or a list of values, which is flattened with the list of values returned by the same function applied to the other input values. The functions can also return
None
in which case the output of that function is ignored for further processing over the chain.This processor provides a convenient way to compose functions that only work with single values (instead of iterables). For this reason the
MapCompose
processor is typically used as input processor, since data is often extracted using theextract()
method of selectors, which returns a list of unicode strings.The example below should clarify how it works:
>>> def filter_world(x): ... return None if x == 'world' else x ... >>> from scrapy.loader.processors import MapCompose >>> proc = MapCompose(filter_world, unicode.upper) >>> proc([u'hello', u'world', u'this', u'is', u'scrapy']) [u'HELLO, u'THIS', u'IS', u'SCRAPY']
As with the Compose processor, functions can receive Loader contexts, and constructor keyword arguments are used as default context values. See
Compose
processor for more info.
-
class
scrapy.loader.processors.
SelectJmes
(json_path)¶ Queries the value using the json path provided to the constructor and returns the output. Requires jmespath (https://github.com/jmespath/jmespath.py) to run. This processor takes only one input at a time.
例:
>>> from scrapy.loader.processors import SelectJmes, Compose, MapCompose >>> proc = SelectJmes("foo") #for direct use on lists and dictionaries >>> proc({'foo': 'bar'}) 'bar' >>> proc({'foo': {'bar': 'baz'}}) {'bar': 'baz'}
Json の中身を見る:
>>> import json >>> proc_single_json_str = Compose(json.loads, SelectJmes("foo")) >>> proc_single_json_str('{"foo": "bar"}') u'bar' >>> proc_json_list = Compose(json.loads, MapCompose(SelectJmes('foo'))) >>> proc_json_list('[{"foo":"bar"}, {"baz":"tar"}]') [u'bar']
Scrapy シェル¶
The Scrapy shell is an interactive shell where you can try and debug your scraping code very quickly, without having to run the spider. It’s meant to be used for testing data extraction code, but you can actually use it for testing any kind of code as it is also a regular Python shell.
The shell is used for testing XPath or CSS expressions and see how they work and what data they extract from the web pages you’re trying to scrape. It allows you to interactively test your expressions while you’re writing your spider, without having to run the spider to test every change.
Once you get familiarized with the Scrapy shell, you’ll see that it’s an invaluable tool for developing and debugging your spiders.
シェルの設定¶
If you have IPython installed, the Scrapy shell will use it (instead of the standard Python console). The IPython console is much more powerful and provides smart auto-completion and colorized output, among other things.
We highly recommend you install IPython, specially if you’re working on Unix systems (where IPython excels). See the IPython installation guide for more info.
Scrapy also has support for bpython, and will try to use it where IPython is unavailable.
Through scrapy’s settings you can configure it to use any one of
ipython
, bpython
or the standard python
shell, regardless of which
are installed. This is done by setting the SCRAPY_PYTHON_SHELL
environment
variable; or by defining it in your scrapy.cfg:
[settings]
shell = bpython
シェルの実行¶
To launch the Scrapy shell you can use the shell
command like
this:
scrapy shell <url>
Where the <url>
is the URL you want to scrape.
shell
also works for local files. This can be handy if you want
to play around with a local copy of a web page. shell
understands
the following syntaxes for local files:
# 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
注釈
When using relative file paths, be explicit and prepend them
with ./
(or ../
when relevant).
scrapy shell index.html
will not work as one might expect (and
this is by design, not a bug).
Because shell
favors HTTP URLs over File URIs,
and index.html
being syntactically similar to example.com
,
shell
will treat index.html
as a domain name and trigger
a DNS lookup error:
$ 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.
shell
will not test beforehand if a file called index.html
exists in the current directory. Again, be explicit.
シェルの使用¶
The Scrapy shell is just a regular Python console (or IPython console if you have it available) which provides some additional shortcut functions for convenience.
使用可能なショートカット¶
shelp()
- print a help with the list of available objects and shortcutsfetch(request_or_url)
- fetch a new response from the given request or URL and update all related objects accordingly.view(response)
- open the given response in your local web browser, for inspection. This will add a <base> tag to the response body in order for external links (such as images and style sheets) to display properly. Note, however, that this will create a temporary file in your computer, which won’t be removed automatically.
使用可能な Scrapy オブジェクト¶
The Scrapy shell automatically creates some convenient objects from the
downloaded page, like the Response
object and the
Selector
objects (for both HTML and XML
content).
Those objects are:
crawler
- the currentCrawler
object.spider
- the Spider which is known to handle the URL, or aSpider
object if there is no spider found for the current URLrequest
- aRequest
object of the last fetched page. You can modify this request usingreplace()
or fetch a new request (without leaving the shell) using thefetch
shortcut.response
- aResponse
object containing the last fetched pagesettings
- the current Scrapy settings
シェルセッションの例¶
Here’s an example of a typical shell session where we start by scraping the http://scrapy.org page, and then proceed to scrape the https://reddit.com page. Finally, we modify the (Reddit) request method to POST and re-fetch it getting an error. We end the session by typing Ctrl-D (in Unix systems) or Ctrl-Z in Windows.
Keep in mind that the data extracted here may not be the same when you try it, as those pages are not static and could have changed by the time you test this. The only purpose of this example is to get you familiarized with how the Scrapy shell works.
First, we launch the shell:
scrapy shell 'http://scrapy.org' --nolog
Then, the shell fetches the URL (using the Scrapy downloader) and prints the
list of available objects and useful shortcuts (you’ll notice that these lines
all start with the [s]
prefix):
[s] Available Scrapy objects:
[s] crawler <scrapy.crawler.Crawler object at 0x1e16b50>
[s] item {}
[s] request <GET http://scrapy.org>
[s] response <200 http://scrapy.org>
[s] settings <scrapy.settings.Settings object at 0x2bfd650>
[s] spider <Spider 'default' at 0x20c6f50>
[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
>>>
After that, we can start playing with the objects:
>>> response.xpath('//title/text()').extract_first()
u'Scrapy | A Fast and Powerful Scraping and Web Crawling Framework'
>>> fetch("http://reddit.com")
[s] Available Scrapy objects:
[s] crawler <scrapy.crawler.Crawler object at 0x7fb3ed9c9c90>
[s] item {}
[s] request <GET http://reddit.com>
[s] response <200 https://www.reddit.com/>
[s] settings <scrapy.settings.Settings object at 0x7fb3ed9c9c10>
[s] spider <DefaultSpider 'default' at 0x7fb3ecdd3390>
[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
>>> response.xpath('//title/text()').extract()
[u'reddit: the front page of the internet']
>>> request = request.replace(method="POST")
>>> fetch(request)
[s] Available Scrapy objects:
[s] crawler <scrapy.crawler.Crawler object at 0x1e16b50>
...
>>>
応答を調べるためにシェルを起動する¶
Sometimes you want to inspect the responses that are being processed in a certain point of your spider, if only to check that response you expect is getting there.
This can be achieved by using the scrapy.shell.inspect_response
function.
Here’s an example of how you would call it from your spider:
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.
When you run the spider, you will get something similar to this:
2014-01-23 17:48:31-0400 [scrapy] DEBUG: Crawled (200) <GET http://example.com> (referer: None)
2014-01-23 17:48:31-0400 [scrapy] 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'
Then, you can check if the extraction code is working:
>>> response.xpath('//h1[@class="fn"]')
[]
Nope, it doesn’t. So you can open the response in your web browser and see if it’s the response you were expecting:
>>> view(response)
True
Finally you hit Ctrl-D (or Ctrl-Z in Windows) to exit the shell and resume the crawling:
>>> ^D
2014-01-23 17:50:03-0400 [scrapy] DEBUG: Crawled (200) <GET http://example.net> (referer: None)
...
Note that you can’t use the fetch
shortcut here since the Scrapy engine is
blocked by the shell. However, after you leave the shell, the spider will
continue crawling where it stopped, as shown above.
アイテムパイプライン¶
After an item has been scraped by a spider, it is sent to the Item Pipeline which processes it through several components that are executed sequentially.
Each item pipeline component (sometimes referred as just “Item Pipeline”) is a Python class that implements a simple method. They receive an item and perform an action over it, also deciding if the item should continue through the pipeline or be dropped and no longer processed.
Typical uses of item pipelines are:
- cleansing HTML data
- validating scraped data (checking that the items contain certain fields)
- checking for duplicates (and dropping them)
- storing the scraped item in a database
独自のアイテムパイプラインの作成¶
Each item pipeline component is a Python class that must implement the following method:
-
process_item
(self, item, spider)¶ This method is called for every item pipeline component.
process_item()
must either: return a dict with data, return anItem
(or any descendant class) object, return a Twisted Deferred or raiseDropItem
exception. Dropped items are no longer processed by further pipeline components.パラメータ:
Additionally, they may also implement the following methods:
-
open_spider
(self, spider)¶ This method is called when the spider is opened.
パラメータ: spider ( Spider
object) – the spider which was opened
-
close_spider
(self, spider)¶ This method is called when the spider is closed.
パラメータ: spider ( Spider
object) – the spider which was closed
-
from_crawler
(cls, crawler)¶ If present, this classmethod is called to create a pipeline instance from a
Crawler
. It must return a new instance of the pipeline. Crawler object provides access to all Scrapy core components like settings and signals; it is a way for pipeline to access them and hook its functionality into Scrapy.パラメータ: crawler ( Crawler
object) – crawler that uses this pipeline
アイテムパイプラインの例¶
価格の確認と価格のないアイテムのドロップ¶
Let’s take a look at the following hypothetical pipeline that adjusts the
price
attribute for those items that do not include VAT
(price_excludes_vat
attribute), and drops those items which don’t
contain a price:
from scrapy.exceptions import DropItem
class PricePipeline(object):
vat_factor = 1.15
def process_item(self, item, spider):
if item['price']:
if item['price_excludes_vat']:
item['price'] = item['price'] * self.vat_factor
return item
else:
raise DropItem("Missing price in %s" % item)
アイテムをJSONファイルに出力する¶
The following pipeline stores all scraped items (from all spiders) into a
single items.jl
file, containing one item per line serialized in JSON
format:
import json
class JsonWriterPipeline(object):
def open_spider(self, spider):
self.file = open('items.jl', 'wb')
def close_spider(self, spider):
self.file.close()
def process_item(self, item, spider):
line = json.dumps(dict(item)) + "\n"
self.file.write(line)
return item
注釈
The purpose of JsonWriterPipeline is just to introduce how to write item pipelines. If you really want to store all scraped items into a JSON file you should use the Feed exports.
アイテムをMongoDBに出力する¶
In this example we’ll write items to MongoDB using pymongo. MongoDB address and database name are specified in Scrapy settings; MongoDB collection is named after item class.
The main point of this example is to show how to use from_crawler()
method and how to clean up the resources properly.:
import pymongo
class MongoPipeline(object):
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(dict(item))
return item
アイテムのスクリーンショットを撮る¶
This example demonstrates how to return Deferred from process_item()
method.
It uses Splash to render screenshot of item url. Pipeline
makes request to locally running instance of Splash. After request is downloaded
and Deferred callback fires, it saves item to a file and adds filename to an item.
import scrapy
import hashlib
from urllib.parse import quote
class ScreenshotPipeline(object):
"""Pipeline that uses Splash to render screenshot of
every Scrapy item."""
SPLASH_URL = "http://localhost:8050/render.png?url={}"
def process_item(self, item, spider):
encoded_item_url = quote(item["url"])
screenshot_url = self.SPLASH_URL.format(encoded_item_url)
request = scrapy.Request(screenshot_url)
dfd = spider.crawler.engine.download(request, spider)
dfd.addBoth(self.return_item, item)
return dfd
def return_item(self, response, item):
if response.status != 200:
# Error happened, return item.
return item
# Save screenshot to file, filename will be hash of url.
url = item["url"]
url_hash = hashlib.md5(url.encode("utf8")).hexdigest()
filename = "{}.png".format(url_hash)
with open(filename, "wb") as f:
f.write(response.body)
# Store filename in item.
item["screenshot_filename"] = filename
return item
重複チェック¶
A filter that looks for duplicate items, and drops those items that were already processed. Let’s say that our items have a unique id, but our spider returns multiples items with the same id:
from scrapy.exceptions import DropItem
class DuplicatesPipeline(object):
def __init__(self):
self.ids_seen = set()
def process_item(self, item, spider):
if item['id'] in self.ids_seen:
raise DropItem("Duplicate item found: %s" % item)
else:
self.ids_seen.add(item['id'])
return item
アイテムパイプラインコンポーネントの有効化¶
To activate an Item Pipeline component you must add its class to the
ITEM_PIPELINES
setting, like in the following example:
ITEM_PIPELINES = {
'myproject.pipelines.PricePipeline': 300,
'myproject.pipelines.JsonWriterPipeline': 800,
}
The integer values you assign to classes in this setting determine the order in which they run: items go through from lower valued to higher valued classes. It’s customary to define these numbers in the 0-1000 range.
フィードのエクスポート¶
バージョン 0.10 で追加.
One of the most frequently required features when implementing scrapers is being able to store the scraped data properly and, quite often, that means generating an “export file” with the scraped data (commonly called “export feed”) to be consumed by other systems.
Scrapy provides this functionality out of the box with the Feed Exports, which allows you to generate a feed with the scraped items, using multiple serialization formats and storage backends.
シリアライズフォーマット¶
For serializing the scraped data, the feed exports use the Item exporters. These formats are supported out of the box:
But you can also extend the supported format through the
FEED_EXPORTERS
setting.
JSON¶
FEED_FORMAT
:json
- Exporter used:
JsonItemExporter
- See this warning if you’re using JSON with large feeds.
JSON lines¶
FEED_FORMAT
:jsonlines
- Exporter used:
JsonLinesItemExporter
CSV¶
FEED_FORMAT
:csv
- Exporter used:
CsvItemExporter
- To specify columns to export and their order use
FEED_EXPORT_FIELDS
. Other feed exporters can also use this option, but it is important for CSV because unlike many other export formats CSV uses a fixed header.
XML¶
FEED_FORMAT
:xml
- Exporter used:
XmlItemExporter
Pickle¶
FEED_FORMAT
:pickle
- Exporter used:
PickleItemExporter
Marshal¶
FEED_FORMAT
:marshal
- Exporter used:
MarshalItemExporter
ストレージ¶
When using the feed exports you define where to store the feed using a URI
(through the FEED_URI
setting). The feed exports supports multiple
storage backend types which are defined by the URI scheme.
The storages backends supported out of the box are:
Some storage backends may be unavailable if the required external libraries are not available. For example, the S3 backend is only available if the botocore or boto library is installed (Scrapy supports boto only on Python 2).
ストレージURIパラメータ¶
The storage URI can also contain parameters that get replaced when the feed is being created. These parameters are:
%(time)s
- gets replaced by a timestamp when the feed is being created%(name)s
- gets replaced by the spider name
Any other named parameter gets replaced by the spider attribute of the same
name. For example, %(site_id)s
would get replaced by the spider.site_id
attribute the moment the feed is being created.
Here are some examples to illustrate:
- Store in FTP using one directory per spider:
ftp://user:password@ftp.example.com/scraping/feeds/%(name)s/%(time)s.json
- Store in S3 using one directory per spider:
s3://mybucket/scraping/feeds/%(name)s/%(time)s.json
バックエンドストレージ¶
ローカルファイルシステム¶
The feeds are stored in the local filesystem.
- URI scheme:
file
- Example URI:
file:///tmp/export.csv
- Required external libraries: none
Note that for the local filesystem storage (only) you can omit the scheme if
you specify an absolute path like /tmp/export.csv
. This only works on Unix
systems though.
FTP¶
The feeds are stored in a FTP server.
- URI scheme:
ftp
- Example URI:
ftp://user:pass@ftp.example.com/path/to/export.csv
- Required external libraries: none
S3¶
The feeds are stored on Amazon S3.
The AWS credentials can be passed as user/password in the URI, or they can be passed through the following settings:
標準出力¶
The feeds are written to the standard output of the Scrapy process.
- URI scheme:
stdout
- Example URI:
stdout:
- Required external libraries: none
設定¶
These are the settings used for configuring the feed exports:
FEED_URI¶
Default: None
The URI of the export feed. See バックエンドストレージ for supported URI schemes.
This setting is required for enabling the feed exports.
FEED_FORMAT¶
The serialization format to be used for the feed. See シリアライズフォーマット for possible values.
FEED_EXPORT_ENCODING¶
Default: None
The encoding to be used for the feed.
If unset or set to None
(default) it uses UTF-8 for everything except JSON output,
which uses safe numeric encoding (\uXXXX
sequences) for historic reasons.
Use utf-8
if you want UTF-8 for JSON too.
FEED_EXPORT_FIELDS¶
Default: None
A list of fields to export, optional.
Example: FEED_EXPORT_FIELDS = ["foo", "bar", "baz"]
.
Use FEED_EXPORT_FIELDS option to define fields to export and their order.
When FEED_EXPORT_FIELDS is empty or None (default), Scrapy uses fields
defined in dicts or Item
subclasses a spider is yielding.
If an exporter requires a fixed set of fields (this is the case for CSV export format) and FEED_EXPORT_FIELDS is empty or None, then Scrapy tries to infer field names from the exported data - currently it uses field names from the first item.
FEED_STORAGES¶
Default: {}
A dict containing additional feed storage backends supported by your project. The keys are URI schemes and the values are paths to storage classes.
FEED_STORAGES_BASE¶
Default:
{
'': 'scrapy.extensions.feedexport.FileFeedStorage',
'file': 'scrapy.extensions.feedexport.FileFeedStorage',
'stdout': 'scrapy.extensions.feedexport.StdoutFeedStorage',
's3': 'scrapy.extensions.feedexport.S3FeedStorage',
'ftp': 'scrapy.extensions.feedexport.FTPFeedStorage',
}
A dict containing the built-in feed storage backends supported by Scrapy. You
can disable any of these backends by assigning None
to their URI scheme in
FEED_STORAGES
. E.g., to disable the built-in FTP storage backend
(without replacement), place this in your settings.py
:
FEED_STORAGES = {
'ftp': None,
}
FEED_EXPORTERS¶
Default: {}
A dict containing additional exporters supported by your project. The keys are serialization formats and the values are paths to Item exporter classes.
FEED_EXPORTERS_BASE¶
Default:
{
'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',
}
A dict containing the built-in feed exporters supported by Scrapy. You can
disable any of these exporters by assigning None
to their serialization
format in FEED_EXPORTERS
. E.g., to disable the built-in CSV exporter
(without replacement), place this in your settings.py
:
FEED_EXPORTERS = {
'csv': None,
}
リクエストとレスポンス¶
Scrapy uses Request
and Response
objects for crawling web
sites.
Typically, Request
objects are generated in the spiders and pass
across the system until they reach the Downloader, which executes the request
and returns a Response
object which travels back to the spider that
issued the request.
Both Request
and Response
classes have subclasses which add
functionality not required in the base classes. These are described
below in Request subclasses and
Response サブクラス.
Request オブジェクト¶
-
class
scrapy.http.
Request
(url[, callback, method='GET', headers, body, cookies, meta, encoding='utf-8', priority=0, dont_filter=False, errback])¶ A
Request
object represents an HTTP request, which is usually generated in the Spider and executed by the Downloader, and thus generating aResponse
.パラメータ: - url (string) – the URL of this request
- callback (callable) – the function that will be called with the response of this
request (once its downloaded) as its first parameter. For more information
see 追加データをコールバック関数に渡す below.
If a Request doesn’t specify a callback, the spider’s
parse()
method will be used. Note that if exceptions are raised during processing, errback is called instead. - method (string) – the HTTP method of this request. Defaults to
'GET'
. - meta (dict) – the initial values for the
Request.meta
attribute. If given, the dict passed in this parameter will be shallow copied. - body (str or unicode) – the request body. If a
unicode
is passed, then it’s encoded tostr
using the encoding passed (which defaults toutf-8
). Ifbody
is not given, an empty string is stored. Regardless of the type of this argument, the final value stored will be astr
(neverunicode
orNone
). - headers (dict) – the headers of this request. The dict values can be strings
(for single valued headers) or lists (for multi-valued headers). If
None
is passed as value, the HTTP header will not be sent at all. - cookies (dict or list) –
the request cookies. These can be sent in two forms.
- Using a dict:
request_with_cookies = Request(url="http://www.example.com", cookies={'currency': 'USD', 'country': 'UY'})
- Using a list of dicts:
request_with_cookies = Request(url="http://www.example.com", cookies=[{'name': 'currency', 'value': 'USD', 'domain': 'example.com', 'path': '/currency'}])
The latter form allows for customizing the
domain
andpath
attributes of the cookie. This is only useful if the cookies are saved for later requests.When some site returns cookies (in a response) those are stored in the cookies for that domain and will be sent again in future requests. That’s the typical behaviour of any regular web browser. However, if, for some reason, you want to avoid merging with existing cookies you can instruct Scrapy to do so by setting the
dont_merge_cookies
key to True in theRequest.meta
.Example of request without merging cookies:
request_with_cookies = Request(url="http://www.example.com", cookies={'currency': 'USD', 'country': 'UY'}, meta={'dont_merge_cookies': True})
For more info see CookiesMiddleware.
- Using a dict:
- encoding (string) – the encoding of this request (defaults to
'utf-8'
). This encoding will be used to percent-encode the URL and to convert the body tostr
(if given asunicode
). - priority (int) – the priority of this request (defaults to
0
). The priority is used by the scheduler to define the order used to process requests. Requests with a higher priority value will execute earlier. Negative values are allowed in order to indicate relatively low-priority. - dont_filter (boolean) – indicates that this request should not be filtered by
the scheduler. This is used when you want to perform an identical
request multiple times, to ignore the duplicates filter. Use it with
care, or you will get into crawling loops. Default to
False
. - errback (callable) – a function that will be called if any exception was raised while processing the request. This includes pages that failed with 404 HTTP errors and such. It receives a Twisted Failure instance as first parameter. For more information, see エラー処理を使用して要求処理で例外を捕捉する below.
-
url
¶ A string containing the URL of this request. Keep in mind that this attribute contains the escaped URL, so it can differ from the URL passed in the constructor.
This attribute is read-only. To change the URL of a Request use
replace()
.
-
method
¶ A string representing the HTTP method in the request. This is guaranteed to be uppercase. Example:
"GET"
,"POST"
,"PUT"
, etc
-
headers
¶ A dictionary-like object which contains the request headers.
-
body
¶ A str that contains the request body.
This attribute is read-only. To change the body of a Request use
replace()
.
-
meta
¶ A dict that contains arbitrary metadata for this request. This dict is empty for new Requests, and is usually populated by different Scrapy components (extensions, middlewares, etc). So the data contained in this dict depends on the extensions you have enabled.
See Request.meta 特殊キー for a list of special meta keys recognized by Scrapy.
This dict is shallow copied when the request is cloned using the
copy()
orreplace()
methods, and can also be accessed, in your spider, from theresponse.meta
attribute.
-
copy
()¶ Return a new Request which is a copy of this Request. See also: 追加データをコールバック関数に渡す.
-
replace
([url, method, headers, body, cookies, meta, encoding, dont_filter, callback, errback])¶ Return a Request object with the same members, except for those members given new values by whichever keyword arguments are specified. The attribute
Request.meta
is copied by default (unless a new value is given in themeta
argument). See also 追加データをコールバック関数に渡す.
追加データをコールバック関数に渡す¶
The callback of a request is a function that will be called when the response
of that request is downloaded. The callback function will be called with the
downloaded Response
object as its first argument.
Example:
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)
In some cases you may be interested in passing arguments to those callback
functions so you can receive the arguments later, in the second callback. You
can use the Request.meta
attribute for that.
Here’s an example of how to pass an item using this mechanism, to populate different fields from different pages:
def parse_page1(self, response):
item = MyItem()
item['main_url'] = response.url
request = scrapy.Request("http://www.example.com/some_page.html",
callback=self.parse_page2)
request.meta['item'] = item
return request
def parse_page2(self, response):
item = response.meta['item']
item['other_url'] = response.url
return item
エラー処理を使用して要求処理で例外を捕捉する¶
The errback of a request is a function that will be called when an exception is raise while processing it.
It receives a Twisted Failure instance as first parameter and can be used to track connection establishment timeouts, DNS errors etc.
Here’s an example spider logging all errors and catching some specific errors if needed:
import scrapy
from scrapy.spidermiddlewares.httperror import HttpError
from twisted.internet.error import DNSLookupError
from twisted.internet.error import TimeoutError, TCPTimedOutError
class ErrbackSpider(scrapy.Spider):
name = "errback_example"
start_urls = [
"http://www.httpbin.org/", # HTTP 200 expected
"http://www.httpbin.org/status/404", # Not found error
"http://www.httpbin.org/status/500", # server issue
"http://www.httpbin.org:12345/", # non-responding host, timeout expected
"http://www.httphttpbinbin.org/", # DNS error expected
]
def start_requests(self):
for u in self.start_urls:
yield scrapy.Request(u, callback=self.parse_httpbin,
errback=self.errback_httpbin,
dont_filter=True)
def parse_httpbin(self, response):
self.logger.info('Got successful response from {}'.format(response.url))
# do something useful here...
def errback_httpbin(self, failure):
# log all failures
self.logger.error(repr(failure))
# in case you want to do something special for some errors,
# you may need the failure's type:
if failure.check(HttpError):
# these exceptions come from HttpError spider middleware
# you can get the non-200 response
response = failure.value.response
self.logger.error('HttpError on %s', response.url)
elif failure.check(DNSLookupError):
# this is the original request
request = failure.request
self.logger.error('DNSLookupError on %s', request.url)
elif failure.check(TimeoutError, TCPTimedOutError):
request = failure.request
self.logger.error('TimeoutError on %s', request.url)
Request.meta 特殊キー¶
The Request.meta
attribute can contain any arbitrary data, but there
are some special keys recognized by Scrapy and its built-in extensions.
Those are:
dont_redirect
dont_retry
handle_httpstatus_list
handle_httpstatus_all
dont_merge_cookies
(seecookies
parameter ofRequest
constructor)cookiejar
dont_cache
redirect_urls
bindaddress
dont_obey_robotstxt
download_timeout
download_maxsize
download_latency
proxy
bindaddress¶
The IP of the outgoing IP address to use for the performing the request.
download_timeout¶
The amount of time (in secs) that the downloader will wait before timing out.
See also: DOWNLOAD_TIMEOUT
.
download_latency¶
The amount of time spent to fetch the response, since the request has been started, i.e. HTTP message sent over the network. This meta key only becomes available when the response has been downloaded. While most other meta keys are used to control Scrapy behavior, this one is supposed to be read-only.
Request subclasses¶
Here is the list of built-in Request
subclasses. You can also subclass
it to implement your own custom functionality.
FormRequest objects¶
The FormRequest class extends the base Request
with functionality for
dealing with HTML forms. It uses lxml.html forms to pre-populate form
fields with form data from Response
objects.
-
class
scrapy.http.
FormRequest
(url[, formdata, ...])¶ The
FormRequest
class adds a new argument to the constructor. The remaining arguments are the same as for theRequest
class and are not documented here.パラメータ: formdata (dict or iterable of tuples) – is a dictionary (or iterable of (key, value) tuples) containing HTML Form data which will be url-encoded and assigned to the body of the request. The
FormRequest
objects support the following class method in addition to the standardRequest
methods:-
classmethod
from_response
(response[, formname=None, formnumber=0, formdata=None, formxpath=None, formcss=None, clickdata=None, dont_click=False, ...])¶ Returns a new
FormRequest
object with its form field values pre-populated with those found in the HTML<form>
element contained in the given response. For an example see FormRequest.from_response()を使用してユーザーログインをシミュレートする.The policy is to automatically simulate a click, by default, on any form control that looks clickable, like a
<input type="submit">
. Even though this is quite convenient, and often the desired behaviour, sometimes it can cause problems which could be hard to debug. For example, when working with forms that are filled and/or submitted using javascript, the defaultfrom_response()
behaviour may not be the most appropriate. To disable this behaviour you can set thedont_click
argument toTrue
. Also, if you want to change the control clicked (instead of disabling it) you can also use theclickdata
argument.パラメータ: - response (
Response
object) – the response containing a HTML form which will be used to pre-populate the form fields - formname (string) – if given, the form with name attribute set to this value will be used.
- formxpath (string) – if given, the first form that matches the xpath will be used.
- formcss (string) – if given, the first form that matches the css selector will be used.
- formnumber (integer) – the number of form to use, when the response contains
multiple forms. The first one (and also the default) is
0
. - formdata (dict) – fields to override in the form data. If a field was
already present in the response
<form>
element, its value is overridden by the one passed in this parameter. - clickdata (dict) – attributes to lookup the control clicked. If it’s not
given, the form data will be submitted simulating a click on the
first clickable element. In addition to html attributes, the control
can be identified by its zero-based index relative to other
submittable inputs inside the form, via the
nr
attribute. - dont_click (boolean) – If True, the form data will be submitted without clicking in any element.
The other parameters of this class method are passed directly to the
FormRequest
constructor.バージョン 0.10.3 で追加: The
formname
parameter.バージョン 0.17 で追加: The
formxpath
parameter.バージョン 1.1.0 で追加: The
formcss
parameter.- response (
-
classmethod
Request 使用例¶
FormRequestを使用したHTTP POSTによるデータの送信¶
If you want to simulate a HTML Form POST in your spider and send a couple of
key-value fields, you can return a FormRequest
object (from your
spider) like this:
return [FormRequest(url="http://www.example.com/post/action",
formdata={'name': 'John Doe', 'age': '27'},
callback=self.after_post)]
FormRequest.from_response()を使用してユーザーログインをシミュレートする¶
It is usual for web sites to provide pre-populated form fields through <input
type="hidden">
elements, such as session related data or authentication
tokens (for login pages). When scraping, you’ll want these fields to be
automatically pre-populated and only override a couple of them, such as the
user name and password. You can use the FormRequest.from_response()
method for this job. Here’s an example spider which uses it:
import scrapy
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):
# check login succeed before going on
if "authentication failed" in response.body:
self.logger.error("Login failed")
return
# continue scraping with authenticated session...
Response オブジェクト¶
-
class
scrapy.http.
Response
(url[, status=200, headers=None, body=b'', flags=None, request=None])¶ A
Response
object represents an HTTP response, which is usually downloaded (by the Downloader) and fed to the Spiders for processing.パラメータ: - url (string) – the URL of this response
- status (integer) – the HTTP status of the response. Defaults to
200
. - headers (dict) – the headers of this response. The dict values can be strings (for single valued headers) or lists (for multi-valued headers).
- body (str) – the response body. It must be str, not unicode, unless you’re
using a encoding-aware Response subclass, such as
TextResponse
. - flags (list) – is a list containing the initial values for the
Response.flags
attribute. If given, the list will be shallow copied. - request (
Request
object) – the initial value of theResponse.request
attribute. This represents theRequest
that generated this response.
-
url
¶ A string containing the URL of the response.
This attribute is read-only. To change the URL of a Response use
replace()
.
-
status
¶ An integer representing the HTTP status of the response. Example:
200
,404
.
-
headers
¶ A dictionary-like object which contains the response headers. Values can be accessed using
get()
to return the first header value with the specified name orgetlist()
to return all header values with the specified name. For example, this call will give you all cookies in the headers:response.headers.getlist('Set-Cookie')
-
body
¶ The body of this Response. Keep in mind that Response.body is always a bytes object. If you want the unicode version use
TextResponse.text
(only available inTextResponse
and subclasses).This attribute is read-only. To change the body of a Response use
replace()
.
-
request
¶ The
Request
object that generated this response. This attribute is assigned in the Scrapy engine, after the response and the request have passed through all Downloader Middlewares. In particular, this means that:- HTTP redirections will cause the original request (to the URL before redirection) to be assigned to the redirected response (with the final URL after redirection).
- Response.request.url doesn’t always equal Response.url
- This attribute is only available in the spider code, and in the
Spider Middlewares, but not in
Downloader Middlewares (although you have the Request available there by
other means) and handlers of the
response_downloaded
signal.
-
meta
¶ A shortcut to the
Request.meta
attribute of theResponse.request
object (ie.self.request.meta
).Unlike the
Response.request
attribute, theResponse.meta
attribute is propagated along redirects and retries, so you will get the originalRequest.meta
sent from your spider.参考
Request.meta
attribute
-
flags
¶ A list that contains flags for this response. Flags are labels used for tagging Responses. For example: ‘cached’, ‘redirected‘, etc. And they’re shown on the string representation of the Response (__str__ method) which is used by the engine for logging.
-
copy
()¶ Returns a new Response which is a copy of this Response.
-
replace
([url, status, headers, body, request, flags, cls])¶ Returns a Response object with the same members, except for those members given new values by whichever keyword arguments are specified. The attribute
Response.meta
is copied by default.
-
urljoin
(url)¶ Constructs an absolute url by combining the Response’s
url
with a possible relative url.This is a wrapper over urlparse.urljoin, it’s merely an alias for making this call:
urlparse.urljoin(response.url, url)
Response サブクラス¶
Here is the list of available built-in Response subclasses. You can also subclass the Response class to implement your own functionality.
TextResponse オブジェクト¶
-
class
scrapy.http.
TextResponse
(url[, encoding[, ...]])¶ TextResponse
objects adds encoding capabilities to the baseResponse
class, which is meant to be used only for binary data, such as images, sounds or any media file.TextResponse
objects support a new constructor argument, in addition to the baseResponse
objects. The remaining functionality is the same as for theResponse
class and is not documented here.パラメータ: encoding (string) – is a string which contains the encoding to use for this response. If you create a TextResponse
object with a unicode body, it will be encoded using this encoding (remember the body attribute is always a string). Ifencoding
isNone
(default value), the encoding will be looked up in the response headers and body instead.TextResponse
objects support the following attributes in addition to the standardResponse
ones:-
text
¶ Response body, as unicode.
The same as
response.body.decode(response.encoding)
, but the result is cached after the first call, so you can accessresponse.text
multiple times without extra overhead.注釈
unicode(response.body)
is not a correct way to convert response body to unicode: you would be using the system default encoding (typically ascii) instead of the response encoding.
-
encoding
¶ A string with the encoding of this response. The encoding is resolved by trying the following mechanisms, in order:
- the encoding passed in the constructor encoding argument
- the encoding declared in the Content-Type HTTP header. If this encoding is not valid (ie. unknown), it is ignored and the next resolution mechanism is tried.
- the encoding declared in the response body. The TextResponse class
doesn’t provide any special functionality for this. However, the
HtmlResponse
andXmlResponse
classes do. - the encoding inferred by looking at the response body. This is the more fragile method but also the last one tried.
-
selector
¶ A
Selector
instance using the response as target. The selector is lazily instantiated on first access.
TextResponse
objects support the following methods in addition to the standardResponse
ones:-
xpath
(query)¶ A shortcut to
TextResponse.selector.xpath(query)
:response.xpath('//p')
-
css
(query)¶ A shortcut to
TextResponse.selector.css(query)
:response.css('p')
-
HtmlResponse オブジェクト¶
-
class
scrapy.http.
HtmlResponse
(url[, ...])¶ The
HtmlResponse
class is a subclass ofTextResponse
which adds encoding auto-discovering support by looking into the HTML meta http-equiv attribute. SeeTextResponse.encoding
.
XmlResponse オブジェクト¶
-
class
scrapy.http.
XmlResponse
(url[, ...])¶ The
XmlResponse
class is a subclass ofTextResponse
which adds encoding auto-discovering support by looking into the XML declaration line. SeeTextResponse.encoding
.
LinkExtractor¶
LinkExtractorは, 最終的に追跡されるウェブページ (scrapy.http.Response
オブジェクト) からリンクを抽出することのみを目的とするオブジェクトです.
scrapy.linkextractors import LinkExtractor
によって Scrapy で有効化されますが, シンプルなインターフェースを実装することで, 独自のカスタム LinkExtractor を作成してニーズに合わせることができます.
すべてのリンク抽出プログラムが持つ唯一のパブリックメソッドは extract_links
です.
これは, Response
オブジェクトを受け取り
scrapy.link.Link
オブジェクトのリストを返します.
LinkExtractor は一度インスタンス化されることを意図されており, extract_links
メソッドは異なる応答で数回呼び出され, 続くリンクを抽出します.
LinkExtractor は, 一連のルールを通じて CrawlSpider
クラス (Scrapyで利用可能) で使用されますが,
CrawlSpider
からサブクラス化しない場合でも、スパイダーで使用することができます.
ビルトイン LinkExtractor リファレンス¶
Scrapy にバンドルされたリンク抽出クラスは,
scrapy.linkextractors
モジュールとして提供されています.
デフォルトのリンク抽出プログラムは LinkExtractor
で,
LxmlLinkExtractor
と同じです:
from scrapy.linkextractors import LinkExtractor
古いScrapyバージョンでは他のリンク抽出クラスが使用されていましたが, 現在は推奨されていません.
LxmlLinkExtractor¶
-
class
scrapy.linkextractors.lxmlhtml.
LxmlLinkExtractor
(allow=(), deny=(), allow_domains=(), deny_domains=(), deny_extensions=None, restrict_xpaths=(), restrict_css=(), tags=('a', 'area'), attrs=('href', ), canonicalize=True, unique=True, process_value=None)¶ LxmlLinkExtractor は, 便利なフィルタリングオプションを備えた推奨リンク抽出ツールです. lxmlの堅牢なHTMLパーサーを使用して実装されています.
パラメータ: - allow (正規表現(またはそのリスト)) – リンクを抽出するために(絶対)URLが一致しなければならない単一の正規表現(または正規表現のリスト). 指定されていない(または空)場合, すべてのリンクに一致します.
- deny (正規表現(またはそのリスト)) – 除外する(絶対)URLが一致しなければならない(つまり抽出されない)単一の正規表現(または正規表現のリスト).
これは,
allow
パラメータよりも優先されます. 指定されていない場合(または空の場合), リンクを除外しません. - allow_domains (文字列またはリスト) – リンクを抽出するために考慮されるドメインを含む文字列の単一の値, またはリスト.
- deny_domains (文字列またはリスト) – リンクを抽出するために考慮されないドメインを含む文字列の単一の値、またはリスト.
- deny_extensions (リスト) – リンクを抽出するときに無視すべき拡張子を含む単一の値または文字列のリスト.
指定されていない場合は, scrapy.linkextractors パッケージで定義されている
IGNORED_EXTENSIONS
のデフォルト値になります. - restrict_xpaths (文字列またはリスト) – は, XPath(またはXPathのリスト)であり, そこからリンクを抽出する応答内の領域を定義します. 指定すると, それらのXPathによって選択されたテキストのみがリンクのためにスキャンされます. 下記の例を参照してください.
- restrict_css (文字列またはリスト) – リンクの抽出元となる応答内の領域を定義するCSSセレクタ(またはセレクタのリスト).
restrict_xpaths
と同じ動作をします. - tags (文字列またはリスト) – リンクを抽出するときに考慮するタグまたはタグのリスト. デフォルトは
('a', 'area')
タグです. - attrs (リスト) – 抽出するリンクを探すときに考慮する属性または属性のリスト(
tags
パラメータで指定されたタグのみ). デフォルトは('href')
属性です. - canonicalize (boolean) – 抽出された各URLを正規化します (w3lib.url.canonicalize_urlを使用). デフォルトは
True
です. - unique (boolean) – 抽出されたリンクに重複フィルタリングを適用するかどうか.
- process_value (callable) –
タグから抽出された各値とスキャンされた属性を受け取り, 値を修正して新しい値を返す, または
None
を返してリンクを完全に無視する関数. 指定されていない場合,process_value
のデフォルトはlambda x: x
です.たとえば, このコードからリンクを抽出するには:
<a href="javascript:goToPage('../other/page.html'); return false">Link text</a>
process_value
で次の関数を使用することができます:def process_value(value): m = re.search("javascript:goToPage\('(.*?)'", value) if m: return m.group(1)
設定¶
Scrapyの設定では, コア, 拡張機能, パイプライン, スパイダー自体を含むすべての Scrapy コンポーネントの動作をカスタマイズすることができます.
設定のインフラストラクチャは, コードで値を取得するために使用できる, キーと値のマッピングのグローバルな名前空間を提供します. この設定は, 以下で説明するさまざまなメカニズムによって設定できます.
この設定は, 現在アクティブなScrapyプロジェクトを選択するためのメカニズムでもあります.
使用可能なビルトイン設定のリストについては, ビルトイン設定リファレンス を参照してください.
設定を指定する¶
Scrapyを使用するときは, 環境変数 SCRAPY_SETTINGS_MODULE
を使用して, 設定を Scrapy に教えてください.
SCRAPY_SETTINGS_MODULE
の値はPythonのパス構文でなければなりません, e.g.
myproject.settings
. 設定モジュールは, Pythonの インポートサーチパス 上にある必要があります.
設定を入力する¶
設定は, それぞれ異なる優先順位を持つ異なるメカニズムを使用しています. 以下は優先順位の高い順にリストされています:
- コマンドラインオプション(優先度高)
- スパイダーごとの設定
- プロジェクト設定モジュール
- コマンドごとのデフォルト設定
- デフォルトのグローバル設定(優先度低)
これら設定の優先度は内部的に処理されますが, 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
モジュールにあり, ビルトイン設定リファレンス に記載されています.
設定にアクセスする方法¶
スパイダーでは, 設定は self.settings
で取得することができます:
class MySpider(scrapy.Spider):
name = 'myspider'
start_urls = ['http://example.com']
def parse(self, response):
print("Existing settings: %s" % self.settings.attributes.keys())
注釈
settings
属性は, スパイダーが初期化された後,
ベース Spider クラスに設定されます.
初期化の前に設定を使用する場合(たとえば, スパイダーの __init__()
メソッド),
from_crawler()
メソッドをオーバーライドする必要があります.
設定は, 拡張機能, ミドルウェアおよびアイテムパイプラインの from_crawler
メソッドに渡される,
クローラの scrapy.crawler.Crawler.settings
属性を介してアクセスできます.
class MyExtension(object):
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'))
設定オブジェクトは dict'' (例: ``settings['LOG_ENABLED']
) のように使用できますが,
Settings
API で提供されるメソッドの1つを使用して,
タイプエラーを回避するために必要な形式で設定を抽出することをお勧めします.
名前を設定する理由¶
設定名には通常, 構成するコンポーネントの接頭辞が付いています.
例えば, 架空の robots.txt
拡張子の適切な設定名は
ROBOTSTXT_ENABLED
, ROBOTSTXT_OBEY
, ROBOTSTXT_CACHEDIR
などです.
ビルトイン設定リファレンス¶
ここでは, アルファベット順に使用可能なすべての Scrapy 設定のリストと, デフォルト値, 適用されるスコープが示されています.
使用可能な場合スコープは, 特定のコンポーネントに関連付けられていれば, 設定が使用されている場所を示します. その場合, そのコンポーネントのモジュール, 通常は拡張モジュール, ミドルウェアまたはパイプラインが表示されます. また, 設定を有効にするためにコンポーネントを有効にする必要があることも意味します.
AWS_ACCESS_KEY_ID¶
デフォルト: None
S3フィードストレージバックエンド など, Amazon Web services のアクセスを必要とするコードで使用されるAWSアクセスキー.
AWS_SECRET_ACCESS_KEY¶
デフォルト: None
S3フィードストレージバックエンド など, Amazon Web services へのアクセスを必要とするコードで使用されるAWS秘密鍵.
BOT_NAME¶
デフォルト: 'scrapybot'
このScrapyプロジェクトによって実装されたボットの名前(プロジェクト名とも呼ばれます). これは, デフォルトで User-Agent, ロギングに使用されます.
startproject
コマンドを使用してプロジェクトを作成すると, プロジェクト名が自動的に入力されます.
CONCURRENT_REQUESTS_PER_DOMAIN¶
デフォルト: 8
単一のドメインに対して実行される並行(つまり同時)リクエストの最大数.
AutoThrottle 拡張機能 と
AUTOTHROTTLE_TARGET_CONCURRENCY
オプションも参照してください.
CONCURRENT_REQUESTS_PER_IP¶
デフォルト: 0
単一の IP に対して実行される並行(つまり同時)要求の最大数.
0以外の場合, CONCURRENT_REQUESTS_PER_DOMAIN
設定は無視され,
代わりにこの設定が使用されます. つまり, ドメインごとではなく, IPごとに並行処理の制限が適用されます.
この設定は, DOWNLOAD_DELAY
及び
AutoThrottle 拡張機能: にも影響します. CONCURRENT_REQUESTS_PER_IP
がゼロ以外の場合, ドメインごとではなくIPごとにダウンロード遅延が強制されます.
DEFAULT_REQUEST_HEADERS¶
デフォルト:
{
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language': 'en',
}
Scrapy HTTP Request に使用されるデフォルトのヘッダー. これらは,
DefaultHeadersMiddleware
に設定されています.
DEPTH_LIMIT¶
デフォルト: 0
スコープ: scrapy.spidermiddlewares.depth.DepthMiddleware
どのサイトでもクロールできる最大の深さ. ゼロの場合, 制限は課されません.
DEPTH_PRIORITY¶
デフォルト: 0
スコープ: scrapy.spidermiddlewares.depth.DepthMiddleware
深さに基づいてリクエストの優先度を調整するために使用される整数:
- 0(デフォルト)の場合, 深度からの優先調整は行われません
- 正の値は優先度を下げます. つまり, 深度の高い要求が後で処理されます. これは, 幅優先のクロール(BFO)を行うときによく使用されます
- 負の値は優先度を増加させます. すなわち, より深い深度要求がより早く処理されます(DFO)
BFO または DFO のチューニングに関しては Scrapyは幅優先, 深さ優先どちらでクロールしますか? を参照してください.
注釈
この設定は, 他の優先度設定である REDIRECT_PRIORITY_ADJUST
及び RETRY_PRIORITY_ADJUST
と比較して, 優先度を調整します.
DEPTH_STATS_VERBOSE¶
デフォルト: False
スコープ: scrapy.spidermiddlewares.depth.DepthMiddleware
冗長な深さ統計を収集するかどうか. これを有効にすると, 各深さのリクエスト数が統計情報に収集されます.
DOWNLOADER_HTTPCLIENTFACTORY¶
デフォルト: 'scrapy.core.downloader.webclient.ScrapyHTTPClientFactory'
HTTP / 1.0接続( HTTP10DownloadHandler
の場合)に使用する,
Twisted の protocol.ClientFactory
クラスを定義します.
注釈
Twisted < 11.1 を使用しない限り, HTTP/1.0 は今日めったに使われないので, この設定を無視しても問題ありません.
HTTP/1.0 を使用し, http(s)
スキームに応じて DOWNLOAD_HANDLERS_BASE
をオーバーライドする,
すなわち 'scrapy.core.downloader.handlers.http.HTTP10DownloadHandler'
.
DOWNLOADER_CLIENTCONTEXTFACTORY¶
デフォルト: 'scrapy.core.downloader.contextfactory.ScrapyClientContextFactory'
使用する ContextFactory へのクラスパスを表します.
ContextFactory は, SSL / TLS コンテキストの Twisted の用語で, 使用するTLS / SSLプロトコルのバージョン, 証明書の検証の有無, クライアント側の認証(およびその他のさまざまなもの)の有効化を定義します.
注釈
Scrapy のデフォルトコンテキストファクトリは, リモートサーバー証明書の検証を実行しません. これは, 通常のウェブスクレーピングでは問題ありません.
リモートサーバー証明書の検証が有効になっている必要がある場合は,
プラットフォームの証明書を使用してリモートエンドポイントを検証する
'scrapy.core.downloader.contextfactory.BrowserLikeContextFactory'
という別のコンテキストファクトリクラスを使用することもできます.
Twisted>=14.0. で使用することができます.
カスタム ContextFactory を使用する場合は,
init で method
パラメータを受け入れるようにしてください
(これは OpenSSL.SSL
メソッドの DOWNLOADER_CLIENT_TLS_METHOD
のマッピングです).
DOWNLOADER_CLIENT_TLS_METHOD¶
デフォルト: 'TLS'
この設定を使用して, デフォルトの HTTP/1.1 ダウンローダが使用する TLS/SSL 方式をカスタマイズします.
この設定は, これらの文字列値のいずれかでなければなりません:
'TLS'
: OpenSSLのTLS_method()
(a.k.aSSLv23_method()
), にマップされています. これにより, プラットフォームでサポートされている最高位から始まる プロトコルネゴシエーションが可能になります; デフォルト, 推奨'TLSv1.0'
: この値を指定すると, HTTPS接続はTLSバージョン1.0を使用します. Scrapy < 1.1 の動作が必要な場合にこれを設定します'TLSv1.1'
: TLS バージョン 1.1 を強制します'TLSv1.2'
: TLS バージョン 1.2 を強制します'SSLv3'
: SSL バージョン 3 を強制します (非推奨)
注釈
PyOpenSSL >= 0.13, Twisted >= 0.13 以上を使用することをお勧めします(出来れば Twisted> = 14.0).
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
を変更してください. 詳細については,
ダウンローダーミドルウェアの有効化 を参照してください.
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¶
デフォルト: {}
プロジェクトで有効になっているリクエストダウンローダーハンドラを含む dict
.
形式のサンプルについては 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 で有効になっているリクエストハンドラを含む dict
. プロジェクトでこの設定を変更しないでください. 代わりに
DOWNLOAD_HANDLERS
を変更してください.
これらのダウンロードハンドラのいずれかを無効にするには,
DOWNLOAD_HANDLERS
の URI スキームにNoneを割り当てます.
たとえば, 組み込みのFTPハンドラを無効にするには(置き換えずに), これを settings.py に記述子ます:
DOWNLOAD_HANDLERS = {
'ftp': None,
}
DOWNLOAD_TIMEOUT¶
デフォルト: 180
ダウンローダーがタイムアウトするまで待機する時間(秒単位).
注釈
このタイムアウトは, download_timeout
スパイダ属性と download_timeout
Request.meta キーを使用したリクエストごとに設定できます.
DOWNLOAD_MAXSIZE¶
デフォルト: 1073741824 (1024MB)
ダウンローダがダウンロードする最大応答サイズ(バイト単位).
無効にする場合は, 0に設定します.
注釈
このサイズは, download_maxsize
Request.metaキーを使用して,
download_maxsize
スパイダ属性とper-requestを使用してスパイダごとに設定できます.
この機能には Twisted >= 11.1 が必要です.
DOWNLOAD_WARNSIZE¶
デフォルト: 33554432 (32MB)
ダウンローダが警告を開始するレスポンスサイズ(バイト単位).
無効にする場合は, 0に設定します.
注釈
このサイズは, download_warnsize
Request.metaキーを使用して,
download_warnsize
スパイダ属性およびper-requestを使用してスパイダごとに設定できます.
これには, Twisted >= 11.1 が必要です.
DUPEFILTER_CLASS¶
デフォルト: 'scrapy.dupefilters.RFPDupeFilter'
重複リクエストを検出してフィルタリングするために使用されるクラス.
デフォルトのフィルタ (RFPDupeFilter
) は,
scrapy.utils.request.request_fingerprint
関数を使用してリクエストフィンガープリントに基づいてフィルタリングします.
重複をチェックする方法を変更するには, RFPDupeFilter
をサブクラス化し,
request_fingerprint
メソッドをオーバーライドすることができます.
このメソッドは Request
オブジェクトを受け入れ, そのフィンガープリント(文字列)を返す必要があります.
DUPEFILTER_DEBUG¶
デフォルト: False
デフォルトでは, RFPDupeFilter
は最初の重複要求のみを記録します.
DUPEFILTER_DEBUG
を True
に設定すると, すべての重複リクエストが記録されます.
EDITOR¶
デフォルト: 環境依存
edit
マンドでスパイダーを編集するために使用するエディター.
EDITOR
環境変数が設定されていると, デフォルトで使用されます.
それ以外の場合, デフォルトは vi
Unixシステムの場合)または IDLE エディター(Windowsの場合)になります.
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 のデフォルトで利用可能な拡張機能とそのオーダーを含む dict
.
この設定には, すべての安定したビルトイン拡張機能が含まれています.
そのうちのいくつかは設定によって有効にする必要があることに注意してください.
詳細については, 拡張機能ユーザーガイド 及び 使用可能な拡張機能の一覧 を参照してください.
FEED_TEMPDIR¶
Feed Temp ディレクトリでは, FTP フィードストレージ と Amazon S3 にアップロードする前に, クローラの一時ファイルを保存するカスタムフォルダを設定できます.
ITEM_PIPELINES¶
デフォルト: {}
使用するアイテムパイプラインとその注文を含む dict
.
順序値は任意ですが, 0〜1000の範囲で定義するのが通例です.
下位の注文は高次のオーダーの前に処理されます.
例:
ITEM_PIPELINES = {
'mybot.pipelines.validate.ValidateMyItem': 300,
'mybot.pipelines.validate.StoreMyItem': 800,
}
ITEM_PIPELINES_BASE¶
デフォルト: {}
Scrapy でデフォルトで有効になっているパイプラインを含む dict
.
プロジェクトでこの設定を変更しないでください.
代わりに ITEM_PIPELINES
を変更してください
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です. 詳細は ロギング を参照してください.
LOG_STDOUT¶
デフォルト: False
True
の場合, プロセスのすべての標準出力(およびエラー)がログにリダイレクトされます.
たとえば, print 'hello'
を実行すると, Scrapyログに表示されます.
MEMDEBUG_NOTIFY¶
デフォルト: []
メモリデバッグが有効になっている場合, この設定が空でなければ, 指定されたアドレスにメモリレポートが送信されます. そうでない場合, レポートはログに書き込まれます.
例:
MEMDEBUG_NOTIFY = ['user@example.com']
MEMUSAGE_ENABLED¶
デフォルト: False
スコープ: scrapy.extensions.memusage
メモリ使用量の拡張を有効にして, メモリ制限を超えた場合に Scrapy プロセスをシャットダウンするかどうか. また, その場合は電子メールで通知されます.
メモリ使用量拡張機能 を参照してください.
MEMUSAGE_LIMIT_MB¶
デフォルト: 0
スコープ: scrapy.extensions.memusage
(MEMUSAGE_ENABLEDがTrueの場合)Scrapy をシャットダウンする前に許容される メモリの最大量(メガバイト単位). ゼロの場合, チェックは実行されません.
メモリ使用量拡張機能 を参照してください.
MEMUSAGE_CHECK_INTERVAL_SECONDS¶
バージョン 1.1 で追加.
デフォルト: 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_REPORT¶
デフォルト: False
スコープ: scrapy.extensions.memusage
各スパイダーが閉じられた後にメモリ使用量レポートを送信するかどうか.
メモリ使用量拡張機能 を参照してください.
MEMUSAGE_WARNING_MB¶
デフォルト: 0
スコープ: scrapy.extensions.memusage
通知する警告電子メールを送信する前に許容されるメモリの最大量(メガバイト単位). ゼロの場合, 警告は生成されません.
NEWSPIDER_MODULE¶
デフォルト: ''
genspider
コマンドを使用して新しいスパイダーを作成する場所.
例:
NEWSPIDER_MODULE = 'mybot.spiders_dev'
RANDOMIZE_DOWNLOAD_DELAY¶
デフォルト: True
有効にすると, 同じWebサイトからリクエストを取得する間, Scrapyはランダムな時間
(0.5 * DOWNLOAD_DELAY
から 1.5 * DOWNLOAD_DELAY
の間まで)
待機します.
このランダム化は, リクエスト間の時間から統計的に有意な類似性を探し, リクエストを分析するサイトによってクローラが検出される(およびその後ブロックされる)可能性を低下させます.
ランダム化ポリシーは, wget --random-wait
オプションで使用されるものと同じです.
DOWNLOAD_DELAY
が 0(デフォルト)の場合, このオプションは無効です.
REACTOR_THREADPOOL_MAXSIZE¶
デフォルト: 10
Twisted Reactor スレッドプールサイズの最大限度. これは, さまざまな Scrapy コンポーネントで使用される汎用スレッドプールです. スレッド化された DNS リゾルバ, BlockingFeedStorage, S3 FilesStore などです. ブロッキング IO が不十分で問題が発生している場合は, この値を大きくしてください.
REDIRECT_MAX_TIMES¶
デフォルト: 20
要求をリダイレクトできる最大時間を定義します. この最大値の後, 要求の応答はそのまま返されます. 私達は, Firefoxのデフォルト値を同じタスクに使用しました.
REDIRECT_PRIORITY_ADJUST¶
デフォルト: +2
スコープ: scrapy.downloadermiddlewares.redirect.RedirectMiddleware
元のリクエストに対するリダイレクトリクエストの優先度を調整します.
- 正の優先度調整(デフォルト)はより高い優先度を意味します.
- 負の優先順位調整は低い優先順位を意味します.
RETRY_PRIORITY_ADJUST¶
デフォルト: -1
スコープ: scrapy.downloadermiddlewares.retry.RetryMiddleware
オリジナルのリクエストに対するリトライリクエストの優先度を調整する:
- 正の優先度調整はより高い優先度を意味します.
- 負の優先順位調整(デフォルト)は低い優先順位を意味します.
ROBOTSTXT_OBEY¶
デフォルト: False
スコープ: scrapy.downloadermiddlewares.robotstxt
有効にすると, Scrapy は robots.txt ポリシーを尊重します. 詳細については, RobotsTxtMiddleware を参照してください.
注釈
歴史的な理由からデフォルト値は False
ですが, このオプションは
scrapy startproject
コマンドで生成される settings.py ファイルではデフォルトで有効になっています.
SCHEDULER_DEBUG¶
デフォルト: False
True
に設定すると, 要求スケジューラに関するデバッグ情報が記録されます.
要求をディスクにシリアライズできない場合は, 現在ログに記録されます(1回のみ).
Stats カウンター (scheduler/unserializable
) は, これが発生する回数を追跡します.
ログのエントリ例:
1956-01-31 00:00:00+0800 [scrapy] 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.PickleFifoDiskQueue
, scrapy.squeues.MarshalFifoDiskQueue
,
scrapy.squeues.MarshalLifoDiskQueue
.
SCHEDULER_MEMORY_QUEUE¶
デフォルト: 'scrapy.squeues.LifoMemoryQueue'
スケジューラーが使用するインメモリー・キューのタイプ. その他の使用可能なタイプは,
scrapy.squeues.FifoMemoryQueue
です.
SPIDER_CONTRACTS¶
デフォルト:: {}
あなたのプロジェクトで有効にされたスパイダー契約を含む辞書. スパイダーのテストに使用されます. 詳細は スパイダーコントラクト を参照してください.
SPIDER_CONTRACTS_BASE¶
デフォルト:
{
'scrapy.contracts.default.UrlContract' : 1,
'scrapy.contracts.default.ReturnsContract': 2,
'scrapy.contracts.default.ScrapesContract': 3,
}
Scrapyでデフォルトで有効になっているコントラクトを含む辞書.
プロジェクトでこの設定を変更しないでください, SPIDER_CONTRACTS
を変更してください. 詳細は, スパイダーコントラクト を参照してください.
これらのコントラクトを無効にするには SPIDER_CONTRACTS
のクラスパスに None
を割り当ててください.
例えば, 組み込みの ScrapesContract
を無効にするには, settings.py
に, この様に記述します:
SPIDER_CONTRACTS = {
'scrapy.contracts.default.ScrapesContract': None,
}
SPIDER_LOADER_CLASS¶
デフォルト: 'scrapy.spiderloader.SpiderLoader'
スパイダーローダー API を実装する必要があるスパイダーのロードに使用されるクラス.
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¶
デフォルト: []
(empty list)
スパイダーがスクレイピングを終えた後, Scrapyの統計情報を送信します. 詳細は
StatsMailer
を参照してください.
TELNETCONSOLE_PORT¶
デフォルト: [6023, 6073]
Telnet コンソールに使用するポート範囲. None
または 0
を設定すると,
動的に割り当てられたポートが使用されます. 詳細については, Telnet コンソール を参照してください.
TEMPLATES_DIR¶
デフォルト: Scrapy モジュール内の templates
ディレクトリ
startproject
コマンドで新しいプロジェクトを作成するときにテンプレートを検索するディレクトリと,
genspider
コマンドで新しいスパイダーを検索するディレクトリ.
プロジェクト名は, プロジェクトサブディレクトリ内のカスタムファイルまたはディレクトリの名前と競合してはいけません.
URLLENGTH_LIMIT¶
デフォルト: 2083
スコープ: spidermiddlewares.urllength
クロールを許可するURLの最大長. この設定のデフォルト値の詳細については, http://www.boutell.com/newfaq/misc/urllength.html を参照してください.
USER_AGENT¶
デフォルト: "Scrapy/VERSION (+http://scrapy.org)"
オーバーライドされない限り, クロール時に使用されるデフォルトの User-Agent.
他の場所で文書化された設定:¶
次の設定は他の場所で文書化されています. それぞれのケースを確認して使用する方法を確認してください.
- AJAXCRAWL_ENABLED
- AUTOTHROTTLE_DEBUG
- AUTOTHROTTLE_ENABLED
- AUTOTHROTTLE_MAX_DELAY
- AUTOTHROTTLE_START_DELAY
- AUTOTHROTTLE_TARGET_CONCURRENCY
- AWS_ACCESS_KEY_ID
- AWS_SECRET_ACCESS_KEY
- BOT_NAME
- CLOSESPIDER_ERRORCOUNT
- CLOSESPIDER_ITEMCOUNT
- CLOSESPIDER_PAGECOUNT
- CLOSESPIDER_TIMEOUT
- COMMANDS_MODULE
- COMPRESSION_ENABLED
- CONCURRENT_ITEMS
- CONCURRENT_REQUESTS
- CONCURRENT_REQUESTS_PER_DOMAIN
- CONCURRENT_REQUESTS_PER_IP
- COOKIES_DEBUG
- COOKIES_ENABLED
- DEFAULT_ITEM_CLASS
- DEFAULT_REQUEST_HEADERS
- DEPTH_LIMIT
- DEPTH_PRIORITY
- DEPTH_STATS
- DEPTH_STATS_VERBOSE
- DNSCACHE_ENABLED
- DNSCACHE_SIZE
- DNS_TIMEOUT
- DOWNLOADER
- DOWNLOADER_CLIENTCONTEXTFACTORY
- DOWNLOADER_CLIENT_TLS_METHOD
- DOWNLOADER_HTTPCLIENTFACTORY
- DOWNLOADER_MIDDLEWARES
- DOWNLOADER_MIDDLEWARES_BASE
- DOWNLOADER_STATS
- DOWNLOAD_DELAY
- DOWNLOAD_HANDLERS
- DOWNLOAD_HANDLERS_BASE
- DOWNLOAD_MAXSIZE
- DOWNLOAD_TIMEOUT
- DOWNLOAD_WARNSIZE
- DUPEFILTER_CLASS
- DUPEFILTER_DEBUG
- EDITOR
- EXTENSIONS
- EXTENSIONS_BASE
- FEED_EXPORTERS
- FEED_EXPORTERS_BASE
- FEED_EXPORT_ENCODING
- FEED_EXPORT_FIELDS
- FEED_FORMAT
- FEED_STORAGES
- FEED_STORAGES_BASE
- FEED_STORE_EMPTY
- FEED_TEMPDIR
- FEED_URI
- FILES_EXPIRES
- FILES_RESULT_FIELD
- FILES_STORE
- FILES_STORE_S3_ACL
- FILES_URLS_FIELD
- HTTPCACHE_ALWAYS_STORE
- HTTPCACHE_DBM_MODULE
- HTTPCACHE_DIR
- HTTPCACHE_ENABLED
- HTTPCACHE_EXPIRATION_SECS
- HTTPCACHE_GZIP
- HTTPCACHE_IGNORE_HTTP_CODES
- HTTPCACHE_IGNORE_MISSING
- HTTPCACHE_IGNORE_RESPONSE_CACHE_CONTROLS
- HTTPCACHE_IGNORE_SCHEMES
- HTTPCACHE_POLICY
- HTTPCACHE_STORAGE
- HTTPERROR_ALLOWED_CODES
- HTTPERROR_ALLOW_ALL
- HTTPPROXY_AUTH_ENCODING
- IMAGES_EXPIRES
- IMAGES_MIN_HEIGHT
- IMAGES_MIN_WIDTH
- IMAGES_RESULT_FIELD
- IMAGES_STORE
- IMAGES_STORE_S3_ACL
- IMAGES_THUMBS
- IMAGES_URLS_FIELD
- ITEM_PIPELINES
- ITEM_PIPELINES_BASE
- LOG_DATEFORMAT
- LOG_ENABLED
- LOG_ENCODING
- LOG_FILE
- LOG_FORMAT
- LOG_LEVEL
- LOG_STDOUT
- MAIL_FROM
- MAIL_HOST
- MAIL_PASS
- MAIL_PORT
- MAIL_SSL
- MAIL_TLS
- MAIL_USER
- MEMDEBUG_ENABLED
- MEMDEBUG_NOTIFY
- MEMUSAGE_CHECK_INTERVAL_SECONDS
- MEMUSAGE_ENABLED
- MEMUSAGE_LIMIT_MB
- MEMUSAGE_NOTIFY_MAIL
- MEMUSAGE_REPORT
- MEMUSAGE_WARNING_MB
- METAREFRESH_ENABLED
- METAREFRESH_MAXDELAY
- NEWSPIDER_MODULE
- RANDOMIZE_DOWNLOAD_DELAY
- REACTOR_THREADPOOL_MAXSIZE
- REDIRECT_ENABLED
- REDIRECT_MAX_TIMES
- REDIRECT_MAX_TIMES
- REDIRECT_PRIORITY_ADJUST
- REFERER_ENABLED
- RETRY_ENABLED
- RETRY_HTTP_CODES
- RETRY_PRIORITY_ADJUST
- RETRY_TIMES
- ROBOTSTXT_OBEY
- SCHEDULER
- SCHEDULER_DEBUG
- SCHEDULER_DISK_QUEUE
- SCHEDULER_MEMORY_QUEUE
- SCHEDULER_PRIORITY_QUEUE
- SPIDER_CONTRACTS
- SPIDER_CONTRACTS_BASE
- SPIDER_LOADER_CLASS
- SPIDER_MIDDLEWARES
- SPIDER_MIDDLEWARES_BASE
- SPIDER_MODULES
- STATSMAILER_RCPTS
- STATS_CLASS
- STATS_DUMP
- TELNETCONSOLE_ENABLED
- TELNETCONSOLE_HOST
- TELNETCONSOLE_PORT
- TELNETCONSOLE_PORT
- TEMPLATES_DIR
- URLLENGTH_LIMIT
- USER_AGENT
エクセプション¶
ビルトインエクセプションリファレンス¶
Scrapyに含まれるすべての例外のリストとその使用法.
DropItem¶
-
exception
scrapy.exceptions.
DropItem
¶
アイテムの処理を停止するためにアイテムパイプラインステージで発生させる必要がある例外. 詳細については、項目 アイテムパイプライン を参照してください.
CloseSpider¶
-
exception
scrapy.exceptions.
CloseSpider
(reason='cancelled')¶ この例外は、スパイダーのコールバックからクローズ/ストップを要求することができます. サポートされている引数:
パラメータ: reason (str) – クローズした理由
例:
def parse_page(self, response):
if 'Bandwidth exceeded' in response.body:
raise CloseSpider('bandwidth_exceeded')
IgnoreRequest¶
-
exception
scrapy.exceptions.
IgnoreRequest
¶
この例外は、スケジューラまたは任意のダウンローダミドルウェアによって, リクエストを無視すべきであることを示すために発生させることができます.
- コマンドラインツール
- Scrapy プロジェクトの管理に使用するコマンドラインツールについて学ぶ.
- スパイダー
- ウェブサイトをクロールするためのルールを書く.
- セレクタ
- XPathを使用してWebページからデータを抽出する.
- Scrapy シェル
- インタラクティブな環境で抽出コードをテストする.
- アイテム
- スクレイプしたいデータを定義する.
- アイテムローダー
- 抽出したデータをアイテムに埋め込む.
- アイテムパイプライン
- 後処理してスクラップしたデータを保存する.
- フィードのエクスポート
- さまざまなフォーマットとストレージを使用してスクラップしたデータを出力する.
- リクエストとレスポンス
- HTTP要求と応答を表すために使用されるクラスを理解する.
- LinkExtractor
- ページから続くリンクを抽出するための便利なクラス.
- 設定
- Scrapyを設定方法を学び, 利用可能な設定 をすべて見る.
- エクセプション
- 使用可能な例外とその意味をすべて表示する.
Built-in サービス¶
ロギング¶
注釈
scrapy.log
has been deprecated alongside its functions in favor of
explicit calls to the Python standard logging. Keep reading to learn more
about the new logging system.
Scrapy uses Python’s builtin logging system for event logging. We’ll provide some simple examples to get you started, but for more advanced use-cases it’s strongly suggested to read thoroughly its documentation.
Logging works out of the box, and can be configured to some extent with the Scrapy settings listed in ロギング設定.
Scrapy calls scrapy.utils.log.configure_logging()
to set some reasonable
defaults and handle those settings in ロギング設定 when
running commands, so it’s recommended to manually call it if you’re running
Scrapy from scripts as described in スクリプトから Scrapy を実行する.
ログレベル¶
Python’s builtin logging defines 5 different levels to indicate severity on a given log message. Here are the standard ones, listed in decreasing order:
logging.CRITICAL
- for critical errors (highest severity)logging.ERROR
- for regular errorslogging.WARNING
- for warning messageslogging.INFO
- for informational messageslogging.DEBUG
- for debugging messages (lowest severity)
ログメッセージの使用方法¶
Here’s a quick example of how to log a message using the logging.WARNING
level:
import logging
logging.warning("This is a warning")
There are shortcuts for issuing log messages on any of the standard 5 levels,
and there’s also a general logging.log
method which takes a given level as
argument. If you need so, last example could be rewrote as:
import logging
logging.log(logging.WARNING, "This is a warning")
On top of that, you can create different “loggers” to encapsulate messages (For example, a common practice it’s to create different loggers for every module). These loggers can be configured independently, and they allow hierarchical constructions.
Last examples use the root logger behind the scenes, which is a top level
logger where all messages are propagated to (unless otherwise specified). Using
logging
helpers is merely a shortcut for getting the root logger
explicitly, so this is also an equivalent of last snippets:
import logging
logger = logging.getLogger()
logger.warning("This is a warning")
You can use a different logger just by getting its name with the
logging.getLogger
function:
import logging
logger = logging.getLogger('mycustomlogger')
logger.warning("This is a warning")
Finally, you can ensure having a custom logger for any module you’re working on
by using the __name__
variable, which is populated with current module’s
path:
import logging
logger = logging.getLogger(__name__)
logger.warning("This is a warning")
スパイダーからのロギング¶
Scrapy provides a logger
within each Spider
instance, that can be accessed and used like this:
import scrapy
class MySpider(scrapy.Spider):
name = 'myspider'
start_urls = ['http://scrapinghub.com']
def parse(self, response):
self.logger.info('Parse function called on %s', response.url)
That logger is created using the Spider’s name, but you can use any custom Python logger you want. For example:
import logging
import scrapy
logger = logging.getLogger('mycustomlogger')
class MySpider(scrapy.Spider):
name = 'myspider'
start_urls = ['http://scrapinghub.com']
def parse(self, response):
logger.info('Parse function called on %s', response.url)
ロギング設定¶
Loggers on their own don’t manage how messages sent through them are displayed. For this task, different “handlers” can be attached to any logger instance and they will redirect those messages to appropriate destinations, such as the standard output, files, emails, etc.
By default, Scrapy sets and configures a handler for the root logger, based on the settings below.
ロギング設定¶
These settings can be used to configure the logging:
The first couple of settings define a destination for log messages. If
LOG_FILE
is set, messages sent through the root logger will be
redirected to a file named LOG_FILE
with encoding
LOG_ENCODING
. If unset and LOG_ENABLED
is True
, log
messages will be displayed on the standard error. Lastly, if
LOG_ENABLED
is False
, there won’t be any visible log output.
LOG_LEVEL
determines the minimum level of severity to display, those
messages with lower severity will be filtered out. It ranges through the
possible levels listed in ログレベル.
LOG_FORMAT
and LOG_DATEFORMAT
specify formatting strings
used as layouts for all messages. Those strings can contain any placeholders
listed in logging’s logrecord attributes docs and
datetime’s strftime and strptime directives
respectively.
コマンドラインオプション¶
There are command-line arguments, available for all commands, that you can use to override some of the Scrapy settings regarding logging.
--logfile FILE
- Overrides
LOG_FILE
--loglevel/-L LEVEL
- Overrides
LOG_LEVEL
--nolog
- Sets
LOG_ENABLED
toFalse
参考
- Module logging.handlers
- Further documentation on available handlers
scrapy.utils.log モジュール¶
-
scrapy.utils.log.
configure_logging
(settings=None, install_root_handler=True)¶ Initialize logging defaults for Scrapy.
パラメータ: - settings (dict,
Settings
object orNone
) – settings used to create and configure a handler for the root logger (default: None). - install_root_handler (bool) – whether to install root logging handler (default: True)
This function does:
- Route warnings and twisted logging through Python standard logging
- Assign DEBUG and ERROR level to Scrapy and Twisted loggers respectively
- Route stdout to log if LOG_STDOUT setting is True
When
install_root_handler
is True (default), this function also creates a handler for the root logger according to given settings (see ロギング設定). You can override default options usingsettings
argument. Whensettings
is empty or None, defaults are used.configure_logging
is automatically called when using Scrapy commands, but needs to be called explicitly when running custom scripts. In that case, its usage is not required but it’s recommended.If you plan on configuring the handlers yourself is still recommended you call this function, passing install_root_handler=False. Bear in mind there won’t be any log output set by default in that case.
To get you started on manually configuring logging’s output, you can use logging.basicConfig() to set a basic root handler. This is an example on how to redirect
INFO
or higher messages to a file:import logging from scrapy.utils.log import configure_logging configure_logging(install_root_handler=False) logging.basicConfig( filename='log.txt', format='%(levelname)s: %(message)s', level=logging.INFO )
Refer to スクリプトから Scrapy を実行する for more details about using Scrapy this way.
- settings (dict,
統計コレクション¶
Scrapy provides a convenient facility for collecting stats in the form of
key/values, where values are often counters. The facility is called the Stats
Collector, and can be accessed through the stats
attribute of the クローラー API, as illustrated by the examples in
the 共通統計コレクタを使用する section below.
However, the Stats Collector is always available, so you can always import it in your module and use its API (to increment or set new stat keys), regardless of whether the stats collection is enabled or not. If it’s disabled, the API will still work but it won’t collect anything. This is aimed at simplifying the stats collector usage: you should spend no more than one line of code for collecting stats in your spider, Scrapy extension, or whatever code you’re using the Stats Collector from.
Another feature of the Stats Collector is that it’s very efficient (when enabled) and extremely efficient (almost unnoticeable) when disabled.
The Stats Collector keeps a stats table per open spider which is automatically opened when the spider is opened, and closed when the spider is closed.
共通統計コレクタを使用する¶
Access the stats collector through the stats
attribute. Here is an example of an extension that access stats:
class ExtensionThatAccessStats(object):
def __init__(self, stats):
self.stats = stats
@classmethod
def from_crawler(cls, crawler):
return cls(crawler.stats)
Set stat value:
stats.set_value('hostname', socket.gethostname())
Increment stat value:
stats.inc_value('custom_count')
Set stat value only if greater than previous:
stats.max_value('max_items_scraped', value)
Set stat value only if lower than previous:
stats.min_value('min_free_memory_percent', value)
Get stat value:
>>> stats.get_value('custom_count')
1
Get all stats:
>>> stats.get_stats()
{'custom_count': 1, 'start_time': datetime.datetime(2009, 7, 14, 21, 47, 28, 977139)}
利用可能な統計コレクタ¶
Besides the basic StatsCollector
there are other Stats Collectors
available in Scrapy which extend the basic Stats Collector. You can select
which Stats Collector to use through the STATS_CLASS
setting. The
default Stats Collector used is the MemoryStatsCollector
.
MemoryStatsCollector¶
-
class
scrapy.statscollectors.
MemoryStatsCollector
¶ A simple stats collector that keeps the stats of the last scraping run (for each spider) in memory, after they’re closed. The stats can be accessed through the
spider_stats
attribute, which is a dict keyed by spider domain name.This is the default Stats Collector used in Scrapy.
-
spider_stats
¶ A dict of dicts (keyed by spider name) containing the stats of the last scraping run for each spider.
-
DummyStatsCollector¶
-
class
scrapy.statscollectors.
DummyStatsCollector
¶ A Stats collector which does nothing but is very efficient (because it does nothing). This stats collector can be set via the
STATS_CLASS
setting, to disable stats collect in order to improve performance. However, the performance penalty of stats collection is usually marginal compared to other Scrapy workload like parsing pages.
Eメールを送る¶
Although Python makes sending e-mails relatively easy via the smtplib library, Scrapy provides its own facility for sending e-mails which is very easy to use and it’s implemented using Twisted non-blocking IO, to avoid interfering with the non-blocking IO of the crawler. It also provides a simple API for sending attachments and it’s very easy to configure, with a few settings.
簡単な例¶
MailSenderをインスタンス化するには2つの方法があります. 標準コンストラクタを使用してインスタンス化できます:
from scrapy.mail import MailSender
mailer = MailSender()
または, settings を尊重する, Scrapy設定オブジェクトを渡してインスタンス化することもできます:
mailer = MailSender.from_settings(settings)
そして、MailSenderを使って電子メールを送信する方法(添付ファイルなし):
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) – the SMTP host to use for sending the emails. If omitted, the
MAIL_HOST
setting will be used. - mailfrom (str) – the address used to send emails (in the
From:
header). If omitted, theMAIL_FROM
setting will be used. - smtpuser – the SMTP user. If omitted, the
MAIL_USER
setting will be used. If not given, no SMTP authentication will be performed. - smtppass (str) – the SMTP pass for authentication.
- smtpport (int) – the SMTP port to connect to
- smtptls (boolean) – enforce using SMTP STARTTLS
- smtpssl (boolean) – enforce using a secure SSL connection
-
classmethod
from_settings
(settings)¶ Instantiate using a Scrapy settings object, which will respect these Scrapy settings.
パラメータ: settings ( scrapy.settings.Settings
object) – the e-mail recipients
-
send
(to, subject, body, cc=None, attachs=(), mimetype='text/plain', charset=None)¶ Send email to the given recipients.
パラメータ: - to (str or list of str) – the e-mail recipients
- subject (str) – the subject of the e-mail
- cc (str or list of str) – the e-mails to CC
- body (str) – the e-mail body
- attachs (iterable) – an iterable of tuples
(attach_name, mimetype, file_object)
whereattach_name
is a string with the name that will appear on the e-mail’s attachment,mimetype
is the mimetype of the attachment andfile_object
is a readable file object with the contents of the attachment - mimetype (str) – the MIME type of the e-mail
- charset (str) – the character encoding to use for the e-mail contents
- smtphost (str) – the SMTP host to use for sending the emails. If omitted, the
メール設定¶
これらの設定は, MailSender
クラスのデフォルトのコンストラクタ値を定義し,
コードを記述することなくプロジェクト内の電子メール通知を構成するために使用できます(これらの拡張子と MailSender
を使用するコード用).
MAIL_TLS¶
初期値: False
STARTTLSを使用して強制する. STARTTLSは、既存の安全でない接続を取得し, SSL / TLSを使用して安全な接続にアップグレードする方法です.
Telnet コンソール¶
Scrapyには、Scrapy実行プロセスを検査および制御するための組み込みのTelnetコンソールが付属しています. elnetコンソールは、Scrapyプロセス内で実行されている通常のPythonシェルであるため、文字通りその中から何かを行うことができます.
Telnetコンソールは, デフォルトで有効になっている 組み込みScrapy拡張 ですが, 必要に応じて無効にすることもできます. 拡張機能の詳細については, Telnetコンソール拡張機能 を参照してください.
Telnetコンソールにアクセスする方法¶
Telnetコンソールは
TELNETCONSOLE_PORT
設定で定義されているTCPポートをリッスンします.
デフォルトでは 6023
に設定されています.
コンソールにアクセスするには:
telnet localhost 6023
>>>
Windowsにデフォルトでインストールされるtelnetプログラムと、ほとんどのLinuxディストリビューションが必要です.
Telnetコンソールで使用可能な変数¶
elnetコンソールは、Scrapyプロセス内で動作する通常のPythonシェルに似ているので、新しいモジュールのインポートなど、何でもできます.
しかし, telnetコンソールには, 便宜上いくつかのデフォルト変数が定義されています:
Telnetコンソールの使用例¶
Telnetコンソールで実行できるタスクの例を以下に示します:
エンジンステータスを表示する¶
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.
- ロギング
- Pythonの組み込みログをScrapyで使用する方法を学ぶ.
- 統計コレクション
- スクレイピングクローラに関する統計情報を収集する.
- Eメールを送る
- 特定のイベントが発生したときに電子メール通知を送信する.
- Telnet コンソール
- 組み込みのPythonコンソールを使用して実行中のクローラを検査する.
- ウェブサービス
- Webサービスを使用してクローラを監視および制御する.
特定の問題の解決¶
よくある質問¶
ScrapyとBeautifulSoupまたはlxmlとの比較¶
BeautifulSoup と lxml はHTMLとXMLを解析するためのライブラリです. Scrapyは, Webサイトをクロールし, Webサイトからデータを抽出するWebスパイダーを作成するためのアプリケーションフレームワークです.
Scrapy には, データを抽出するためのメカニズム ( selectors と呼ばれる) が組み込まれていますが, 使い方が分かりやすい場合は BeautifulSoup (または lxml) をかんたんに使用することができます. 結局のところ, Pythonコードからインポートして使用できるライブラリを用いて解析しているだけです.
つまり, BeautifulSoup (または lxml) と Scrapy を比較するのは jinja2 と Django を比較するのと同じことです.
Scrapy で BeautifulSoup を使うことができますか?¶
使用できます.
上記 のように, BeautifulSoup を Scrapy のコールバックでHTMLレスポンスを解析するために使用できます.
レスポンスのボディを BeautifulSoup
オブジェクトにフィードし, そこから必要なデータを抽出するだけです.
以下は, BeautifulSoup API を使用したスパイダーの例です. HTMLパーサーとして lxml
を使用しています:
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 公式ドキュメント を参照してください.
Scrapy がサポートしているのは Python のどのバージョンですか?¶
Scrapy は Python 2.7 と Python 3.3+ での動作が確認されています。 Python 2.6 は Scrapy 0.20 からサポート対象から外されています。 Scrapy 1.1 から Python 3 サポートが開始されています。
注釈
Windows では Python 3 はサポートされていません。
Did Scrapy “steal” X from Django?¶
Probably, but we don’t like that word. We think Django is a great open source project and an example to follow, so we’ve used it as an inspiration for Scrapy.
We believe that, if something is already done well, there’s no need to reinvent it. This concept, besides being one of the foundations for open source and free software, not only applies to software but also to documentation, procedures, policies, etc. So, instead of going through each problem ourselves, we choose to copy ideas from those projects that have already solved them properly, and focus on the real problems we need to solve.
We’d be proud if Scrapy serves as an inspiration for other projects. Feel free to steal from us!
Scrapy はHTTPプロキシで動作しますか?¶
はい. HTTPプロキシダウンローダミドルウェアを介してHTTPプロキシのサポートが提供されています(Scrapy 0.8以降).
HttpProxyMiddleware
を参照してください.
異なるページの属性を持つアイテムをスクラップする方法はありますか?¶
追加データをコールバック関数に渡す を参照してください.
Scrapy がクラッシュする: No module named win32api¶
Twisted のバグ のために, pywin32 をインストールする必要があります.
スパイダーでユーザーログインをシミュレートする方法はありますか?¶
Scrapyは幅優先, 深さ優先どちらでクロールしますか?¶
By default, Scrapy uses a LIFO queue for storing pending requests, which basically means that it crawls in DFO order. This order is more convenient in most cases. If you do want to crawl in true BFO order, you can do it by setting the following settings:
DEPTH_PRIORITY = 1
SCHEDULER_DISK_QUEUE = 'scrapy.squeues.PickleFifoDiskQueue'
SCHEDULER_MEMORY_QUEUE = 'scrapy.squeues.FifoMemoryQueue'
私の Scrapy のクローラにはメモリリークがあります。どうしたら良いですか?¶
メモリリークのデバッグ を参照してください.
また, Pythonには, 漏れのない漏れ で説明されているメモリリークの問題があります.
どうしたらScrapyの消費メモリを少なくすることができますか?¶
直前の質問を参照してください.
スパイダーで基本的なHTTP認証を使用することはできますか?¶
はい, HttpAuthMiddleware
を確認してください.
どのようにして英語のかわりに, 私の母国語でページをダウンロードするのですか?¶
Try changing the default Accept-Language request header by overriding the
DEFAULT_REQUEST_HEADERS
setting.
プロジェクトを作成せずにスパイダーを実行することはできますか?¶
はい. runspider
コマンドを使用することで可能です. 例えば, my_spider.py
ファイルがすでに作成されているのであれば, 以下のように実行することができます:
scrapy runspider my_spider.py
詳細は, runspider
コマンドを参照してください.
“Filtered offsite request”メッセージが表示されます. どうすれば修正できますか?
Those messages (logged with DEBUG
level) don’t necessarily mean there is a
problem, so you may not need to fix them.
Those messages are thrown by the Offsite Spider Middleware, which is a spider middleware (enabled by default) whose purpose is to filter out requests to domains outside the ones covered by the spider.
詳細については, OffsiteMiddleware
を参照してください.
プロダクションでScrapyクローラーを導入するための推奨される方法はなんですか?¶
スパイダーのデプロイ 参照してください.
大量のエクスポートにJSONを使用することはできますか?¶
It’ll depend on how large your output is. See this warning in JsonItemExporter
documentation.
シグナルハンドラから(Twised)遅延を返すことはできますか?¶
Some signals support returning deferreds from their handlers, others don’t. See the ビルトインシグナルリファレンス to know which ones.
応答ステータスコード999は何を意味しますか?¶
999 is a custom response status code used by Yahoo sites to throttle requests.
Try slowing down the crawling speed by using a download delay of 2
(or
higher) in your spider:
class MySpider(CrawlSpider):
name = 'myspider'
download_delay = 2
# [ ... rest of the spider code ... ]
Or by setting a global download delay in your project with the
DOWNLOAD_DELAY
setting.
スパイダーのデバッグで pdb.set_trace()
メソッドを呼ぶことはできますか?¶
Yes, but you can also use the Scrapy shell which allows you to quickly analyze
(and even modify) the response being processed by your spider, which is, quite
often, more useful than plain old 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
パラメーターは一体何ですか?¶
The __VIEWSTATE
parameter is used in sites built with ASP.NET/VB.NET. For
more info on how it works see this page. Also, here’s an example spider
which scrapes one of these sites.
大きな XML/CSV データフィードを解析する最適な方法は何ですか?¶
Parsing big feeds with XPath selectors can be problematic since they need to build the DOM of the entire feed in memory, and this can be quite slow and consume a lot of memory.
In order to avoid parsing all the entire feed at once in memory, you can use
the functions xmliter
and csviter
from scrapy.utils.iterators
module. In fact, this is what the feed spiders (see スパイダー) use
under the cover.
Scrapy は自動的にクッキーを管理しますか?¶
はい, Scrapy はサーバーから送信されたCookieを受信して追跡し, 通常のWebブラウザーと同様に後続のリクエストでそれらを送信します.
詳細については, リクエストとレスポンス と CookiesMiddleware を参照してください.
Scrapyから送受信されるクッキーを確認するにはどうすればよいですか?¶
COOKIES_DEBUG
設定を有効化してください.
スパイダーに止めるように指示するにはどうすればよいですか?¶
CloseSpider
エクセプションをコールバックから発生させます. 詳細については CloseSpider
を参照してください.
私のScrapyボットが禁止されるのを防ぐには?¶
BANされることを回避する 参照してください.
スパイダーの引数や設定を使用してスパイダーを構成する必要がありますか?¶
Both spider arguments and settings can be used to configure your spider. There is no strict rule that mandates to use one or the other, but settings are more suited for parameters that, once set, don’t change much, while spider arguments are meant to change more often, even on each spider run and sometimes are required for the spider to run at all (for example, to set the start url of a spider).
To illustrate with an example, assuming you have a spider that needs to log into a site to scrape data, and you only want to scrape data from a certain section of the site (which varies each time). In that case, the credentials to log in would be settings, while the url of the section to scrape would be a spider argument.
XML文書をスクラップしていて、XPathセレクタがアイテムを返さない¶
ネームスペースを削除する必要があるかもしれません. ネームスペースの削除 参照してください.
スパイダーのデバッグ¶
このドキュメントでは, スパイダーをデバッグするための最も一般的な手法について説明します. 以下のスパイダーを考えてみましょう:
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):
# collect `item_urls`
for item_url in item_urls:
yield scrapy.Request(item_url, self.parse_item)
def parse_item(self, response):
item = MyItem()
# populate `item` fields
# and extract item_details_url
yield scrapy.Request(item_details_url, self.parse_details, meta={'item': item})
def parse_details(self, response):
item = response.meta['item']
# populate more `item` fields
return item
Basically this is a simple spider which parses two pages of items (the
start_urls). Items also have a details page with additional information, so we
use the meta
functionality of Request
to pass a
partially populated item.
パースコマンド¶
The most basic way of checking the output of your spider is to use the
parse
command. It allows to check the behaviour of different parts
of the spider at the method level. It has the advantage of being flexible and
simple to use, but does not allow debugging code inside a method.
特定の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 -----------------------------------------------------------------
[]
Using the --verbose
or -v
option we can see the status at each depth level:
$ 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 -----------------------------------------------------------------
[]
Checking items scraped from a single start_url, can also be easily achieved using:
$ scrapy parse --spider=myspider -d 3 'http://example.com/page1'
Scrapy シェル¶
While the parse
command is very useful for checking behaviour of a
spider, it is of little help to check what happens inside a callback, besides
showing the response received and the output. How to debug the situation when
parse_details
sometimes receives no item?
Fortunately, the shell
is your bread and butter in this case (see
応答を調べるためにシェルを起動する):
from scrapy.shell import inspect_response
def parse_details(self, response):
item = response.meta.get('item', None)
if item:
# populate more `item` fields
return item
else:
inspect_response(response, self)
See also: 応答を調べるためにシェルを起動する.
ブラウザで開く¶
Sometimes you just want to see how a certain response looks in a browser, you
can use the open_in_browser
function for that. Here is an example of how
you would use it:
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
will open a browser with the response received by Scrapy at
that point, adjusting the base tag so that images and styles are displayed
properly.
ロギング¶
ロギングはスパイダーの実行に関する情報を得るためのもう1つの便利なオプションです. Although not as convenient, it comes with the advantage that the logs will be available in all future runs should they be necessary again:
def parse_details(self, response):
item = response.meta.get('item', None)
if item:
# populate more `item` fields
return item
else:
self.logger.warning('No item received for %s', response.url)
For more information, check the ロギング section.
スパイダーコントラクト¶
バージョン 0.15 で追加.
注釈
これは新機能(Scrapy 0.15で導入されました)であり、機能/ APIの軽微な更新の対象となる可能性があります. リリースノート を確認してください.
Testing spiders can get particularly annoying and while nothing prevents you from writing unit tests the task gets cumbersome quickly. Scrapy offers an integrated way of testing your spiders by the means of contracts.
This allows you to test each callback of your spider by hardcoding a sample url
and check various constraints for how the callback processes the response. Each
contract is prefixed with an @
and included in the docstring. See the
following example:
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
¶ This contract (
@url
) sets the sample url used when checking other contract conditions for this spider. This contract is mandatory. All callbacks lacking this contract are ignored when running the checks:@url url
-
class
scrapy.contracts.default.
ReturnsContract
¶ This contract (
@returns
) sets lower and upper bounds for the items and requests returned by the spider. The upper bound is optional:@returns item(s)|request(s) [min [max]]
-
class
scrapy.contracts.default.
ScrapesContract
¶ This contract (
@scrapes
) checks that all the items returned by the callback have the specified fields:@scrapes field_1 field_2 ...
Use the check
command to run the contract checks.
カスタムコントラクト¶
If you find you need more power than the built-in scrapy contracts you can
create and load your own contracts in the project by using the
SPIDER_CONTRACTS
setting:
SPIDER_CONTRACTS = {
'myproject.contracts.ResponseCheck': 10,
'myproject.contracts.ItemValidate': 10,
}
Each contract must inherit from scrapy.contracts.Contract
and can
override three methods:
-
class
scrapy.contracts.
Contract
(method, *args)¶ パラメータ: - method (function) – callback function to which the contract is associated
- args (list) – list of arguments passed into the docstring (whitespace separated)
-
adjust_request_args
(args)¶ This receives a
dict
as an argument containing default arguments forRequest
object. Must return the same or a modified version of it.
-
pre_process
(response)¶ This allows hooking in various checks on the response received from the sample request, before it’s being passed to the callback.
-
post_process
(output)¶ This allows processing the output of the callback. Iterators are converted listified before being passed to this hook.
Here is a demo contract which checks the presence of a custom header in the
response received. Raise scrapy.exceptions.ContractFail
in order to
get the failures pretty printed:
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を使用する際の一般的な方法について説明します. これらは, 多くの話題を網羅しており, 他の特定のセクションにはいるのはよくありません.
スクリプトから Scrapy を実行する¶
scrapy crawl
コマンドで Scrapy を実行する従来の方法に加え,
API を利用してスクリプトから Scrapy を実行することができます.
Scrapy は Twisted 非同期ネットワーキングライブラリの上に構築されているので, Twisted リアクタ内で実行する必要があります.
スパイダーを実行するために使用できる最初のユーティリティーは
scrapy.crawler.CrawlerProcess
です. このクラスは,
Twisted リアクターを開始し, ロギング・シャットダウンハンドラを設定します.
このクラスは, すべてのScrapyコマンドで使用されるクラスです.
ここで, 1つのスパイダーを実行する方法の例を示します.
import scrapy
from scrapy.crawler import CrawlerProcess
class MySpider(scrapy.Spider):
# 独自のスパイダー定義
...
process = CrawlerProcess({
'USER_AGENT': 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)'
})
process.crawl(MySpider)
process.start() # クロールが終了するまでスクリプトはここでブロックされます
CrawlerProcess
ドキュメントをチェックして, 使用法の詳細を確認してください.
プロジェクトの内部にいる場合は, プロジェクト内のコンポーネントをインポートするために使用できる追加のヘルパーがいくつかあります.
名前を渡すスパイダーを
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' はプロジェクトのスパイダーの名前です.
process.crawl('followall', domain='scrapinghub.com')
process.start() # クロールが終了するまでスクリプトはここでブロックされます
クロールプロセスをより詳細に制御できる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):
# 独自のスパイダー定義
...
configure_logging({'LOG_FORMAT': '%(levelname)s: %(message)s'})
runner = CrawlerRunner()
d = runner.crawl(MySpider)
d.addBoth(lambda _: reactor.stop())
reactor.run() # クロールが終了するまでスクリプトはここでブロックされます
同じプロセスで複数のスパイダーを実行する¶
デフォルトでは, Scrapy は scrapy crawl
を実行するときにプロセスごとに1つのスパイダーを実行します.
ただし, Scrapy は 内部 API を使用することでプロセスごとに複数のスパイダーを実行できます.
以下は, 複数のスパイダーを同時に実行する例です:
import scrapy
from scrapy.crawler import CrawlerProcess
class MySpider1(scrapy.Spider):
# 一番目の独自のスパイダーの定義
...
class MySpider2(scrapy.Spider):
# 二番目の独自のスパイダーの定義
...
process = CrawlerProcess()
process.crawl(MySpider1)
process.crawl(MySpider2)
process.start() # すべてのクロールジョブが終了するまでスクリプトはここでブロックされます
CrawlerRunner
を使用した同様の例です:
import scrapy
from twisted.internet import reactor
from scrapy.crawler import CrawlerRunner
from scrapy.utils.log import configure_logging
class MySpider1(scrapy.Spider):
# 一番目の独自のスパイダーの定義
...
class MySpider2(scrapy.Spider):
# 二番目の独自のスパイダーの定義
...
configure_logging()
runner = CrawlerRunner()
runner.crawl(MySpider1)
runner.crawl(MySpider2)
d = runner.join()
d.addBoth(lambda _: reactor.stop())
reactor.run() # すべてのクロールジョブが終了するまで, スクリプトはここでブロックされます
同様の例ですが, 遅延を連鎖させてスパイダーを順番に実行しています:
from twisted.internet import reactor, defer
from scrapy.crawler import CrawlerRunner
from scrapy.utils.log import configure_logging
class MySpider1(scrapy.Spider):
# 一番目の独自のスパイダーの定義
...
class MySpider2(scrapy.Spider):
# 二番目の独自のスパイダーの定義
...
configure_logging()
runner = CrawlerRunner()
@defer.inlineCallbacks
def crawl():
yield runner.crawl(MySpider1)
yield runner.crawl(MySpider2)
reactor.stop()
crawl()
reactor.run() # 最後のクロールコールが終了するまで, スクリプトはここでブロックされます
分散クロール¶
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サーバーでスパイダーを実行します. スパイダーは,
(spider) 引数 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
BANされることを回避する¶
いくつかのウェブサイトでは, ボットがWebサイトをクロールするのを防ぐために, さまざまな洗練された手段を実装しています. これらの措置を回避することは非常に困難なことがあり, 特別なインフラストラクチャが必要な場合があります. ご不明な点がある場合は, 商用サポート にお問い合わせください.
これらの種類のサイトを扱う際に留意すべきヒントをいくつか紹介します:
- ユーザーエージェントを, よく知られているブラウザのプールからローテーションします(Googleのリストを取得するにはGoogleを使用します)
- 一部のサイトでは, クッキーを使用してボットの動作を特定する場合があるため, クッキーを無効にする (
COOKIES_ENABLED
を参照してください). - ダウンロード遅延 (2 またはそれ以上) を使用する.
DOWNLOAD_DELAY
設定を参照してください. - 可能であれば, サイトに直接アクセスするのではなく, Google cache を使用してページを取得する
- IPプールをローテーションさせ使用します。たとえば, 無料の Tor project や ProxyMesh のような有料サービスです. また, あなた自身のプロキシを添付できるスーパープロキシである scrapoxy のようなオープンソースのプロジェクトが有ります.
- 内部的に禁止を回避する高度に分散されたダウンローダを使用するので, クリーンなページの解析に集中することができます. そのようなダウンローダの一例に Crawlera があります.
それでもあなたのボットが禁止されるのを防ぐことができない場合は, 商用サポート に連絡することを検討してください.
ブロードクロール¶
Scrapy のデフォルトは, 特定のサイトをクロールするために最適化されています. そのサイトは, 単一の Scrapy スパイダーによって処理されることがよくありますが, これは必須ではありません(たとえば, スローされた任意のサイトを処理するスパイダーがあります).
この「フォーカスクロール」に加えて, ドメインのクロールが完了するまでの間に停止するのではなく, 時間や他の任意の制約によってのみ制限されている(潜在的に無制限の)多数のクロールの一般的なタイプがあります. 実行するリクエストがもうないとき これらは「ブロードクロール」と呼ばれ, 検索エンジンで採用されている一般的なクローラです.
これらは, ブロードクロールでよく見られる共通のプロパティです:
- 特定のサイトセットではなく, 多くのドメインを無限にクロールする
- ドメインをクロールする必要はない. そのため, クロールを時間またはクロールされたページ数で制限することは実用的ではない(または不可能)
- データはしばしば別の段階で後処理されるため, 論理的にはより単純である(多くの抽出規則を持つ非常に複雑なスパイダーとは対照的す)
- 同時に複数のドメインをクロールするため, 特定のサイトの制約に制限されずに高速なクロール速度を実現できる (各サイトは丁寧さを考慮してゆっくりとクロールされるが, 多くのサイトは並行してクロールされる)
上記のように, Scrapy のデフォルト設定は, ブロードクロールではなく, フォーカスクロールに対して最適化されています. しかし, Scrapy は非同期アーキテクチャであるため, 高速な広範なクロールを実行するのに非常に適しています. このページでは, ブロードクロールを行うために Scrapy を使用する際に留意する必要がある事項と, 効果的なブロードクロールを達成するために調整する Scrapy 設定の具体的な提案をまとめています.
並行性を高める¶
並行処理は, 並列処理されるリクエストの数です. グローバルごとの制限とドメインごとの制限があります.
Scrapy の既定のグローバル同時実行制限は, 多くの異なるドメインを同時にクロールするのには適していないため, 増やすべきです. どの程度増加させるかは, クローラで使用可能な CPU の量に依存します. 良い出発点は ``100``ですが, 調べる最も良い方法は, いくつかの試行を行い, あなたの Scrapy プロセスがどの CPU に束縛されているかを特定することです. 最適なパフォーマンスを得るには, CPU 使用率が80〜90%の並行処理を選択する必要があります.
グローバルな同時使用を増やすには:
CONCURRENT_REQUESTS = 100
Twisted のIOスレッドプールの最大サイズを増やす¶
現在のところ, Scrapy は DNS 解決をスレッドプールの使用でブロックします. 並行性レベルが高いと, クロールが遅くなったり, DNS リゾルバのタイムアウトが起こる可能性があります. 解決策としては, DNSクエリを処理するスレッドの数を増やすことです. DNS キューは, 接続の確立と全体的なクロールのスピードアップがされ, 速く処理されます.
スレッドプールの最大サイズを増やすには:
REACTOR_THREADPOOL_MAXSIZE = 20
独自のDNSの設定¶
複数のクロールプロセスと1つのセントラル 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経由でのみ利用可能なプレーンなHTMLバージョンのコンテンツを提供します. 2つの方法でそれを示すことができます:
- URL に
#!
を使用する - これは一般的な方法です. - 特別なメタタグを使用する - この方法は「メイン」「インデックス」ウェブサイトページで使用されます.
Scrapy は, (1) のみ自動的にハンドリングします. (2) をハンドリングするには AjaxCrawlMiddleware を有効化してください:
AJAXCRAWL_ENABLED = True
ブロードクロールを行う場合, 多くの「インデックス」Webページをクロールするのが一般的です. よって, AjaxCrawlMiddleware は正しくクロールすることができます. フォーマンスのオーバーヘッドがあるため, デフォルトではオフになっています. フォーカスクロールで有効にする意味はあまりありません.
スクレイピングにFireFoxを使用する¶
Here is a list of tips and advice on using Firefox for scraping, along with a list of useful Firefox add-ons to ease the scraping process.
ライブブラウザDOMの検査に関する警告¶
Since Firefox add-ons operate on a live browser DOM, what you’ll actually see
when inspecting the page source is not the original HTML, but a modified one
after applying some browser clean up and executing Javascript code. Firefox,
in particular, is known for adding <tbody>
elements to tables. Scrapy, on
the other hand, does not modify the original page HTML, so you won’t be able to
extract any data if you use <tbody>
in your XPath expressions.
Therefore, you should keep in mind the following things when working with Firefox and XPath:
- Disable Firefox Javascript while inspecting the DOM looking for XPaths to be used in Scrapy
- Never use full XPath paths, use relative and clever ones based on attributes
(such as
id
,class
,width
, etc) or any identifying features likecontains(@href, 'image')
. - Never include
<tbody>
elements in your XPath expressions unless you really know what you’re doing
スクレイピングに便利なFirefoxアドオン¶
Firebug¶
Firebug is a widely known tool among web developers and it’s also very useful for scraping. In particular, its Inspect Element feature comes very handy when you need to construct the XPaths for extracting data because it allows you to view the HTML code of each page element while moving your mouse over it.
See スクレイピングにFirebugを使用する for a detailed guide on how to use Firebug with Scrapy.
XPath Checker¶
XPath Checker is another Firefox add-on for testing XPaths on your pages.
Tamper Data¶
Tamper Data is a Firefox add-on which allows you to view and modify the HTTP request headers sent by Firefox. Firebug also allows to view HTTP headers, but not to modify them.
Firecookie¶
Firecookie makes it easier to view and manage cookies. You can use this extension to create a new cookie, delete existing cookies, see a list of cookies for the current site, manage cookies permissions and a lot more.
スクレイピングにFirebugを使用する¶
注釈
Google Directory, the example website used in this guide is no longer available as it has been shut down by Google. The concepts in this guide are still valid though. If you want to update this guide to use a new (working) site, your contribution will be more than welcome!. See Scrapy に貢献する for information on how to do so.
イントロダクション¶
This document explains how to use Firebug (a Firefox add-on) to make the scraping process easier and more fun. For other useful Firefox add-ons see スクレイピングに便利なFirefoxアドオン. There are some caveats with using Firefox add-ons to inspect pages, see ライブブラウザDOMの検査に関する警告.
In this example, we’ll show how to use Firebug to scrape data from the Google Directory, which contains the same data as the Open Directory Project used in the tutorial but with a different face.
Firebug comes with a very useful feature called Inspect Element which allows you to inspect the HTML code of the different page elements just by hovering your mouse over them. Otherwise you would have to search for the tags manually through the HTML body which can be a very tedious task.
In the following screenshot you can see the Inspect Element tool in action.

At first sight, we can see that the directory is divided in categories, which are also divided in subcategories.
However, it seems that there are more subcategories than the ones being shown in this page, so we’ll keep looking:

As expected, the subcategories contain links to other subcategories, and also links to actual websites, which is the purpose of the directory.
フォローするリンクを取得する¶
By looking at the category URLs we can see they share a pattern:
Once we know that, we are able to construct a regular expression to follow those links. For example, the following one:
directory\.google\.com/[A-Z][a-zA-Z_/]+$
So, based on that regular expression we can create the first crawling rule:
Rule(LinkExtractor(allow='directory.google.com/[A-Z][a-zA-Z_/]+$', ),
'parse_category',
follow=True,
),
The Rule
object instructs
CrawlSpider
based spiders how to follow the
category links. parse_category
will be a method of the spider which will
process and extract data from those pages.
This is how the spider would look so far:
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
class GoogleDirectorySpider(CrawlSpider):
name = 'directory.google.com'
allowed_domains = ['directory.google.com']
start_urls = ['http://directory.google.com/']
rules = (
Rule(LinkExtractor(allow='directory\.google\.com/[A-Z][a-zA-Z_/]+$'),
'parse_category', follow=True,
),
)
def parse_category(self, response):
# write the category page data extraction code here
pass
データの抽出¶
Now we’re going to write the code to extract data from those pages.
With the help of Firebug, we’ll take a look at some page containing links to websites (say http://directory.google.com/Top/Arts/Awards/) and find out how we can extract those links using Selectors. We’ll also use the Scrapy shell to test those XPath’s and make sure they work as we expect.

As you can see, the page markup is not very descriptive: the elements don’t
contain id
, class
or any attribute that clearly identifies them, so
we’ll use the ranking bars as a reference point to select the data to extract
when we construct our XPaths.
After using FireBug, we can see that each link is inside a td
tag, which is
itself inside a tr
tag that also contains the link’s ranking bar (in
another td
).
So we can select the ranking bar, then find its parent (the tr
), and then
finally, the link’s td
(which contains the data we want to scrape).
This results in the following XPath:
//td[descendant::a[contains(@href, "#pagerank")]]/following-sibling::td//a
It’s important to use the Scrapy shell to test these complex XPath expressions and make sure they work as expected.
Basically, that expression will look for the ranking bar’s td
element, and
then select any td
element who has a descendant a
element whose
href
attribute contains the string #pagerank
“
Of course, this is not the only XPath, and maybe not the simpler one to select
that data. Another approach could be, for example, to find any font
tags
that have that grey colour of the links,
Finally, we can write our parse_category()
method:
def parse_category(self, response):
# The path to website links in directory page
links = response.xpath('//td[descendant::a[contains(@href, "#pagerank")]]/following-sibling::td/font')
for link in links:
item = DirectoryItem()
item['name'] = link.xpath('a/text()').extract()
item['url'] = link.xpath('a/@href').extract()
item['description'] = link.xpath('font[2]/text()').extract()
yield item
Be aware that you may find some elements which appear in Firebug but
not in the original HTML, such as the typical case of <tbody>
elements.
or tags which Therefer in page HTML sources may on Firebug inspects the live DOM
メモリリークのデバッグ¶
Scrapyでは, リクエスト, レスポンス, アイテムなどのオブジェクトの寿命は制限されています. これらは作成され, しばらく使用された後, 最終的に破棄されます.
全オブジェクトの中でも, Requestはおそらく最も寿命の長いものです. スケジューラのキューで待機してから処理するまでです. 詳細は, アーキテクチャの概要 を参照してください.
これらの Scrapy オブジェクトは(かなり長い)存続期間を持つため, 適切に解放されずメモリに蓄積され, 「メモリリーク」を引き起こすリスクが常にあります.
メモリリークをデバッグするのに役立つように, Scrapyには trackref というオブジェクト参照をトラッキングするためのメカニズムが組み込まれています. さらに詳細なメモリデバッグには Guppy というサードパーティのライブラリを使用することもできます. どちらのツールも Telnet コンソール から使用する必要があります.
メモリリークの一般的な原因¶
頻繁に, Scrapy 開発者はリクエストで参照されるオブジェクト(たとえば, meta
属性または要求コールバック関数を使用して)を渡し,
これらの参照されたオブジェクトの有効期間をリクエストの存続期間として効果的に制限します.
これは, 今のところScrapyプロジェクトでのメモリリークの最も一般的な原因であり,
新規参入者がデバッグするのは非常に難しいものです.
大きなプロジェクトでは, 一般的にスパイダーは様々な人によって書かれており, そのスパイダーのいくつかは「リーク」の原因になりえ, 他の(よく書かれた)スパイダーの部分に同時に影響を及ぼし, 全体的なクロールプロセスに影響を及ぼす可能性があります.
また, (以前に割り当てられた)リソースを適切に解放していない場合は,
作成したカスタムミドルウェア, パイプライン, または拡張機能からリークが発生する可能性があります.
たとえば, spider_opened
にリソースを割り当てても
spider_closed
でリソースを解放しないと,
プロセスごとに複数のスパイダーを実行 していると問題が発生する可能性があります.
リクエストが多すぎ?¶
デフォルトでは, Scrapyはリクエストのキューをメモリ内に保持します.
これは, Request
オブジェクトおよび
(例えば, meta
内の)
リクエスト属性内で参照されるすべてのオブジェクトを含みます.
必ずしもリークとはいえませんが, これには多くのメモリを必要とします.
永続的なジョブ・キュー を有効にすると, メモリー使用量を制御できます.
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
ご覧のとおり, このレポートには, 各クラスの中で最も古いオブジェクトの「年齢」も表示されます.
プロセスごとに複数のスパイダーを実行している場合は, 最も古いリクエスト, またはレスポンスを調べることで,
どのスパイダーがリークを起こしているか把握できます.
Telnetコンソールから get_oldest()
関数を使用して,
各クラスの最も古いオブジェクトを取得できます.
どのオブジェクトが追跡されるの?¶
trackrefs
によって追跡されるオブジェクトは, すべてこれらのクラス(およびそのすべてのサブクラス)のものです:
実際の例¶
仮想のメモリリークの具体例を見てみましょう. このような行を持つスパイダーがいくつかあるとします:
return Request("http://www.somenastyspider.com/product.php?pid=%d" % product_id,
callback=self.parse, meta={referer: response})
この行は, リクエスト中にレスポンスの参照を渡しています. このレスポンスの参照は, レスポンスの存続期間とリクエストの存続期間とを結びつけ, メモリリークを引き起こします.
trackref
ツールを使用して, 原因を発見する方法を見てみましょう.
クローラが数分間実行され, メモリ使用量が大きく増えたことがわかったら, Telnet コンソールに入り, 生きている参照を確認します:
>>> 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 (class または classe のタプル) – 与えられた場合, 指定されたクラス(またはクラスのタプル)からのすべてのオブジェクトは無視されます.
-
scrapy.utils.trackref.
get_oldest
(class_name)¶ 指定されたクラス名で生存しているすべてのオブジェクトのイテレータを返します. 見つからない場合は
None
を返します. まず,print_live_refs()
を使用して, クラス名ごとに追跡されたすべてのライブオブジェクトのリストを取得します.
-
scrapy.utils.trackref.
iter_all
(class_name)¶ 指定されたクラス名で生存しているすべてのオブジェクトのイテレータを返します. 見つからない場合は
None
を返します. まず,print_live_refs()
を使用して, クラス名ごとに追跡されたすべてのライブオブジェクトのリストを取得します.
Guppy でメモリリークのデバッグをする¶
trackref
はメモリリークを追跡する非常に便利なメカニズムを提供しますが,
メモリリーク(リクエスト, レスポンス, アイテム, セレクタ)の原因となる可能性の高いオブジェクトのみを追跡します.
しかし, メモリリークが他の(多かれ少なかれわかりにくい)オブジェクトから来る場合もあります.
trackref
を使ってリークを見つけることができない場合は, もう一つのリソース,
Guppy ライブラリ があります.
pip
を使用している場合は, 次のコマンドでGuppyをインストールできます:
pip install guppy
また, Telnet コンソールには, Guppy ヒープオブジェクトにアクセスするための組み込みショートカット(hpy) が付属しています. 以下は, Guppyを使ってヒープ内で利用可能なすべてのPythonオブジェクトを表示する例です:
>>> x = hpy.heap()
>>> x.bytype
Partition of a set of 297033 objects. Total size = 52587824 bytes.
Index Count % Size % Cumulative % Type
0 22307 8 16423880 31 16423880 31 dict
1 122285 41 12441544 24 28865424 55 str
2 68346 23 5966696 11 34832120 66 tuple
3 227 0 5836528 11 40668648 77 unicode
4 2461 1 2222272 4 42890920 82 type
5 16870 6 2024400 4 44915320 85 function
6 13949 5 1673880 3 46589200 89 types.CodeType
7 13422 5 1653104 3 48242304 92 list
8 3735 1 1173680 2 49415984 94 _sre.SRE_Pattern
9 1209 0 456936 1 49872920 95 scrapy.http.headers.Headers
<1676 more rows. Type e.g. '_.more' to view.>
ほとんどのスペースは dict
によって使用されていることがわかります.
これらの dict
がどの属性から参照されているかを確認したい場合は, 以下のようにします:
>>> x.bytype[0].byvia
Partition of a set of 22307 objects. Total size = 16423880 bytes.
Index Count % Size % Cumulative % Referred Via:
0 10982 49 9416336 57 9416336 57 '.__dict__'
1 1820 8 2681504 16 12097840 74 '.__dict__', '.func_globals'
2 3097 14 1122904 7 13220744 80
3 990 4 277200 2 13497944 82 "['cookies']"
4 987 4 276360 2 13774304 84 "['cache']"
5 985 4 275800 2 14050104 86 "['meta']"
6 897 4 251160 2 14301264 87 '[2]'
7 1 0 196888 1 14498152 88 "['moduleDict']", "['modules']"
8 672 3 188160 1 14686312 89 "['cb_kwargs']"
9 27 0 155016 1 14841328 90 '[1]'
<333 more rows. Type e.g. '_.more' to view.>
ご覧のとおり, Guppy モジュールは非常に強力ですが, Python についての深い知識も必要です. Guppyの詳細については, Guppy ドキュメント を参照してください.
漏れのない漏れ¶
場合によっては, Scrapy プロセスのメモリ使用量が増加するだけで, 減少しないことがあります. この場合残念なことに, Scrapy または, あなたのプロジェクトどちらにも, メモリリークが発生する可能性があります. これは(あまりよく知られていない)Python の問題で, Python がリリースしたメモリをオペレーティングシステムに返さないことにより発生します. 詳細については, 以下を参照してください:
この記事 で詳しく述べられている Evan Jones が提案した改良点は, Python 2.5でマージされましたが, これは問題が軽減されただけで, 完全に修正されたわけではありません. 以下は, 記事の引用です:
Unfortunately, this patch can only free an arena if there are no more objects allocated in it anymore. This means that fragmentation is a large issue. An application could have many megabytes of free memory, scattered throughout all the arenas, but it will be unable to free any of it. This is a problem experienced by all memory allocators. The only way to solve it is to move to a compacting garbage collector, which is able to move objects in memory. This would require significant changes to the Python interpreter.
メモリ消費を合理的に保つために, ジョブを複数の小さなジョブに分割するか, 永続的なジョブ・キュー を有効にし, スパイダーを停止/開始するすることが望ましいです.
ファイルと画像のダウンロードと処理¶
Scrapy provides reusable item pipelines for downloading files attached to a particular item (for example, when you scrape products and also want to download their images locally). These pipelines share a bit of functionality and structure (we refer to them as media pipelines), but typically you’ll either use the Files Pipeline or the Images Pipeline.
Both pipelines implement these features:
- Avoid re-downloading media that was downloaded recently
- Specifying where to store the media (filesystem directory, Amazon S3 bucket)
The Images Pipeline has a few extra functions for processing images:
- Convert all downloaded images to a common format (JPG) and mode (RGB)
- Thumbnail generation
- Check images width/height to make sure they meet a minimum constraint
The pipelines also keep an internal queue of those media URLs which are currently being scheduled for download, and connect those responses that arrive containing the same media to that queue. This avoids downloading the same media more than once when it’s shared by several items.
ファイルパイプラインの使用¶
The typical workflow, when using the FilesPipeline
goes like
this:
- In a Spider, you scrape an item and put the URLs of the desired into a
file_urls
field. - The item is returned from the spider and goes to the item pipeline.
- When the item reaches the
FilesPipeline
, the URLs in thefile_urls
field are scheduled for download using the standard Scrapy scheduler and downloader (which means the scheduler and downloader middlewares are reused), but with a higher priority, processing them before other pages are scraped. The item remains “locked” at that particular pipeline stage until the files have finish downloading (or fail for some reason). - When the files are downloaded, another field (
files
) will be populated with the results. This field will contain a list of dicts with information about the downloaded files, such as the downloaded path, the original scraped url (taken from thefile_urls
field) , and the file checksum. The files in the list of thefiles
field will retain the same order of the originalfile_urls
field. If some file failed downloading, an error will be logged and the file won’t be present in thefiles
field.
画像パイプラインの使用¶
Using the ImagesPipeline
is a lot like using the FilesPipeline
,
except the default field names used are different: you use image_urls
for
the image URLs of an item and it will populate an images
field for the information
about the downloaded images.
The advantage of using the ImagesPipeline
for image files is that you
can configure some extra functions like generating thumbnails and filtering
the images based on their size.
The Images Pipeline uses Pillow for thumbnailing and normalizing images to JPEG/RGB format, so you need to install this library in order to use it. Python Imaging Library (PIL) should also work in most cases, but it is known to cause troubles in some setups, so we recommend to use Pillow instead of PIL.
メディアパイプラインの有効化¶
To enable your media pipeline you must first add it to your project
ITEM_PIPELINES
setting.
For Images Pipeline, use:
ITEM_PIPELINES = {'scrapy.pipelines.images.ImagesPipeline': 1}
For Files Pipeline, use:
ITEM_PIPELINES = {'scrapy.pipelines.files.FilesPipeline': 1}
注釈
You can also use both the Files and Images Pipeline at the same time.
Then, configure the target storage setting to a valid value that will be used
for storing the downloaded images. Otherwise the pipeline will remain disabled,
even if you include it in the ITEM_PIPELINES
setting.
For the Files Pipeline, set the FILES_STORE
setting:
FILES_STORE = '/path/to/valid/dir'
For the Images Pipeline, set the IMAGES_STORE
setting:
IMAGES_STORE = '/path/to/valid/dir'
サポートされているストレージ¶
File system is currently the only officially supported storage, but there is also support for storing files in Amazon S3.
ファイルシステムストレージ¶
The files are stored using a SHA1 hash of their URLs for the file names.
For example, the following image URL:
http://www.example.com/image.jpg
Whose SHA1 hash is:
3afec3b4765f8f0a07b78f98c07b83f013567a0a
Will be downloaded and stored in the following file:
<IMAGES_STORE>/full/3afec3b4765f8f0a07b78f98c07b83f013567a0a.jpg
Where:
<IMAGES_STORE>
is the directory defined inIMAGES_STORE
setting for the Images Pipeline.full
is a sub-directory to separate full images from thumbnails (if used). For more info see 画像のサムネイル生成.
Amazon S3 ストレージ¶
FILES_STORE
and IMAGES_STORE
can represent an Amazon S3
bucket. Scrapy will automatically upload the files to the bucket.
For example, this is a valid IMAGES_STORE
value:
IMAGES_STORE = 's3://bucket/images'
You can modify the Access Control List (ACL) policy used for the stored files,
which is defined by the FILES_STORE_S3_ACL
and
IMAGES_STORE_S3_ACL
settings. By default, the ACL is set to
private
. To make the files publicly available use the public-read
policy:
IMAGES_STORE_S3_ACL = 'public-read'
For more information, see canned ACLs in the Amazon S3 Developer Guide.
使用例¶
In order to use a media pipeline first, enable it.
Then, if a spider returns a dict with the URLs key (file_urls
or
image_urls
, for the Files or Images Pipeline respectively), the pipeline will
put the results under respective key (files
or images
).
If you prefer to use Item
, then define a custom item with the
necessary fields, like in this example for Images Pipeline:
import scrapy
class MyItem(scrapy.Item):
# ... other item fields ...
image_urls = scrapy.Field()
images = scrapy.Field()
If you want to use another field name for the URLs key or for the results key, it is also possible to override it.
For the Files Pipeline, set FILES_URLS_FIELD
and/or
FILES_RESULT_FIELD
settings:
FILES_URLS_FIELD = 'field_name_for_your_files_urls'
FILES_RESULT_FIELD = 'field_name_for_your_processed_files'
For the Images Pipeline, set IMAGES_URLS_FIELD
and/or
IMAGES_RESULT_FIELD
settings:
IMAGES_URLS_FIELD = 'field_name_for_your_images_urls'
IMAGES_RESULT_FIELD = 'field_name_for_your_processed_images'
If you need something more complex and want to override the custom pipeline behaviour, see メディアパイプラインの拡張.
If you have multiple image pipelines inheriting from ImagePipeline and you want to have different settings in different pipelines you can set setting keys preceded with uppercase name of your pipeline class. E.g. if your pipeline is called MyPipeline and you want to have custom IMAGES_URLS_FIELD you define setting MYPIPELINE_IMAGES_URLS_FIELD and your custom settings will be used.
その他の機能¶
ファイルの有効期限¶
The Image Pipeline avoids downloading files that were downloaded recently. To
adjust this retention delay use the FILES_EXPIRES
setting (or
IMAGES_EXPIRES
, in case of Images Pipeline), which
specifies the delay in number of days:
# 120 days of delay for files expiration
FILES_EXPIRES = 120
# 30 days of delay for images expiration
IMAGES_EXPIRES = 30
The default value for both settings is 90 days.
If you have pipeline that subclasses FilesPipeline and you’d like to have different setting for it you can set setting keys preceded by uppercase class name. E.g. given pipeline class called MyPipeline you can set setting key:
MYPIPELINE_FILES_EXPIRES = 180
and pipeline class MyPipeline will have expiration time set to 180.
画像のサムネイル生成¶
The Images Pipeline can automatically create thumbnails of the downloaded images.
In order use this feature, you must set IMAGES_THUMBS
to a dictionary
where the keys are the thumbnail names and the values are their dimensions.
For example:
IMAGES_THUMBS = {
'small': (50, 50),
'big': (270, 270),
}
When you use this feature, the Images Pipeline will create thumbnails of the each specified size with this format:
<IMAGES_STORE>/thumbs/<size_name>/<image_id>.jpg
Where:
<size_name>
is the one specified in theIMAGES_THUMBS
dictionary keys (small
,big
, etc)<image_id>
is the SHA1 hash of the image url
Example of image files stored using small
and big
thumbnail names:
<IMAGES_STORE>/full/63bbfea82b8880ed33cdb762aa11fab722a90a24.jpg
<IMAGES_STORE>/thumbs/small/63bbfea82b8880ed33cdb762aa11fab722a90a24.jpg
<IMAGES_STORE>/thumbs/big/63bbfea82b8880ed33cdb762aa11fab722a90a24.jpg
The first one is the full image, as downloaded from the site.
小さな画像をフィルタリングする¶
When using the Images Pipeline, you can drop images which are too small, by
specifying the minimum allowed size in the IMAGES_MIN_HEIGHT
and
IMAGES_MIN_WIDTH
settings.
For example:
IMAGES_MIN_HEIGHT = 110
IMAGES_MIN_WIDTH = 110
注釈
The size constraints don’t affect thumbnail generation at all.
It is possible to set just one size constraint or both. When setting both of them, only images that satisfy both minimum sizes will be saved. For the above example, images of sizes (105 x 105) or (105 x 200) or (200 x 105) will all be dropped because at least one dimension is shorter than the constraint.
By default, there are no size constraints, so all images are processed.
メディアパイプラインの拡張¶
See here the methods that you can override in your custom Files Pipeline:
-
class
scrapy.pipelines.files.
FilesPipeline
¶ -
get_media_requests
(item, info)¶ As seen on the workflow, the pipeline will get the URLs of the images to download from the item. In order to do this, you can override the
get_media_requests()
method and return a Request for each file URL:def get_media_requests(self, item, info): for file_url in item['file_urls']: yield scrapy.Request(file_url)
Those requests will be processed by the pipeline and, when they have finished downloading, the results will be sent to the
item_completed()
method, as a list of 2-element tuples. Each tuple will contain(success, file_info_or_error)
where:success
is a boolean which isTrue
if the image was downloaded successfully orFalse
if it failed for some reasonfile_info_or_error
is a dict containing the following keys (if success isTrue
) or a Twisted Failure if there was a problem.url
- the url where the file was downloaded from. This is the url of the request returned from theget_media_requests()
method.path
- the path (relative toFILES_STORE
) where the file was storedchecksum
- a MD5 hash of the image contents
The list of tuples received by
item_completed()
is guaranteed to retain the same order of the requests returned from theget_media_requests()
method.Here’s a typical value of the
results
argument:[(True, {'checksum': '2b00042f7481c7b056c4b410d28f33cf', 'path': 'full/0a79c461a4062ac383dc4fade7bc09f1384a3910.jpg', 'url': 'http://www.example.com/files/product1.pdf'}), (False, Failure(...))]
By default the
get_media_requests()
method returnsNone
which means there are no files to download for the item.
-
item_completed
(results, item, info)¶ The
FilesPipeline.item_completed()
method called when all file requests for a single item have completed (either finished downloading, or failed for some reason).The
item_completed()
method must return the output that will be sent to subsequent item pipeline stages, so you must return (or drop) the item, as you would in any pipeline.Here is an example of the
item_completed()
method where we store the downloaded file paths (passed in results) in thefile_paths
item field, and we drop the item if it doesn’t contain any files: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") item['file_paths'] = file_paths return item
By default, the
item_completed()
method returns the item.
-
See here the methods that you can override in your custom Images Pipeline:
-
class
scrapy.pipelines.images.
ImagesPipeline
¶ - The
ImagesPipeline
is an extension of theFilesPipeline
, customizing the field names and adding custom behavior for images.-
get_media_requests
(item, info)¶ Works the same way as
FilesPipeline.get_media_requests()
method, but using a different field name for image urls.Must return a Request for each image URL.
-
item_completed
(results, item, info)¶ The
ImagesPipeline.item_completed()
method is called when all image requests for a single item have completed (either finished downloading, or failed for some reason).Works the same way as
FilesPipeline.item_completed()
method, but using a different field names for storing image downloading results.By default, the
item_completed()
method returns the item.
-
カスタムイメージのパイプラインの例¶
Here is a full example of the Images Pipeline whose methods are examplified above:
import scrapy
from scrapy.pipelines.images import ImagesPipeline
from scrapy.exceptions import DropItem
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")
item['image_paths'] = image_paths
return item
スパイダーのデプロイ¶
このセクションでは, Scrapy のスパイダーを定期的に実行するためのさまざまなオプションについて説明します. あなたのローカルマシンで Scrapy のスパイダーを実行するは,(早期の)開発段階にとっては非常に便利ですが, ロングランニングスパイダーを実行したり, スパイダーを継続的に稼動させたりするには現実的ではありません. ここでは, Scrapy のスパイダーをデプロイするためのソリューションを提案します.
Scrapyのスパイダーを展開するためのオプティカルな選択肢は:
- Scrapyd (open source)
- Scrapy Cloud (cloud-based)
Scrapyd サーバーへのデプロイ¶
Scrapyd は Scrapy のスパイダーを実行するためのオープンソースのアプリケーションです. これは, HTTP API を備えたサーバーを提供し, Scrapy スパイダーの実行および監視することができます.
スパイダーを Scrapyd にデプロイするには, scrapyd-client パッケージが提供する scrapyd-deploy ツールを使用します. 詳細については, scrapyd-deploy documentation を参照してください.
Scrapyd は何人かの Scrapy 開発者によって維持されています.
Scrapy Cloud へのデプロイ¶
Scrapy Cloud はScrapyの背後にある Scrapinghub, のホスティング型のクラウドベースのサービスです.
Scrapy Cloud は, サーバーのセットアップと監視の必要性を排除し, スパイダーを管理し, スクラップされたアイテム, ログ, 統計情報を確認するための優れたUIを提供します.
Scrapy Cloud にスパイダーをデプロイするには, shub コマンドラインツールを使用します. 詳細については, Scrapy Cloud documentation を参照してください.
Scrapy Cloud はScrapydと互換性があり, 必要に応じてそれらの間を切り替えることができます.
scrapyd-deploy
と同様に scrapy.cfg
ファイルから読みこまれます.
AutoThrottle 拡張機能¶
これは, ScrapyサーバーとクロールしているWebサイトの両方の負荷に基づいてクロール速度を自動的に調整する拡張機能です.
設計目標¶
- 既定のダウンロード遅延ゼロを使用する代わりに, サイトをより良くする
- 自動的に最適なクロール速度に調整し, ユーザーはダウンロード遅延をチューニングして最適なものを見つける必要がない. ユーザーは許可する同時要求の最大数を指定するだけで, 残りの部分は拡張機能で処理する.
使い方¶
AutoThrottle拡張機能はダウンロード遅延を動的に調整して, スパイダーが
AUTOTHROTTLE_TARGET_CONCURRENCY
の同時リクエストを各リモートWebサイトに送信します.
ダウンロード待ち時間を使用して遅延を計算します.
主な考え方は次のとおりです: サーバが応答するのに 待ち時間
が必要な場合, クライアントは
N
個の要求を並行して処理するために, 各 待ち時間/ N
秒間に要求を送信する必要があります.
遅延を調整する代わりに, 一定のダウンロード遅延を設定し,
CONCURRENT_REQUESTS_PER_DOMAIN
または
CONCURRENT_REQUESTS_PER_IP
オプションを使用して並行性に厳しい制限を課すことができます.
同様の効果が得られますが, いくつかの重要な違いがあります:
- ダウンロードの遅延が小さいため, 時折リクエストが激しくなります.
- 多くの場合, non-200 (エラー) レスポンスは通常の応答より速く返される可能性があるため, サーバーがエラーを返すようになると, ダウンロードの遅延が少なく, 並行処理の制限が厳しいため, クローラはサーバーに要求を高速に送信します. しかし, これはクローラが行うべきこととは反対です. エラーの場合, 遅くするのがより理にかなっています.
オートスロットルにはこれらの問題はありません.
スロットルアルゴリズム¶
オートスロットルアルゴリズムは, 次のルールに基づいてダウンロードの遅延を調整します:
- スパイダーは常に
AUTOTHROTTLE_START_DELAY
のダウンロード遅延で始まります. - レスポンスが受信されると, ターゲットダウンロード遅延は,
latency
がレスポンスのレイテンシであるlatency / N
として計算されます.N
はAUTOTHROTTLE_TARGET_CONCURRENCY
の値です. - 次の要求のダウンロード遅延は, 前回のダウンロード遅延と目標のダウンロード遅延の平均値に設定されます.
- レイテンシの non-200 レスポンス待ち時間は遅延を減少させることができません.
- ダウンロードの遅延が
DOWNLOAD_DELAY
より小さくなることも,AUTOTHROTTLE_MAX_DELAY
より大きくなることもできません.
注釈
AutoThrottle拡張機能は, 標準的なScrapyの設定の並行性と遅延を優先します.
これは, CONCURRENT_REQUESTS_PER_DOMAIN
オプションと
CONCURRENT_REQUESTS_PER_IP
オプションを尊重し, ダウンロード遅延を
DOWNLOAD_DELAY
よりも低く設定しないことを意味します.
Scrapyでは, ダウンロードの待ち時間は, TCP接続を確立してからHTTPヘッダーを受信するまでの経過時間として測定されます.
これらのレイテンシは, Scrapyがスパイダーコールバックを処理するのに忙しく, ダウンロードに参加できないために, 協調的なマルチタスク環境では正確に測定することが非常に難しいことに注意してください. しかし, これらのレイテンシは, Scrapy(そして最終的にはサーバー)がどの程度忙しいかについての妥当な見積もりを与えるはずであり, この拡張はその前提に基づいています.
設定¶
オートスロットルエクステンションを制御するための設定以下です:
AUTOTHROTTLE_ENABLED
AUTOTHROTTLE_START_DELAY
AUTOTHROTTLE_MAX_DELAY
AUTOTHROTTLE_DEBUG
CONCURRENT_REQUESTS_PER_DOMAIN
CONCURRENT_REQUESTS_PER_IP
DOWNLOAD_DELAY
詳細については, 使い方 を参照してください.
AUTOTHROTTLE_TARGET_CONCURRENCY¶
バージョン 1.1 で追加.
デフォルト: 1.0
リモートWebサイトと並行して送信する必要があるリクエストの平均数.
デフォルトでは, AutoThrottleは, 1つの同時リクエストを各リモートWebサイトに送信する遅延を調整します.
このオプションをより高い値(たとえば 2.0
)に設定すると, リモートサーバーのスループットと負荷が増加します.
AUTOTHROTTLE_TARGET_CONCURRENCY
が小さいほど( 0.5
など), クローラはより控えめで丁寧なものになります.
AutoThrottle拡張機能が有効な場合, CONCURRENT_REQUESTS_PER_DOMAIN
および CONCURRENT_REQUESTS_PER_IP
オプションは引き続き考慮されます. This means that if
AUTOTHROTTLE_TARGET_CONCURRENCY
が
CONCURRENT_REQUESTS_PER_DOMAIN
または
CONCURRENT_REQUESTS_PER_IP
より高い値に設定されていると, クローラはこの数の同時要求に達しません.
与えられたすべての時点で, Scrapyは AUTOTHROTTLE_TARGET_CONCURRENCY
よりも多かれ少なかれ並行した要求を送ることができます.
クローラがアプローチしようとする推奨値であり, ハードな制限ではありません.
AUTOTHROTTLE_DEBUG¶
デフォルト: False
受信したすべてのレスポンスの統計情報を表示する AutoThrottle デバッグモードを有効にすると, 調整パラメータがリアルタイムでどのように調整されているかがわかります.
ベンチマーク¶
バージョン 0.17 で追加.
Scrapyには, ローカルのHTTPサーバーを生成し, 最大限の速度でクロールする単純なベンチマークスイートが付属しています. このベンチマークの目的は, 比較のための共通ベースラインを得るために, Scrapyがハードウェアでどのように機能するかを理解することです. ベンチマークには, 何もせず, リンクをたどる単純なスパイダーが使用されます.
実行するには:
scrapy bench
このような出力が表示されるはずです:
2013-05-16 13:08:46-0300 [scrapy] INFO: Scrapy 0.17.0 started (bot: scrapybot)
2013-05-16 13:08:47-0300 [scrapy] INFO: Spider opened
2013-05-16 13:08:47-0300 [scrapy] INFO: Crawled 0 pages (at 0 pages/min), scraped 0 items (at 0 items/min)
2013-05-16 13:08:48-0300 [scrapy] INFO: Crawled 74 pages (at 4440 pages/min), scraped 0 items (at 0 items/min)
2013-05-16 13:08:49-0300 [scrapy] INFO: Crawled 143 pages (at 4140 pages/min), scraped 0 items (at 0 items/min)
2013-05-16 13:08:50-0300 [scrapy] INFO: Crawled 210 pages (at 4020 pages/min), scraped 0 items (at 0 items/min)
2013-05-16 13:08:51-0300 [scrapy] INFO: Crawled 274 pages (at 3840 pages/min), scraped 0 items (at 0 items/min)
2013-05-16 13:08:52-0300 [scrapy] INFO: Crawled 343 pages (at 4140 pages/min), scraped 0 items (at 0 items/min)
2013-05-16 13:08:53-0300 [scrapy] INFO: Crawled 410 pages (at 4020 pages/min), scraped 0 items (at 0 items/min)
2013-05-16 13:08:54-0300 [scrapy] INFO: Crawled 474 pages (at 3840 pages/min), scraped 0 items (at 0 items/min)
2013-05-16 13:08:55-0300 [scrapy] INFO: Crawled 538 pages (at 3840 pages/min), scraped 0 items (at 0 items/min)
2013-05-16 13:08:56-0300 [scrapy] INFO: Crawled 602 pages (at 3840 pages/min), scraped 0 items (at 0 items/min)
2013-05-16 13:08:57-0300 [scrapy] INFO: Closing spider (closespider_timeout)
2013-05-16 13:08:57-0300 [scrapy] INFO: Crawled 666 pages (at 3840 pages/min), scraped 0 items (at 0 items/min)
2013-05-16 13:08:57-0300 [scrapy] INFO: Dumping Scrapy stats:
{'downloader/request_bytes': 231508,
'downloader/request_count': 682,
'downloader/request_method_count/GET': 682,
'downloader/response_bytes': 1172802,
'downloader/response_count': 682,
'downloader/response_status_count/200': 682,
'finish_reason': 'closespider_timeout',
'finish_time': datetime.datetime(2013, 5, 16, 16, 8, 57, 985539),
'log_count/INFO': 14,
'request_depth_max': 34,
'response_received_count': 682,
'scheduler/dequeued': 682,
'scheduler/dequeued/memory': 682,
'scheduler/enqueued': 12767,
'scheduler/enqueued/memory': 12767,
'start_time': datetime.datetime(2013, 5, 16, 16, 8, 47, 676539)}
2013-05-16 13:08:57-0300 [scrapy] INFO: Spider closed (closespider_timeout)
これは, Scrapyを実行しているハードウェアで毎分約3900ページをクロールできることを示しています. これはリンクをたどることを目的とした非常にシンプルなスパイダーであることに注意してください. カスタムスパイダーを作成すると, クロール速度が遅くなるほど多くの処理が行われます. どのくらい遅くなるかは, あなたのスパイダーがどれくらいのことをしているか, どの程度うまく書かれているかによって決まります.
将来, 他の一般的なシナリオをカバーするために, ベンチマークスイートにさらに多くのケースが追加される予定です.
ジョブ: クロールの一時停止と再開¶
大規模なサイトでは, クロールを一時停止してから後で再開できるようにすることが望ましい場合があります.
Scrapy は, 以下の機能により, この機能を使用できます:
- スケジュールされた要求をディスクに保存するスケジューラ
- ディスクに訪問要求を継続する重複フィルタ
- バッチ間で永続的なスパイダー状態(キーと値のペア)を維持する拡張機能
ジョブディレクトリ¶
永続性サポートを有効にするには, JOBDIR
設定を使用してジョブディレクトリを定義するだけです.
このディレクトリは, 単一のジョブ(つまり, スパイダ実行)の状態を保持するために必要なすべてのデータを格納するためのディレクトリです.
このディレクトリは, 単一のジョブの状態を格納するために使用されるため,
異なるスパイダ, または同じスパイダの異なるジョブ・実行間で共有されてはならないことに注意することが重要です.
使用方法¶
持続性がサポートされているスパイダーを起動するには, 次のように実行します:
scrapy crawl somespider -s JOBDIR=crawls/somespider-1
その後, いつでも(Ctrl-Cを押すかシグナルを送信することによって)スパイダーを安全に停止し, 後で同じコマンドを発行して再開することができます:
scrapy crawl somespider -s JOBDIR=crawls/somespider-1
バッチ間で永続的な状態を維持する¶
一時停止/再開バッチの間にスパイダーの状態を維持したい場合があります.
これには, spider.state
属性を使用できます. これは dict
でなければなりません.
スパイダーの起動と停止時に, ジョブディレクトリからその属性をシリアル化,
格納, ロードするための拡張機能が組み込まれています.
以下は, スパイダーの状態を使用するコールバックの例です(簡潔にするために他のスパイダーコードは省略されています):
def parse_item(self, response):
# parse item here
self.state['items_count'] = self.state.get('items_count', 0) + 1
持続性の落とし穴¶
Scrapyの永続性サポートを使用できるようにするには, 次の点に注意してください.
Cookieの有効期限¶
クッキーの有効期限が切れる可能性があります. したがって, スパイダーをすぐに再開しないと, スケジュールされたリクエストはすぐに機能しなくなる可能性があります. スパイダーがクッキーに依存していない場合, これは問題にはなりません.
シリアル化を要求する¶
永続性を機能させるためには, リクエストが pickle
モジュールによって直列化可能でなければならないため,
リクエストが直列化可能であることを確認する必要があります.
最も一般的な問題は, 永続化できない要求コールバックに対して lambda
関数を使用することです.
語
例えば, これはうまくいきません:
def some_callback(self, response):
somearg = 'test'
return scrapy.Request('http://www.example.com', callback=lambda r: self.other_callback(r, somearg))
def other_callback(self, response, somearg):
print "the argument passed is:", somearg
しかし, これはうまくいきます:
def some_callback(self, response):
somearg = 'test'
return scrapy.Request('http://www.example.com', callback=self.other_callback, meta={'somearg': somearg})
def other_callback(self, response):
somearg = response.meta['somearg']
print "the argument passed is:", somearg
シリアライズできなかったリクエストを記録する場合は, プロジェクトの設定ページで
SCHEDULER_DEBUG
設定を True
に設定します.
デフォルトでは False
です.
- よくある質問
- 最もよく寄せられる質問への回答を得る.
- スパイダーのデバッグ
- スパイダーの一般的な問題をデバッグする方法を学ぶ.
- スパイダーコントラクト
- スパイダーをテストのために使用する方法を学ぶ.
- 一般的なプラクティス
- いくつかの Scrapy の共通プラクティスを理解する.
- ブロードクロール
- 多くのドメインを並行してクロールするための調整.
- スクレイピングにFireFoxを使用する
- Firefoxといくつかの便利なアドオンを使用してスクラップする方法を学ぶ.
- スクレイピングにFirebugを使用する
- Firebugを使って効率的にスクレイプする方法を学ぶ.
- メモリリークのデバッグ
- クローラでメモリリークを見つけて取り除く方法を学ぶ.
- ファイルと画像のダウンロードと処理
- スクラップしたアイテムに関連するファイルや画像をダウンロードする.
- スパイダーのデプロイ
- Scrapyスパイダーをデプロイしてリモートサーバーで実行する.
- AutoThrottle 拡張機能
- 負荷に基づいて動的にクロール速度を調整する.
- ベンチマーク
- あなたのハードウェアでScrapyがどのように機能するかを調べる.
- ジョブ: クロールの一時停止と再開
- 大きなスパイダーのクロールを一時停止して再開する方法を学ぶ.
Scrapy を拡張する¶
アーキテクチャの概要¶
このドキュメントでは, Scrapyのアーキテクチャとそのコンポーネントがどのように相互作用するかについて説明します.
概要¶
次の図は, Scrapy アーキテクチャの概要とそのコンポーネントと, システム内部で実行されるデータフローの概要を示しています(緑色の矢印). コンポーネントの簡単な説明は, それらの詳細な情報については, 以下のリンクを参照してください. データフローも以下で説明します.
データフロー¶

Scrapy のデータフローは実行エンジンによって制御され, 以下のようになります:
- Engine は, Spider からクロールする最初のリクエストを取得します.
- Engine は, Scheduler 内のリクエストをスケジュールし, 次にクロールするリクエストを要求します.
- Scheduler は, 次のリクエストを Engine に渡します.
- Engine は, Downloader Middlewares
を経由して Downloader にリクエストを送信します
(
process_request()
を参照してください). - ページのダウンロードが終了すると,
Downloader はそのページでレスポンスを生成し,
Downloader Middlewares
(
process_response()
を参照してください) を経由して Engine に送信します. - Engine は, レスポンスを Downloader
から受信し, Spider Middleware
(
process_spider_input()
を参照してください) を経由する処理のために Spider に送信します. - Spider はレスポンスを処理し,
Spider Middleware
(
process_spider_output()
を参照してください) を経由して, 収集したアイテムと新しいリクエストを Engine に返します. - The Engine は, 処理されたアイテムを Item Pipelines に渡し, 処理されたリクエストを Scheduler に渡した後, 次のクロールリクエストを要求します.
- このプロセスは, Scheduler からの要求がなくなるまで(ステップ1から)繰り返されます.
コンポーネント¶
Scrapy エンジン¶
エンジンは, システムのすべてのコンポーネント間のデータフローを制御し, 特定のアクションが発生したときにイベントをトリガーします. 詳細については, 上記の データフロー のセクションを参照してください.
スケジューラー¶
スケジューラは, エンジンからリクエストを受信し, エンジンが要求したときに後で(エンジンにも)それらを供給するためにそれらのキューを実行します.
ダウンローダー¶
ダウンローダーは, Web ページを取得してエンジンに供給し, そのエンジンをスパイダーにフィードします.
アイテムパイプライン¶
アイテムパイプラインは, アイテムがスパイダーによって抽出されるとアイテムの処理を行います. 典型的なタスクには, クレンジング, 検証, 永続性(アイテムをデータベースに格納するなど)が含まれます. 詳細は, アイテムパイプライン を参照してください.
ダウンローダーミドルウェア¶
ダウンローダーミドルウェアは, エンジンとダウンローダーの間に位置し, エンジンからダウンローダーに渡されたリクエストと, ダウンローダーからエンジンに渡すレスポンスを処理する特定のフックです.
次のいずれかを実行する必要がある場合は, ダウンローダーミドルウェアを使用します:
- ダウンローダに送信される直前のリクエスト(つまり, Scrapy がリクエストをウェブサイトに送信する直前)を処理する
- 受信したレスポンスをスパイダーに渡す前に変更する
- 受け取ったレスポンスをスパイダーに渡す代わりに新しいリクエストを送信する
- ウェブページを取得せずにスパイダーにレスポンスを渡す
- いくつかのリクエストを実行しない
詳細については, ダウンローダーミドルウェア を参照してください.
スパイダーミドルウェア¶
スパイダーミドルウェアは, エンジンとスパイダーの間に位置し, スパイダーの入力(レスポンス)と出力(アイテムとリクエスト)を処理する特定のフックです.
次のいずれかを実行する必要がある場合は, スパイダーミドルウェアを使用します:
- スパイダーコールバックの後処理出力 - リクエストまたはアイテムの変更/追加/削除
- start_requests の後処理
- スパイダーの例外処理
- レスポンスの内容に基づいてリクエストの一部をコールバックする代わりにerrbackを呼び出す.
詳細については, スパイダーミドルウェア を参照してください.
ダウンローダーミドルウェア¶
ダウンローダーミドルウェアは, Scrapy のリクエスト/レスポンス処理へフックするフレームワークです. Scrapy のリクエストとレスポンスをグローバルに変更するための軽量で低レベルのシステムです.
ダウンローダーミドルウェアの有効化¶
ダウンローダーミドルウェアの有効化をするためには、DOWNLOADER_MIDDLEWARES
に設定してください。
これは辞書であり、キーがミドルウェアクラスパスであり、値はミドルウェアのオーダーであることに注意してください。
例:
DOWNLOADER_MIDDLEWARES = {
'myproject.middlewares.CustomDownloaderMiddleware': 543,
}
DOWNLOADER_MIDDLEWARES
設定はScrapy(オーバーリデンではない)で決められている
:setting:`DOWNLOADER_MIDDLEWARES_BASE`とマージされます。その後、ソートされ実行される順番が決められます。
最初のミドルウェアがエンジンに近く、最後がダウンローダーに近いです。言い換えると、それぞれの:meth:`~scrapy.downloadermiddlewares.DownloaderMiddleware.process_request`メソッドが昇順で(100,200,300..)で実行されていき、それぞれの:meth:`~scrapy.downloadermiddlewares.DownloaderMiddleware.process_response`メソッドが降順で実行されます。
ミドルウェアの順番を決めるためには:setting:`DOWNLOADER_MIDDLEWARES_BASE`を参考にし、値を決める必要があります。順番はそれぞれのミドルウェアの関係性を考慮し決めなくてはなりません。
もしあなたが標準のミドルウェアを実行したくない場合は、DOWNLOADER_MIDDLEWARES
で `None`を設定してください。
例えばあなたがuser-agent middlewareを実行したくない場合は
- DOWNLOADER_MIDDLEWARES = {
- ‘myproject.middlewares.CustomDownloaderMiddleware’: 543, ‘scrapy.downloadermiddlewares.useragent.UserAgentMiddleware’: None,
}
ミドルウェアの中には特別な設定が必要なものもあります。 詳しくはドキュメントを参照してください。
独自のダウンローダーミドルウェアの作成¶
各ミドルウェアコンポーネントは, 以下のメソッドの1つ以上を定義する Python クラスです:
-
class
scrapy.downloadermiddlewares.
DownloaderMiddleware
¶ 注釈
ダウンローダーミドルウェアメソッドのいずれも, 遅延したものを返す可能性があります.
-
process_request
(request, spider)¶ This method is called for each request that goes through the download middleware.
process_request()
should either: returnNone
, return aResponse
object, return aRequest
object, or raiseIgnoreRequest
.If it returns
None
, Scrapy will continue processing this request, executing all other middlewares until, finally, the appropriate downloader handler is called the request performed (and its response downloaded).If it returns a
Response
object, Scrapy won’t bother calling any otherprocess_request()
orprocess_exception()
methods, or the appropriate download function; it’ll return that response. Theprocess_response()
methods of installed middleware is always called on every response.If it returns a
Request
object, Scrapy will stop calling process_request methods and reschedule the returned request. Once the newly returned request is performed, the appropriate middleware chain will be called on the downloaded response.If it raises an
IgnoreRequest
exception, theprocess_exception()
methods of installed downloader middleware will be called. If none of them handle the exception, the errback function of the request (Request.errback
) is called. If no code handles the raised exception, it is ignored and not logged (unlike other exceptions).パラメータ:
-
process_response
(request, response, spider)¶ process_response()
should either: return aResponse
object, return aRequest
object or raise aIgnoreRequest
exception.If it returns a
Response
(it could be the same given response, or a brand-new one), that response will continue to be processed with theprocess_response()
of the next middleware in the chain.If it returns a
Request
object, the middleware chain is halted and the returned request is rescheduled to be downloaded in the future. This is the same behavior as if a request is returned fromprocess_request()
.If it raises an
IgnoreRequest
exception, the errback function of the request (Request.errback
) is called. If no code handles the raised exception, it is ignored and not logged (unlike other exceptions).パラメータ:
-
process_exception
(request, exception, spider)¶ Scrapy calls
process_exception()
when a download handler or aprocess_request()
(from a downloader middleware) raises an exception (including anIgnoreRequest
exception)process_exception()
should return: eitherNone
, aResponse
object, or aRequest
object.If it returns
None
, Scrapy will continue processing this exception, executing any otherprocess_exception()
methods of installed middleware, until no middleware is left and the default exception handling kicks in.If it returns a
Response
object, theprocess_response()
method chain of installed middleware is started, and Scrapy won’t bother calling any otherprocess_exception()
methods of middleware.If it returns a
Request
object, the returned request is rescheduled to be downloaded in the future. This stops the execution ofprocess_exception()
methods of the middleware the same as returning a response would.パラメータ:
-
ビルトインダウンローダーミドルウェアリファレンス¶
This page describes all downloader middleware components that come with Scrapy. For information on how to use them and how to write your own downloader middleware, see the downloader middleware usage guide.
デフォルトで有効になっているコンポーネントの一覧(およびそのオーダー)については,
DOWNLOADER_MIDDLEWARES_BASE
設定を参照してください.
CookiesMiddleware¶
This middleware enables working with sites that require cookies, such as those that use sessions. It keeps track of cookies sent by web servers, and send them back on subsequent requests (from that spider), just like web browsers do.
The following settings can be used to configure the cookie middleware:
スパイダーごとに複数のCookieセッション¶
バージョン 0.15 で追加.
There is support for keeping multiple cookie sessions per spider by using the
cookiejar
Request meta key. By default it uses a single cookie jar
(session), but you can pass an identifier to use different ones.
たとえば:
for i, url in enumerate(urls):
yield scrapy.Request(url, meta={'cookiejar': i},
callback=self.parse_page)
Keep in mind that the cookiejar
meta key is not “sticky”. You need to keep
passing it along on subsequent requests. For example:
def parse_page(self, response):
# do some processing
return scrapy.Request("http://www.example.com/otherpage",
meta={'cookiejar': response.meta['cookiejar']},
callback=self.parse_other_page)
COOKIES_DEBUG¶
デフォルト: False
If enabled, Scrapy will log all cookies sent in requests (ie. Cookie
header) and all cookies received in responses (ie. Set-Cookie
header).
Here’s an example of a log with COOKIES_DEBUG
enabled:
2011-04-06 14:35:10-0300 [scrapy] INFO: Spider opened
2011-04-06 14:35:10-0300 [scrapy] 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] 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] DEBUG: Crawled (200) <GET http://www.diningcity.com/netherlands/index.html> (referer: None)
[...]
DefaultHeadersMiddleware¶
-
class
scrapy.downloadermiddlewares.defaultheaders.
DefaultHeadersMiddleware
¶ This middleware sets all default requests headers specified in the
DEFAULT_REQUEST_HEADERS
setting.
DownloadTimeoutMiddleware¶
-
class
scrapy.downloadermiddlewares.downloadtimeout.
DownloadTimeoutMiddleware
¶ This middleware sets the download timeout for requests specified in the
DOWNLOAD_TIMEOUT
setting ordownload_timeout
spider attribute.
注釈
You can also set download timeout per-request using
download_timeout
Request.meta key; this is supported
even when DownloadTimeoutMiddleware is disabled.
HttpAuthMiddleware¶
-
class
scrapy.downloadermiddlewares.httpauth.
HttpAuthMiddleware
¶ このミドルウェアは, Basic access authentication (別名HTTP認証)を使用して, 特定のスパイダーから生成されたすべてのリクエストを認証します.
特定のスパイダーからHTTP認証を有効にするには, これらのスパイダーの
http_user
およびhttp_pass
属性を設定します.例:
from scrapy.spiders import CrawlSpider class SomeIntranetSiteSpider(CrawlSpider): http_user = 'someuser' http_pass = 'somepass' name = 'intranet.example.com' # .. 残りのスパイダーコードは省略されています ...
HttpCacheMiddleware¶
-
class
scrapy.downloadermiddlewares.httpcache.
HttpCacheMiddleware
¶ このミドルウェアは, すべてのHTTPリクエストとレスポンスに低レベルのキャッシュを提供します. これはキャッシュストレージバックエンドとキャッシュポリシーとを組み合わせなければなりません.
2つのHTTPキャッシュストレージバックエンドを持つ Scrapy:
HTTPキャッシュストレージバックエンドは,
HTTPCACHE_STORAGE
設定で変更できます. また, 独自のストレージバックエンドを実装することもできます.2つのHTTPキャッシュポリシーを持つ Scrapy:
HTTPCACHE_POLICY
設定を使用してHTTPキャッシュポリシーを変更できます. あるいは独自のポリシーを実装することもできます.また,
dont_cache
メタキーを True とすると, すべてのポリシーで応答をキャッシュすることを避けることができます.
ダミーポリシー (デフォルト)¶
このポリシーは, HTTP Cache-Control ディレクティブを意識していません. すべてのリクエストとそれに対応するレスポンスがキャッシュされます. 同じリクエストが再び見られると, インターネットから何も転送せずにレスポンスが返されます.
ダミーポリシーは, スパイダーを素早くテストする(毎回ダウンロードを待たずに), または, インターネット接続が利用できないときにスパイダーをオフラインで試すのに便利です. 目標は, 以前に実行されたとおりにスパイダーの実行を「再生」できるようにすることです.
このポリシーを使用するには:
HTTPCACHE_POLICY
にscrapy.extensions.httpcache.DummyPolicy
を設定します.
RFC2616 ポリシー¶
このポリシーは, HTTPキャッシュ制御の認識を備えた RFC2616 準拠の HTTP キャッシュを提供し, 生産を目的とし, 変更なしのデータのダウンロードを避けるために連続実行で 使用します(帯域幅を節約し, クロールを高速化します).
実装されているもの:
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
何が無くなったか:
- Pragma: no-cache サポート https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.1
- Vary ヘッダーサポート https://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.6
- 更新または削除後の無効化 https://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.10
- ... おそらく他にも ..
このポリシーを使用するには:
HTTPCACHE_POLICY
にscrapy.extensions.httpcache.RFC2616Policy
を設定します.
ファイルシステムストレージバックエンド (デフォルト)¶
ファイルシステムストレージバックエンドは, HTTPキャッシュミドルウェアで使用できます.
このストレージバックエンドを使用するには:
HTTPCACHE_STORAGE
にscrapy.extensions.httpcache.FilesystemCacheStorage
を設定します.
各 request/response のペアは, 次のファイルを含む別のディレクトリに格納されます:
request_body
- the plain request bodyrequest_headers
- the request headers (in raw HTTP format)response_body
- the plain response bodyresponse_headers
- the request headers (in raw HTTP format)meta
- some metadata of this cache resource in Pythonrepr()
format (grep-friendly format)pickled_meta
- the same metadata inmeta
but pickled for more efficient deserialization
ディレクトリ名はリクエストフィンガープリント ( scrapy.utils.request.fingerprint
を参照)から作成され,
1つのレベルのサブディレクトリが, 同じディレクトリにあまりにも多くのファイルを作成することを
避けるために使用されます(多くのファイルシステムでは非効率的です):
/path/to/cache/dir/example.com/72/72811f648e718090f041317756c03adb0ada46c7
DBM ストレージバックエンド¶
バージョン 0.13 で追加.
DBM ストレージバックエンドは, HTTPキャッシュミドルウェアでも使用できます.
デフォルトでは, anydbm モジュールを使用しますが,
HTTPCACHE_DBM_MODULE
設定で変更することができます.
このストレージバックエンドを使用するには:
HTTPCACHE_STORAGE
にscrapy.extensions.httpcache.DbmCacheStorage
を設定します.
LevelDB ストレージバックエンド¶
バージョン 0.23 で追加.
LevelDB ストレージバックエンドは, HTTPキャッシュミドルウェアでも使用できます.
このバックエンドは開発プロセスにはお勧めできません. これは, 同時に1つのプロセスしか LevelDB データベースにアクセスできないためです. そのため, 同じスパイダーに対して並列に Scrapy シェルを開くことはできません.
このストレージバックエンドを使用するには:
HTTPCACHE_STORAGE
にscrapy.extensions.httpcache.LeveldbCacheStorage
を設定しますpip install leveldb
のようにして, LevelDB の Python バインディング をインストールします
HTTPCache middleware 設定¶
HttpCacheMiddleware
は, 次の設定で構成されています:
バージョン 0.11 で追加.
デフォルト: False
HTTPキャッシュを有効にするかどうか.
バージョン 0.11 で変更: 0.11 より前では, キャッシュを有効にするために HTTPCACHE_DIR
が使用されていました.
デフォルト: 0
キャッシュされたリクエストの有効期限(秒単位).
この時間より古いキャッシュされたリクエストは再ダウンロードされます. 0の場合, キャッシュされたリクエストは期限切れになりません.
バージョン 0.11 で変更: 0.11 以前は, 0
はキャッシュされたリクエストが常に期限切れになることを意味しました.
デフォルト: 'httpcache'
(低レベル)HTTPキャッシュを格納するために使用するディレクトリ. 空の場合, HTTPキャッシュは無効になります. 相対パスが指定されている場合は, プロジェクトデータディレクトリに対して相対パスが使用されます. 詳細は, Scrapyプロジェクトのデフォルト構造 を参照してください.
デフォルト: 'scrapy.extensions.httpcache.FilesystemCacheStorage'
キャッシュストレージバックエンドを実装するクラス.
バージョン 0.13 で追加.
デフォルト: 'anydbm'
DBMストレージバックエンド で使用するデータベースモジュール. この設定は, DBMバックエンド特有です.
バージョン 0.18 で追加.
デフォルト: 'scrapy.extensions.httpcache.DummyPolicy'
キャッシュポリシーを実装するクラス.
バージョン 1.0 で追加.
デフォルト: False
有効にすると, キャッシュされたすべてのデータがgzipで圧縮されます. この設定はファイルシステムのバックエンド特有です.
バージョン 1.1 で追加.
デフォルト: False
有効にすると, 無条件にページをキャッシュします.
スパイダーは, Cache-Control: max-stale などを将来使用するために, すべてのレスポンスをキャッシュで利用できるようにすることができます. DummyPolicy はすべてのレスポンスをキャッシュしますが, それを再検証することはありません. また, 別のポリシーが望ましい場合もあります.
この設定は, 依然として Cache-Control: no-store ディレクティブを尊重します. 必要がない場合は, キャッシュミドルウェアにフィードしたレスポンスの Cache-Control ヘッダーから no-store を除外します.
バージョン 1.1 で追加.
デフォルト: []
無視されるレスポンスのキャッシュ制御ディレクティブのリスト.
サイトはしばしば “no-store”, “no-cache”, “must-revalidate”, などを設定しますが, スパイダーがそれらのディレクティブを尊重するならば生成できるトラフィックで動揺します. これにより, クロールしているサイトの重要でないことがわかっている Cache-Control ディレクティブを選択的に無視することができます.
スパイダーは実際に Cache-Control ディレクティブを必要としない限り, Cache-Control ディレクティブを発行しないので, リクエスト内のディレクティブはフィルタリングされません.
HttpCompressionMiddleware¶
-
class
scrapy.downloadermiddlewares.httpcompression.
HttpCompressionMiddleware
¶ このミドルウェアは, 圧縮された(gzip, deflate)トラフィックをWebサイトから送受信できるようにします.
HttpProxyMiddleware¶
バージョン 0.8 で追加.
-
class
scrapy.downloadermiddlewares.httpproxy.
HttpProxyMiddleware
¶ This middleware sets the HTTP proxy to use for requests, by setting the
proxy
meta value forRequest
objects.Like the Python standard library modules urllib and urllib2, it obeys the following environment variables:
http_proxy
https_proxy
no_proxy
You can also set the meta key
proxy
per-request, to a value likehttp://some_proxy_server:port
.
RedirectMiddleware¶
-
class
scrapy.downloadermiddlewares.redirect.
RedirectMiddleware
¶ このミドルウェアは, 応答ステータスに基づいてリクエストのリダイレクトを処理します.
The urls which the request goes through (while being redirected) can be found
in the redirect_urls
Request.meta
key.
The RedirectMiddleware
can be configured through the following
settings (see the settings documentation for more info):
If Request.meta
has dont_redirect
key set to True, the request will be ignored by this middleware.
If you want to handle some redirect status codes in your spider, you can
specify these in the handle_httpstatus_list
spider attribute.
For example, if you want the redirect middleware to ignore 301 and 302 responses (and pass them through to your spider) you can do this:
class MySpider(CrawlSpider):
handle_httpstatus_list = [301, 302]
The handle_httpstatus_list
key of Request.meta
can also be used to specify which response codes to
allow on a per-request basis. You can also set the meta key
handle_httpstatus_all
to True
if you want to allow any response code
for a request.
MetaRefreshMiddleware¶
-
class
scrapy.downloadermiddlewares.redirect.
MetaRefreshMiddleware
¶ このミドルウェアは, メタリフレッシュhtmlタグに基づいてリクエストのリダイレクトを処理します.
The MetaRefreshMiddleware
can be configured through the following
settings (see the settings documentation for more info):
This middleware obey REDIRECT_MAX_TIMES
setting, dont_redirect
and redirect_urls
request meta keys as described for RedirectMiddleware
RetryMiddleware¶
-
class
scrapy.downloadermiddlewares.retry.
RetryMiddleware
¶ A middleware to retry failed requests that are potentially caused by temporary problems such as a connection timeout or HTTP 500 error.
Failed pages are collected on the scraping process and rescheduled at the end, once the spider has finished crawling all regular (non failed) pages. Once there are no more failed pages to retry, this middleware sends a signal (retry_complete), so other extensions could connect to that signal.
The RetryMiddleware
can be configured through the following
settings (see the settings documentation for more info):
If Request.meta
has dont_retry
key
set to True, the request will be ignored by this middleware.
RetryMiddleware 設定¶
デフォルト: [500, 502, 503, 504, 408]
Which HTTP response codes to retry. Other errors (DNS lookup issues, connections lost, etc) are always retried.
In some cases you may want to add 400 to RETRY_HTTP_CODES
because
it is a common code used to indicate server overload. It is not included by
default because HTTP specs say so.
RobotsTxtMiddleware¶
-
class
scrapy.downloadermiddlewares.robotstxt.
RobotsTxtMiddleware
¶ This middleware filters out requests forbidden by the robots.txt exclusion standard.
To make sure Scrapy respects robots.txt make sure the middleware is enabled and the
ROBOTSTXT_OBEY
setting is enabled.
If Request.meta
has
dont_obey_robotstxt
key set to True
the request will be ignored by this middleware even if
ROBOTSTXT_OBEY
is enabled.
DownloaderStats¶
-
class
scrapy.downloadermiddlewares.stats.
DownloaderStats
¶ Middleware that stores stats of all requests, responses and exceptions that pass through it.
To use this middleware you must enable the
DOWNLOADER_STATS
setting.
UserAgentMiddleware¶
-
class
scrapy.downloadermiddlewares.useragent.
UserAgentMiddleware
¶ スパイダーがデフォルトのユーザーエージェントをオーバーライドできるミドルウェア.
In order for a spider to override the default user agent, its user_agent attribute must be set.
AjaxCrawlMiddleware¶
-
class
scrapy.downloadermiddlewares.ajaxcrawl.
AjaxCrawlMiddleware
¶ Middleware that finds ‘AJAX crawlable’ page variants based on meta-fragment html tag. See https://developers.google.com/webmasters/ajax-crawling/docs/getting-started for more info.
注釈
Scrapy finds ‘AJAX crawlable’ pages for URLs like
'http://example.com/!#foo=bar'
even without this middleware. AjaxCrawlMiddleware is necessary when URL doesn’t contain'!#'
. This is often a case for ‘index’ or ‘main’ website pages.
AjaxCrawlMiddleware 設定¶
バージョン 0.21 で追加.
デフォルト: False
Whether the AjaxCrawlMiddleware will be enabled. You may want to enable it for broad crawls.
スパイダーミドルウェア¶
スパイダーミドルウェアは, 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を割り当てる必要があります. たとえば, off-site ミドルウェアを無効にする場合は:
SPIDER_MIDDLEWARES = {
'myproject.middlewares.CustomSpiderMiddleware': 543,
'scrapy.spidermiddlewares.offsite.OffsiteMiddleware': None,
}
最後に, 特定の設定によっていくつかのミドルウェアを有効にする必要があるかもしれないことに留意してください. 詳細は各ミドルウェアのドキュメントを参照してください.
独自のスパイダーミドルウェアの作成¶
各ミドルウェアコンポーネントは, 以下のメソッドの1つ以上を定義する Python クラスです:
-
class
scrapy.spidermiddlewares.
SpiderMiddleware
¶ -
process_spider_input
(response, spider)¶ このメソッドは, 処理のためにスパイダーミドルウェアを経由してスパイダーに入る各レスポンスに対して呼び出されます.
process_spider_input()
は必ずNone
を返すか, または例外を発生させなければいけません.None
を返すと, Scrapy はこのレスポンスの処理を続行し, 最終的にレスポンスが処理のためにスパイダーに渡されるまで他のすべてのミドルウェアを実行します.例外が発生した場合, Scrapy は他のミドルウェアの
process_spider_input()
メソッド呼び出しを無視して errback リクエストを呼び出します. errback の出力は,process_spider_output()
で処理されるか, エラーが発生した場合はprocess_spider_exception()
メソッドにチェーンされて戻ります.パラメータ:
-
process_spider_output
(response, result, spider)¶ このメソッドは, レスポンスを処理した後にスパイダーから返された結果にたいして呼び出されます.
process_spider_output()
は必ずイテラブルなRequest
,dict
またはItem
オブジェクトのいずれかを返す必要があります.パラメータ:
-
process_spider_exception
(response, exception, spider)¶ このメソッドは, スパイダーまたは
process_spider_input()
メソッド (他のスパイダーミドルウェアのもの) が例外を発生させたときに呼び出されます.process_spider_exception()
はNone
, イテラブルなResponse
,dict
またはItem
オブジェクトを返さなければいけません.None
を返すと, Scrapy は, ミドルウェアコンポーネントが残っていない, かつ例外がエンジンに到達するまで, この例外の処理を続け, 次のミドルウェアコンポーネントでprocess_spider_exception()
を実行します.イテラブルを返すと
process_spider_output()
パイプラインが起動し, ほかのprocess_spider_exception()
は呼び出されません.パラメータ:
-
process_start_requests
(start_requests, spider)¶ バージョン 0.15 で追加.
このメソッドはスパイダーの開始要求とともに呼び出され,
process_spider_output()
メソッドと同様に動作します. ただし, レスポンスが関連付けられておらず, リクエスト(項目ではない)のみを返さなければなりません.イテラブル (
start_requests
パラメーター無い) を受取り, イテラブルなRequest
オブジェを返さなければいけません.注釈
このメソッドをスパイダー・ミドルウェアに実装する場合は, 常にiterableを返し,
start_requests
をすべて消費しないようにする必要があります. 非常に大きい(または制限なし)ことがあり, メモリーがオーバーフローする可能性があるからです. Scrapy エンジンは, 開始要求を処理する能力を持っている間に開始要求を引き出すように設計されているため, 開始要求イテレータは, スパイダーを停止するためのその他の条件(時間制限や項目/ページ数など)がある場合には効果的に無限になります.パラメータ:
-
ビルトインスパイダーミドルウェアリファレンス¶
このページでは, Scrapyに付属するすべてのスパイダーミドルウェアコンポーネントについて説明します. それらの使用方法と独自のスパイダーミドルウェアの作成方法については, スパイダーミドルウェア使用方法ガイド を参照してください.
デフォルトで有効になっているコンポーネントの一覧(およびそのオーダー)については,
SPIDER_MIDDLEWARES_BASE
設定を参照してください.
DepthMiddleware¶
-
class
scrapy.spidermiddlewares.depth.
DepthMiddleware
¶ DepthMiddleware は, スクレイプされているサイト内の各リクエストの深さを追跡するために使用されるスクレイプミドルウェアです. これは, スクレイピングなのどの最大深さを制限するために使用することができます.
DepthMiddleware
は以下の設定で設定することができます(詳細については各設定を参照してください):DEPTH_LIMIT
- クロールできる最大の深さ. ゼロの場合, 制限は課されません.DEPTH_STATS
- 深度統計を収集するかどうか.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.meta
の handle_httpstatus_list
キーを使用して, リクエストごとに許可するレスポンスコードを指定することもできます.
リクエストにすべてのレスポンスコードを許可させる場合は, meta キー handle_httpstatus_all
を True
に設定することもできます.
しかし, あなた自身が何を行いたいかを本当に理解していない限り, 200以外の回答をむやみに処理することは, 通常は悪い考えです.
詳細については, HTTP Status Code Definitions を参照してください.
OffsiteMiddleware¶
-
class
scrapy.spidermiddlewares.offsite.
OffsiteMiddleware
¶ スパイダーがカバーするドメイン外のURLに対するリクエストをフィルタリングします.
このミドルウェアは, スパイダーの
allowed_domains
属性にないホスト名を持つすべてのリクエストをフィルタリングします. リスト内の任意のドメインのすべてのサブドメインも許可されます. 例えば, ルールにwww.example.org
が指定されている場合でもbob.www.example.org
は許可されますが,www2.example.com
やexample.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
¶ リクエストの
Referer
ヘッダーに, レスポンスのURLに基づいてヘッダーを挿入します.
UrlLengthMiddleware¶
-
class
scrapy.spidermiddlewares.urllength.
UrlLengthMiddleware
¶ URL が URLLENGTH_LIMIT より長い場合, リクエストをフィルタリングします
The
UrlLengthMiddleware
は, 以下の設定によって構成することができます(詳細については, 設定ドキュメントを参照してください):URLLENGTH_LIMIT
- クロールするURLで許可されるURLの最大長.
拡張機能¶
The extensions framework provides a mechanism for inserting your own custom functionality into Scrapy.
Extensions are just regular classes that are instantiated at Scrapy startup, when extensions are initialized.
拡張機能設定¶
Extensions use the Scrapy settings to manage their settings, just like any other Scrapy code.
It is customary for extensions to prefix their settings with their own name, to avoid collision with existing (and future) extensions. For example, a hypothetic extension to handle Google Sitemaps would use settings like GOOGLESITEMAP_ENABLED, GOOGLESITEMAP_DEPTH, and so on.
拡張機能の読み込みと有効化¶
Extensions are loaded and activated at startup by instantiating a single
instance of the extension class. Therefore, all the extension initialization
code must be performed in the class constructor (__init__
method).
To make an extension available, add it to the EXTENSIONS
setting in
your Scrapy settings. In EXTENSIONS
, each extension is represented
by a string: the full Python path to the extension’s class name. For example:
EXTENSIONS = {
'scrapy.extensions.corestats.CoreStats': 500,
'scrapy.extensions.telnet.TelnetConsole': 500,
}
As you can see, the EXTENSIONS
setting is a dict where the keys are
the extension paths, and their values are the orders, which define the
extension loading order. The EXTENSIONS
setting is merged with the
EXTENSIONS_BASE
setting defined in Scrapy (and not meant to be
overridden) and then sorted by order to get the final sorted list of enabled
extensions.
As extensions typically do not depend on each other, their loading order is
irrelevant in most cases. This is why the EXTENSIONS_BASE
setting
defines all extensions with the same order (0
). However, this feature can
be exploited if you need to add an extension which depends on other extensions
already loaded.
利用可能, 有効, 無効な拡張機能¶
Not all available extensions will be enabled. Some of them usually depend on a
particular setting. For example, the HTTP Cache extension is available by default
but disabled unless the HTTPCACHE_ENABLED
setting is set.
拡張機能の無効化¶
In order to disable an extension that comes enabled by default (ie. those
included in the EXTENSIONS_BASE
setting) you must set its order to
None
. For example:
EXTENSIONS = {
'scrapy.extensions.corestats.CoreStats': None,
}
独自の拡張機能を書く¶
Each extension is a Python class. The main entry point for a Scrapy extension
(this also includes middlewares and pipelines) is the from_crawler
class method which receives a Crawler
instance. Through the Crawler object
you can access settings, signals, stats, and also control the crawling behaviour.
Typically, extensions connect to signals and perform tasks triggered by them.
Finally, if the from_crawler
method raises the
NotConfigured
exception, the extension will be
disabled. Otherwise, the extension will be enabled.
かんたんな拡張機能¶
Here we will implement a simple extension to illustrate the concepts described in the previous section. This extension will log a message every time:
- a spider is opened
- a spider is closed
- a specific number of items are scraped
The extension will be enabled through the MYEXT_ENABLED
setting and the
number of items will be specified through the MYEXT_ITEMCOUNT
setting.
Here is the code of such extension:
import logging
from scrapy import signals
from scrapy.exceptions import NotConfigured
logger = logging.getLogger(__name__)
class SpiderOpenCloseLogging(object):
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
¶
Log basic stats like crawled pages and scraped items.
コア統計拡張機能¶
-
class
scrapy.extensions.corestats.
CoreStats
¶
Enable the collection of core statistics, provided the stats collection is enabled (see 統計コレクション).
Telnetコンソール拡張機能¶
-
class
scrapy.extensions.telnet.
TelnetConsole
¶
Provides a telnet console for getting into a Python interpreter inside the currently running Scrapy process, which can be very useful for debugging.
The telnet console must be enabled by the TELNETCONSOLE_ENABLED
setting, and the server will listen in the port specified in
TELNETCONSOLE_PORT
.
メモリ使用量拡張機能¶
-
class
scrapy.extensions.memusage.
MemoryUsage
¶
注釈
This extension does not work in Windows.
Monitors the memory used by the Scrapy process that runs the spider and:
- sends a notification e-mail when it exceeds a certain value
- closes the spider when it exceeds a certain value
The notification e-mails can be triggered when a certain warning value is
reached (MEMUSAGE_WARNING_MB
) and when the maximum value is reached
(MEMUSAGE_LIMIT_MB
) which will also cause the spider to be closed
and the Scrapy process to be terminated.
This extension is enabled by the MEMUSAGE_ENABLED
setting and
can be configured with the following settings:
メモリデバッガ拡張機能¶
-
class
scrapy.extensions.memdebug.
MemoryDebugger
¶
An extension for debugging memory usage. It collects information about:
- objects uncollected by the Python garbage collector
- objects left alive that shouldn’t. For more info, see trackref でメモリリークのデバッグをする
To enable this extension, turn on the MEMDEBUG_ENABLED
setting. The
info will be stored in the stats.
クローズスパイダー拡張機能¶
-
class
scrapy.extensions.closespider.
CloseSpider
¶
Closes a spider automatically when some conditions are met, using a specific closing reason for each condition.
The conditions for closing a spider can be configured through the following settings:
Default: 0
An integer which specifies a number of seconds. If the spider remains open for
more than that number of second, it will be automatically closed with the
reason closespider_timeout
. If zero (or non set), spiders won’t be closed by
timeout.
Default: 0
An integer which specifies a number of items. If the spider scrapes more than
that amount if items and those items are passed by the item pipeline, the
spider will be closed with the reason closespider_itemcount
. If zero (or
non set), spiders won’t be closed by number of passed items.
バージョン 0.11 で追加.
Default: 0
An integer which specifies the maximum number of responses to crawl. If the spider
crawls more than that, the spider will be closed with the reason
closespider_pagecount
. If zero (or non set), spiders won’t be closed by
number of crawled responses.
バージョン 0.11 で追加.
Default: 0
An integer which specifies the maximum number of errors to receive before
closing the spider. If the spider generates more than that number of errors,
it will be closed with the reason closespider_errorcount
. If zero (or non
set), spiders won’t be closed by number of errors.
StatsMailer 拡張機能¶
-
class
scrapy.extensions.statsmailer.
StatsMailer
¶
This simple extension can be used to send a notification e-mail every time a
domain has finished scraping, including the Scrapy stats collected. The email
will be sent to all recipients specified in the STATSMAILER_RCPTS
setting.
デバッギング拡張機能¶
スタックトレースダンプ拡張¶
-
class
scrapy.extensions.debug.
StackTraceDump
¶
Dumps information about the running process when a SIGQUIT or SIGUSR2 signal is received. The information dumped is the following:
- engine status (using
scrapy.utils.engine.get_engine_status()
) - live references (see trackref でメモリリークのデバッグをする)
- stack trace of all threads
After the stack trace and engine status is dumped, the Scrapy process continues running normally.
This extension only works on POSIX-compliant platforms (ie. not Windows), because the SIGQUIT and SIGUSR2 signals are not available on Windows.
There are at least two ways to send Scrapy the SIGQUIT signal:
By pressing Ctrl-while a Scrapy process is running (Linux only?)
By running this command (assuming
<pid>
is the process id of the Scrapy process):kill -QUIT <pid>
デバッガ拡張機能¶
-
class
scrapy.extensions.debug.
Debugger
¶
Invokes a Python debugger inside a running Scrapy process when a SIGUSR2 signal is received. After the debugger is exited, the Scrapy process continues running normally.
For more info see Debugging in Python.
This extension only works on POSIX-compliant platforms (ie. not Windows).
コア API¶
バージョン 0.15 で追加.
このセクションは, ScrapyコアAPIについて説明します. 拡張APIやミドルウェアの開発者向けです.
クローラー API¶
Scrapy API の主なエントリポイントは, from_crawler
メソッドを使用して拡張機能に渡される
Crawler
オブジェクトです.
このオブジェクトはすべての Scrapy コアコンポーネントへのアクセスを提供し,
拡張機能がそれらにアクセスして機能を Scrapy に引き込む唯一の方法です.
拡張機能マネージャーは, インストールされている拡張機能の読み込みと追跡を担当しており, 使用可能なすべての拡張機能の辞書と,
ダウンローダーミドルウェアの設定
方法と同様の命令を含む EXTENSIONS
設定によって構成されています.
-
class
scrapy.crawler.
Crawler
(spidercls, settings)¶ Crawler オブジェクトは,
scrapy.spiders.Spider
サブクラスとscrapy.settings.Settings
オブジェクトでインスタンス化する必要があります.-
settings
¶ クローラの設定マネージャ.
これは, このクローラーのScrapy設定にアクセスするために拡張機能とミドルウェアによって使用されます.
詳細については, 設定 を参照してください.
APIについては,
Settings
クラスを参照してください.
-
signals
¶ クローラーの信号マネージャ.
これは, 拡張機能とミドルウェアがScrapy機能にフックするために使用されます.
詳細については, シグナル を参照してください.
APIについては,
SignalManager
クラスを参照してください.
-
stats
¶ クローラーの統計コレクタ.
これは, エクステンションとミドルウェアから自分の行動の統計情報を記録したり, 他の拡張機能によって収集された統計情報にアクセスするために使用されます.
詳細については 統計コレクション を参照してください.
API については
StatsCollector
クラスを参照してください.
-
extensions
¶ 有効な拡張機能を追跡する拡張マネージャー.
ほとんどの拡張機能はこの属性にアクセスする必要はありません.
拡張機能の紹介とScrapyの利用可能な拡張機能のリストについては, 拡張機能 を参照してください.
-
engine
¶ 実行エンジン. スケジューラ, ダウンローダ, およびスパイダ間のコアクロールロジックを調整します.
Scrapy エンジンにアクセスして, ダウンローダとスケジューラの動作を検査または変更したい場合にしようできます. ただし, これは高度な使い方であり, APIはまだ安定していません.
-
spider
¶ Spider currently being crawled. クローラの構築中に提供されるspiderクラスのインスタンスであり,
crawl()
メソッドで指定された引数の後に作成されます.
-
crawl
(*args, **kwargs)¶ クローラー開始時に, 指定された args および kwargs 引数を使用してスパイダーをインスタンス化し, 実行エンジンの動作を設定します.
クロールが終了したときに発生する遅延を返します.
-
-
class
scrapy.crawler.
CrawlerRunner
(settings=None)¶ This is a convenient helper class that keeps track of, manages and runs crawlers inside an already setup Twisted 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.
パラメータ:
-
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.
-
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)¶ ベースクラス:
scrapy.crawler.CrawlerRunner
A class to run multiple scrapy crawlers in a process simultaneously.
This class extends
CrawlerRunner
by adding support for starting a Twisted 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 Twisted reactor within your application.The CrawlerProcess 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.
パラメータ:
-
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.
-
start
(stop_after_crawl=True)¶ This method starts a Twisted reactor, adjusts its pool size to
REACTOR_THREADPOOL_MAXSIZE
, and installs a DNS cache based onDNSCACHE_ENABLED
andDNSCACHE_SIZE
.If stop_after_crawl is True, the reactor will be stopped after all crawlers have finished, using
join()
.パラメータ: stop_after_crawl (boolean) – 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)¶ Small helper function that looks up a given string priority in the
SETTINGS_PRIORITIES
dictionary and returns its numerical value, or directly returns a given numerical priority.
-
class
scrapy.settings.
Settings
(values=None, priority='project')¶ ベースクラス:
scrapy.settings.BaseSettings
This object stores Scrapy settings for the configuration of internal components, and can be used for any further customization.
It is a direct subclass and supports all methods of
BaseSettings
. Additionally, after instantiation of this class, the new object will have the global default settings described on ビルトイン設定リファレンス already populated.
-
class
scrapy.settings.
BaseSettings
(values=None, priority='project')¶ Instances of this class behave like dictionaries, but store priorities along with their
(key, value)
pairs, and can be frozen (i.e. marked immutable).Key-value entries can be passed on initialization with the
values
argument, and they would take thepriority
level (unlessvalues
is already an instance ofBaseSettings
, in which case the existing priority levels will be kept). If thepriority
argument is a string, the priority name will be looked up inSETTINGS_PRIORITIES
. Otherwise, a specific integer should be provided.Once the object is created, new settings can be loaded or updated with the
set()
method, and can be accessed with the square bracket notation of dictionaries, or with theget()
method of the instance and its value conversion variants. When requesting a stored key, the value with the highest priority will be retrieved.-
copy
()¶ Make a deep copy of current settings.
This method returns a new instance of the
Settings
class, populated with the same values and their priorities.Modifications to the new object won’t be reflected on the original settings.
-
copy_to_dict
()¶ Make a copy of current settings and convert to a dict.
This method returns a new dict populated with the same values and their priorities as the current settings.
Modifications to the returned dict won’t be reflected on the original settings.
This method can be useful for example for printing settings in Scrapy shell.
-
freeze
()¶ Disable further changes to the current settings.
After calling this method, the present state of the settings will become immutable. Trying to change values through the
set()
method and its variants won’t be possible and will be alerted.
-
frozencopy
()¶ Return an immutable copy of the current settings.
-
get
(name, default=None)¶ Get a setting value without affecting its original type.
パラメータ: - name (string) – the setting name
- default (any) – the value to return if no setting is found
-
getbool
(name, default=False)¶ Get a setting value as a boolean.
1
,'1'
, andTrue
returnTrue
, while0
,'0'
,False
andNone
returnFalse
.For example, settings populated through environment variables set to
'0'
will returnFalse
when using this method.パラメータ: - name (string) – the setting name
- default (any) – the value to return if no setting is found
-
getdict
(name, default=None)¶ Get a setting value as a dictionary. If the setting original type is a dictionary, a copy of it will be returned. If it is a string it will be evaluated as a JSON dictionary. In the case that it is a
BaseSettings
instance itself, it will be converted to a dictionary, containing all its current settings values as they would be returned byget()
, and losing all information about priority and mutability.パラメータ: - name (string) – the setting name
- default (any) – the value to return if no setting is found
-
getfloat
(name, default=0.0)¶ Get a setting value as a float.
パラメータ: - name (string) – the setting name
- default (any) – the value to return if no setting is found
-
getint
(name, default=0)¶ Get a setting value as an int.
パラメータ: - name (string) – the setting name
- default (any) – the value to return if no setting is found
-
getlist
(name, default=None)¶ Get a setting value as a list. If the setting original type is a list, a copy of it will be returned. If it’s a string it will be split by ”,”.
For example, settings populated through environment variables set to
'one,two'
will return a list [‘one’, ‘two’] when using this method.パラメータ: - name (string) – the setting name
- default (any) – the value to return if no setting is found
-
getpriority
(name)¶ Return the current numerical priority value of a setting, or
None
if the givenname
does not exist.パラメータ: name (string) – the setting name
-
getwithbase
(name)¶ Get a composition of a dictionary-like setting and its _BASE counterpart.
パラメータ: name (string) – name of the dictionary-like setting
-
maxpriority
()¶ Return the numerical value of the highest priority present throughout all settings, or the numerical value for
default
fromSETTINGS_PRIORITIES
if there are no settings stored.
-
set
(name, value, priority='project')¶ Store a key/value attribute with a given priority.
Settings should be populated before configuring the Crawler object (through the
configure()
method), otherwise they won’t have any effect.パラメータ: - name (string) – the setting name
- value (any) – the value to associate with the setting
- priority (string or int) – the priority of the setting. Should be a key of
SETTINGS_PRIORITIES
or an integer
-
setmodule
(module, priority='project')¶ Store settings from a module with a given priority.
This is a helper function that calls
set()
for every globally declared uppercase variable ofmodule
with the providedpriority
.パラメータ: - module (module object or string) – the module or the path of the module
- priority (string or int) – the priority of the settings. Should be a key of
SETTINGS_PRIORITIES
or an integer
-
update
(values, priority='project')¶ Store key/value pairs with a given priority.
This is a helper function that calls
set()
for every item ofvalues
with the providedpriority
.If
values
is a string, it is assumed to be JSON-encoded and parsed into a dict withjson.loads()
first. If it is aBaseSettings
instance, the per-key priorities will be used and thepriority
parameter ignored. This allows inserting/updating settings with different priorities with a single command.パラメータ: - values (dict or string or
BaseSettings
) – the settings names and values - priority (string or int) – the priority of the settings. Should be a key of
SETTINGS_PRIORITIES
or an integer
- values (dict or string or
-
スパイダーローダー API¶
-
class
scrapy.loader.
SpiderLoader
¶ このクラスは, プロジェクト全体で定義されたスパイダークラスの取得と処理を担当します.
SPIDER_LOADER_CLASS
プロジェクト設定でパスを指定することで, カスタムスパイダーローダーを使用できます. エラーのない実行を保証するためにscrapy.interfaces.ISpiderLoader
インタフェースを完全に実装する必要があります.-
from_settings
(settings)¶ このクラスメソッドは, クラスのインスタンスを作成するためにScrapyによって使用されます. プロジェクト設定で呼び出され,
SPIDER_MODULES
設定で指定したモジュール内で再帰的に見つかったスパイダーをロードします.パラメータ: settings ( Settings
インスタンス) – プロジェクト設定
-
load
(spider_name)¶ Spider クラスを指定された名前で取得します. 以前に読み込まれたスパイダーのうち, spider_name という名前の Spider クラスが検索され, 見つからなければ KeyError が発生します.
パラメータ: spider_name (str) – Spider クラス名
-
list
()¶ プロジェクトで利用可能なスパイダーの名前を取得する.
-
シグナル 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.
パラメータ: - receiver (callable) – the function to be connected
- signal (object) – the signal to connect to
-
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 deferreds 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
クラスで定義されたStatsコレクタAPIを実装しています(すべて継承しています).
-
class
scrapy.statscollectors.
StatsCollector
¶ -
get_value
(key, default=None)¶ 指定されたstatsキーの値を返します. 存在しない場合はdefaultを返します.
-
get_stats
()¶ 現在実行中のスパイダーからすべての統計情報を dict として取得します.
-
set_value
(key, value)¶ 与えられた stats キーに与えられた値を設定します.
-
set_stats
(stats)¶ stats
引数に渡された dict で現在の統計をオーバーライドします.
-
inc_value
(key, count=1, start=0)¶ 指定された統計値キーの値を与えられた数だけ増やします(設定されていない場合は, 与えられた開始値を仮定する).
-
max_value
(key, value)¶ 指定されたキーの現在の値が
value
よりも小さい場合にのみ, 指定されたキーの値にvalue
を設定します. 指定されたキーに現在の値がない場合, 値は常に設定されます.
-
min_value
(key, value)¶ 指定されたキーの現在の値が
value
より大きい場合にのみ, 指定されたキーの値にvalue
を設定します. 指定されたキーに現在の値がない場合, 値は常に設定されます.
-
clear_stats
()¶ すべての統計情報をクリアします.
次のメソッドは, 統計収集APIの一部ではなく, カスタム統計コレクタを実装するときに使用されます:
-
open_spider
(spider)¶ 統計収集のために指定されたスパイダーを開きます.
-
close_spider
(spider)¶ 指定されたスパイダーを閉じます. これが呼び出された後, 特定の統計情報にアクセスまたは収集することはできません.
-
シグナル¶
Scrapy uses signals extensively to notify when certain events occur. You can catch some of those signals in your Scrapy project (using an extension, for example) to perform additional tasks or extend Scrapy to add functionality not provided out of the box.
Even though signals provide several arguments, the handlers that catch them don’t need to accept all of them - the signal dispatching mechanism will only deliver the arguments that the handler receives.
You can connect to signals (or send your own) through the シグナル API.
Here is a simple example showing how you can catch signals and perform some action:
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
遅延シグナルハンドラ¶
Some signals support returning Twisted deferreds from their handlers, see the ビルトインシグナルリファレンス below to know which ones.
ビルトインシグナルリファレンス¶
Scrapy のビルトインシグナルのリストとその意味は次のとおりです.
engine_started¶
-
scrapy.signals.
engine_started
()¶ Sent when the Scrapy engine has started crawling.
This signal supports returning deferreds from their handlers.
注釈
This signal may be fired after the spider_opened
signal,
depending on how the spider was started. So don’t rely on this signal
getting fired before spider_opened
.
engine_stopped¶
-
scrapy.signals.
engine_stopped
()¶ Sent when the Scrapy engine is stopped (for example, when a crawling process has finished).
This signal supports returning deferreds from their handlers.
item_scraped¶
-
scrapy.signals.
item_scraped
(item, response, spider)¶ Sent when an item has been scraped, after it has passed all the アイテムパイプライン stages (without being dropped).
This signal supports returning deferreds from their handlers.
パラメータ:
item_dropped¶
-
scrapy.signals.
item_dropped
(item, response, exception, spider)¶ Sent after an item has been dropped from the アイテムパイプライン when some stage raised a
DropItem
exception.This signal supports returning deferreds from their handlers.
パラメータ: - item (dict or
Item
object) – the item dropped from the アイテムパイプライン - spider (
Spider
object) – the spider which scraped the item - response (
Response
object) – the response from where the item was dropped - exception (
DropItem
exception) – the exception (which must be aDropItem
subclass) which caused the item to be dropped
- item (dict or
spider_closed¶
-
scrapy.signals.
spider_closed
(spider, reason)¶ Sent after a spider has been closed. This can be used to release per-spider resources reserved on
spider_opened
.This signal supports returning deferreds from their handlers.
パラメータ: - spider (
Spider
object) – the spider which has been closed - reason (str) – a string which describes the reason why the spider was closed. If
it was closed because the spider has completed scraping, the reason
is
'finished'
. Otherwise, if the spider was manually closed by calling theclose_spider
engine method, then the reason is the one passed in thereason
argument of that method (which defaults to'cancelled'
). If the engine was shutdown (for example, by hitting Ctrl-C to stop it) the reason will be'shutdown'
.
- spider (
spider_opened¶
-
scrapy.signals.
spider_opened
(spider)¶ Sent after a spider has been opened for crawling. This is typically used to reserve per-spider resources, but can be used for any task that needs to be performed when a spider is opened.
This signal supports returning deferreds from their handlers.
パラメータ: spider ( Spider
object) – the spider which has been opened
spider_idle¶
-
scrapy.signals.
spider_idle
(spider)¶ Sent when a spider has gone idle, which means the spider has no further:
- requests waiting to be downloaded
- requests scheduled
- items being processed in the item pipeline
If the idle state persists after all handlers of this signal have finished, the engine starts closing the spider. After the spider has finished closing, the
spider_closed
signal is sent.You can, for example, schedule some requests in your
spider_idle
handler to prevent the spider from being closed.This signal does not support returning deferreds from their handlers.
パラメータ: spider ( Spider
object) – the spider which has gone idle
spider_error¶
-
scrapy.signals.
spider_error
(failure, response, spider)¶ Sent when a spider callback generates an error (ie. raises an exception).
This signal does not support returning deferreds from their handlers.
パラメータ:
request_scheduled¶
request_dropped¶
response_received¶
アイテムエクスポーター¶
アイテムを集めたら, そのアイテムを永続化またはエクスポートして, 他のアプリケーションでデータを使用することがしばしばあります. つまり, 結局のところ, スクレイピング工程の全目的です.
この目的のため, Scrapy は, XML, CSV, JSON などのさまざまな出力形式に対しアイテムエクスポーターのコレクションを提供します.
アイテムエクスポーターを使う¶
あなたが急いでいて, アイテムエクスポータを使用してスクレイピングしたデータを出力したい場合は, フィードのエクスポート を参照してください. そうではなく, アイテムエクスポータがどのように機能するかを知りたい, もしくは (デフォルトのエクスポートでカバーされていない)カスタム機能をもっと必要とする場合は以下をお読みください.
アイテムエクスポーターを使用するには, 必要な引数でインスタンス化する必要があります. 各エクスポーターは異なる引数を必要とするため, in ビルトインアイテムエクスポーターリファレンス を参照してください. エクスポーターのインスタンスを作成した後は, 以下の作業を行う必要があります:
- エクスポートプロセスの開始を知らせるために
start_exporting()
メソッドを呼び出します. - エクスポートする各アイテムの
export_item()
メソッドを呼び出します. - 最後に
finish_exporting()
メソッドを呼び出してエクスポートプロセスの終了を知らせます.
ここで アイテムパイプライン を使用して, スクレイピングしたアイテムを異なるファイルにエクスポートするアイテムパイプライン(スパイダーごとに1つ)の例を紹介します:
from scrapy import signals
from scrapy.exporters import XmlItemExporter
class XmlExportPipeline(object):
def __init__(self):
self.files = {}
@classmethod
def from_crawler(cls, crawler):
pipeline = cls()
crawler.signals.connect(pipeline.spider_opened, signals.spider_opened)
crawler.signals.connect(pipeline.spider_closed, signals.spider_closed)
return pipeline
def spider_opened(self, spider):
file = open('%s_products.xml' % spider.name, 'w+b')
self.files[spider] = file
self.exporter = XmlItemExporter(file)
self.exporter.start_exporting()
def spider_closed(self, spider):
self.exporter.finish_exporting()
file = self.files.pop(spider)
file.close()
def process_item(self, item, spider):
self.exporter.export_item(item)
return item
アイテムフィールドのシリアル化¶
デフォルトでは, フィールド値は未変更のシリアル化ライブラリに渡され, シリアル化する方法の決定権は各シリアル化ライブラリに委譲されます.
ただし, 各フィールドの値がシリアライゼーションライブラリに渡される前に, シリアライズされる方法をカスタマイズできます.
フィールドのシリアル化方法をカスタマイズするには, 次の2つの方法があります.
1. フィールド内のシリアライザの宣言¶
Item
を使用する場合,
フィールドメタデータ でシリアライザを宣言できます.
シリアライザは, 呼び出し可能な値を受け取ってシリアル化された値を返す形式でなければなりません.
例:
import scrapy
def serialize_price(value):
return '$ %s' % 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 '$ %s' % str(value)
return super(Product, self).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')¶ これは, すべてのアイテムエクスポータの(抽象)基本クラスです. エクスポートするフィールドの定義, 空のフィールドのエクスポートの指定, 使用するエンコーディングなど, すべての(具体的な)アイテムエクスポータで使用される共通の機能をサポートしています.
これらの機能は,
fields_to_export
,export_empty_fields
,encoding
のそれぞれのインスタンス属性を設定するコンストラクタ引数で設定できます.-
export_item
(item)¶
指定された項目をエクスポートします. このメソッドはサブクラスで実装する必要があります.
-
serialize_field
(field, name, value)¶
指定されたフィールドの直列化された値を返します. 特定のフィールドまたは値のシリアライズ/エクスポートの方法を制御する場合は,
カスタムアイテムエクスポータでこのメソッドをオーバーライドできます.- デフォルトでは、このメソッドは フィールドで宣言された シリアライザを検索し,
- そのシリアライザをその値に適用した結果を返します.
シリアライザが見つからない場合,
encoding
属性で宣言されたエンコーディングを使用して
エンコードされた
str
のunicode
値を除いて, 値は変更されません.param field: フィールドはシリアル化されています。 生の dict がエクスポートされている場合(
Item
ではなく)*フィールド* 値は空の dict です. :type field:Field
オブジェクトまたは空の dictparam name: シリアル化されているフィールドの名前 type name: str :param value: シリアル化された値
-
start_exporting
()¶ - エクスポートプロセスの開始を知らせます.
一部のエクスポーターは, これを使用して必要なヘッダー(たとえば,
XmlItemExporter
)を生成することがあります. アイテムをエクスポートする前に, このメソッドを呼び出す必要があります.-
finish_exporting
()¶ エクスポートプロセスの終了を知らせます.
一部のエクスポーターは, これを使用して必要なフッター (たとえば,
XmlItemExporter
のような)を生成することがあります. エクスポートする項目がなくなったら, 必ずこのメソッドを呼び出す必要があります.-
fields_to_export
¶
エクスポートされるフィールドの名前を持つリスト, またはすべてのフィールドをエクスポートする場合は None です. デフォルトは None です.
一部のエクスポーター (
CsvItemExporter
など) は, この属性で定義されたフィールドの順序を尊重します.いくつかのエクスポーターは, スパイダーが (
Item
インスタンスでない) dictsを返すとき, データを適切にエクスポートするために fields_to_export リストを要求することがあります.-
export_empty_fields
¶ エクスポートされたデータに空のフィールドフィールドまたは空になっていないアイテムフィールドを含めるかどうか.
デフォルトは
False
です. 一部のエクスポーター (CsvItemExporter
など) はこの属性を無視し、空のフィールドを常にエクスポートします. このオプションは dict 項目では無視されます.-
encoding
¶
Unicode値をエンコードするために使用されるエンコード. これはUnicode値にのみ影響します(このエンコーディングを使用してstrに常にシリアル化されます). 他の値の型は, 変更されずに特定の直列化ライブラリに渡されます.
-
-
XmlItemExporter¶
-
class
scrapy.exporters.
XmlItemExporter
(file, item_element='item', root_element='items', **kwargs)¶ Exports Items in XML format to the specified file object.
パラメータ: - file – the file-like object to use for exporting the data.
- root_element (str) – The name of root element in the exported XML.
- item_element (str) – The name of each item element in the exported XML.
The additional keyword arguments of this constructor are passed to the
BaseItemExporter
constructor.A typical output of this exporter would be:
<?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>
Unless overridden in the
serialize_field()
method, multi-valued fields are exported by serializing each value inside a<value>
element. This is for convenience, as multi-valued fields are very common.For example, the item:
Item(name=['John', 'Doe'], age='23')
Would be serialized as:
<?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=', ', **kwargs)¶ Exports Items in CSV format to the given file-like object. If the
fields_to_export
attribute is set, it will be used to define the CSV columns and their order. Theexport_empty_fields
attribute has no effect on this exporter.パラメータ: - file – the file-like object to use for exporting the data.
- include_headers_line (str) – If enabled, makes the exporter output a header
line with the field names taken from
BaseItemExporter.fields_to_export
or the first exported item fields. - join_multivalued – The char (or chars) that will be used for joining multi-valued fields, if found.
The additional keyword arguments of this constructor are passed to the
BaseItemExporter
constructor, and the leftover arguments to the csv.writer constructor, so you can use any csv.writer constructor argument to customize this exporter.A typical output of this exporter would be:
product,price Color TV,1200 DVD player,200
PickleItemExporter¶
-
class
scrapy.exporters.
PickleItemExporter
(file, protocol=0, **kwargs)¶ Exports Items in pickle format to the given file-like object.
パラメータ: - file – the file-like object to use for exporting the data.
- protocol (int) – The pickle protocol to use.
For more information, refer to the pickle module documentation.
The additional keyword arguments of this constructor are passed to the
BaseItemExporter
constructor.Pickle isn’t a human readable format, so no output examples are provided.
PprintItemExporter¶
-
class
scrapy.exporters.
PprintItemExporter
(file, **kwargs)¶ Exports Items in pretty print format to the specified file object.
パラメータ: file – the file-like object to use for exporting the data. The additional keyword arguments of this constructor are passed to the
BaseItemExporter
constructor.A typical output of this exporter would be:
{'name': 'Color TV', 'price': '1200'} {'name': 'DVD player', 'price': '200'}
Longer lines (when present) are pretty-formatted.
JsonItemExporter¶
-
class
scrapy.exporters.
JsonItemExporter
(file, **kwargs)¶ Exports Items in JSON format to the specified file-like object, writing all objects as a list of objects. The additional constructor arguments are passed to the
BaseItemExporter
constructor, and the leftover arguments to the JSONEncoder constructor, so you can use any JSONEncoder constructor argument to customize this exporter.パラメータ: file – the file-like object to use for exporting the data. A typical output of this exporter would be:
[{"name": "Color TV", "price": "1200"}, {"name": "DVD player", "price": "200"}]
警告
JSON is very simple and flexible serialization format, but it doesn’t scale well for large amounts of data since incremental (aka. stream-mode) parsing is not well supported (if at all) among JSON parsers (on any language), and most of them just parse the entire object in memory. If you want the power and simplicity of JSON with a more stream-friendly format, consider using
JsonLinesItemExporter
instead, or splitting the output in multiple chunks.
JsonLinesItemExporter¶
-
class
scrapy.exporters.
JsonLinesItemExporter
(file, **kwargs)¶ Exports Items in JSON format to the specified file-like object, writing one JSON-encoded item per line. The additional constructor arguments are passed to the
BaseItemExporter
constructor, and the leftover arguments to the JSONEncoder constructor, so you can use any JSONEncoder constructor argument to customize this exporter.パラメータ: file – the file-like object to use for exporting the data. A typical output of this exporter would be:
{"name": "Color TV", "price": "1200"} {"name": "DVD player", "price": "200"}
Unlike the one produced by
JsonItemExporter
, the format produced by this exporter is well suited for serializing large amounts of data.
- アーキテクチャの概要
- Scrapyアーキテクチャを理解する.
- ダウンローダーミドルウェア
- ページのリクエスト数とダウンロードのカスタマイズする.
- スパイダーミドルウェア
- スパイダーの入力と出力をカスタマイズする.
- 拡張機能
- カスタム機能でScrapyを拡張する.
- コア API
- 拡張機能やミドルウェアでそれを使ってScrapy機能を拡張する.
- シグナル
- 利用可能なすべてのシグナルとそれらを操作する方法を見る.
- アイテムエクスポーター
- スクラップしたアイテムをファイルにすばやくエクスポートする (XML, CSV, etc).
残りのすべて¶
リリースノート¶
Scrapy 1.2.2 (2016-12-06)¶
Bug fixes¶
- Fix a cryptic traceback when a pipeline fails on
open_spider()
(issue 2011) - Fix embedded IPython shell variables (fixing issue 396 that re-appeared in 1.2.0, fixed in issue 2418)
- A couple of patches when dealing with robots.txt:
- handle (non-standard) relative sitemap URLs (issue 2390)
- handle non-ASCII URLs and User-Agents in Python 2 (issue 2373)
Documentation¶
- Document
"download_latency"
key inRequest
‘smeta
dict (issue 2033) - Remove page on (deprecated & unsupported) Ubuntu packages from ToC (issue 2335)
- A few fixed typos (issue 2346, issue 2369, issue 2369, issue 2380) and clarifications (issue 2354, issue 2325, issue 2414)
Other changes¶
- Advertize conda-forge as Scrapy’s official conda channel (issue 2387)
- More helpful error messages when trying to use
.css()
or.xpath()
on non-Text Responses (issue 2264) startproject
command now generates a samplemiddlewares.py
file (issue 2335)- Add more dependencies’ version info in
scrapy version
verbose output (issue 2404) - Remove all
*.pyc
files from source distribution (issue 2386)
Scrapy 1.2.1 (2016-10-21)¶
Bug fixes¶
- Include OpenSSL’s more permissive default ciphers when establishing TLS/SSL connections (issue 2314).
- Fix “Location” HTTP header decoding on non-ASCII URL redirects (issue 2321).
Documentation¶
- Fix JsonWriterPipeline example (issue 2302).
- Various notes: issue 2330 on spider names, issue 2329 on middleware methods processing order, issue 2327 on getting multi-valued HTTP headers as lists.
Other changes¶
- Removed
www.
fromstart_urls
in built-in spider templates (issue 2299).
Scrapy 1.2.0 (2016-10-03)¶
New Features¶
- New
FEED_EXPORT_ENCODING
setting to customize the encoding used when writing items to a file. This can be used to turn off\uXXXX
escapes in JSON output. This is also useful for those wanting something else than UTF-8 for XML or CSV output (issue 2034). startproject
command now supports an optional destination directory to override the default one based on the project name (issue 2005).- New
SCHEDULER_DEBUG
setting to log requests serialization failures (issue 1610). - JSON encoder now supports serialization of
set
instances (issue 2058). - Interpret
application/json-amazonui-streaming
asTextResponse
(issue 1503). scrapy
is imported by default when using shell tools (shell
, inspect_response) (issue 2248).
Bug fixes¶
- DefaultRequestHeaders middleware now runs before UserAgent middleware (issue 2088). Warning: this is technically backwards incompatible, though we consider this a bug fix.
- HTTP cache extension and plugins that use the
.scrapy
data directory now work outside projects (issue 1581). Warning: this is technically backwards incompatible, though we consider this a bug fix. Selector
does not allow passing bothresponse
andtext
anymore (issue 2153).- Fixed logging of wrong callback name with
scrapy parse
(issue 2169). - Fix for an odd gzip decompression bug (issue 1606).
- Fix for selected callbacks when using
CrawlSpider
withscrapy parse
(issue 2225). - Fix for invalid JSON and XML files when spider yields no items (issue 872).
- Implement
flush()
fprStreamLogger
avoiding a warning in logs (issue 2125).
Refactoring¶
canonicalize_url
has been moved to w3lib.url (issue 2168).
Tests & Requirements¶
Scrapy’s new requirements baseline is Debian 8 “Jessie”. It was previously Ubuntu 12.04 Precise. What this means in practice is that we run continuous integration tests with these (main) packages versions at a minimum: Twisted 14.0, pyOpenSSL 0.14, lxml 3.4.
Scrapy may very well work with older versions of these packages (the code base still has switches for older Twisted versions for example) but it is not guaranteed (because it’s not tested anymore).
Documentation¶
- Grammar fixes: issue 2128, issue 1566.
- Download stats badge removed from README (issue 2160).
- New scrapy architecture diagram (issue 2165).
- Updated
Response
parameters documentation (issue 2197). - Reworded misleading
RANDOMIZE_DOWNLOAD_DELAY
description (issue 2190). - Add StackOverflow as a support channel (issue 2257).
Scrapy 1.1.3 (2016-09-22)¶
Bug fixes¶
- Class attributes for subclasses of
ImagesPipeline
andFilesPipeline
work as they did before 1.1.1 (issue 2243, fixes issue 2198)
Documentation¶
- Overview and tutorial rewritten to use http://toscrape.com websites (issue 2236, issue 2249, issue 2252).
Scrapy 1.1.2 (2016-08-18)¶
Bug fixes¶
- Introduce a missing
IMAGES_STORE_S3_ACL
setting to override the default ACL policy inImagesPipeline
when uploading images to S3 (note that default ACL policy is “private” – instead of “public-read” – since Scrapy 1.1.0) IMAGES_EXPIRES
default value set back to 90 (the regression was introduced in 1.1.1)
Scrapy 1.1.1 (2016-07-13)¶
Bug fixes¶
- Add “Host” header in CONNECT requests to HTTPS proxies (issue 2069)
- Use response
body
when choosing response class (issue 2001, fixes issue 2000) - Do not fail on canonicalizing URLs with wrong netlocs (issue 2038, fixes issue 2010)
- a few fixes for
HttpCompressionMiddleware
(andSitemapSpider
):- Do not decode HEAD responses (issue 2008, fixes issue 1899)
- Handle charset parameter in gzip Content-Type header (issue 2050, fixes issue 2049)
- Do not decompress gzip octet-stream responses (issue 2065, fixes issue 2063)
- Catch (and ignore with a warning) exception when verifying certificate against IP-address hosts (issue 2094, fixes issue 2092)
- Make
FilesPipeline
andImagesPipeline
backward compatible again regarding the use of legacy class attributes for customization (issue 1989, fixes issue 1985)
New features¶
- Enable genspider command outside project folder (issue 2052)
- Retry HTTPS CONNECT
TunnelError
by default (issue 1974)
Documentation¶
FEED_TEMPDIR
setting at lexicographical position (commit 9b3c72c)- Use idiomatic
.extract_first()
in overview (issue 1994) - Update years in copyright notice (commit c2c8036)
- Add information and example on errbacks (issue 1995)
- Use “url” variable in downloader middleware example (issue 2015)
- Grammar fixes (issue 2054, issue 2120)
- New FAQ entry on using BeautifulSoup in spider callbacks (issue 2048)
- Add notes about scrapy not working on Windows with Python 3 (issue 2060)
- Encourage complete titles in pull requests (issue 2026)
Tests¶
- Upgrade py.test requirement on Travis CI and Pin pytest-cov to 2.2.1 (issue 2095)
Scrapy 1.1.0 (2016-05-11)¶
This 1.1 release brings a lot of interesting features and bug fixes:
- Scrapy 1.1 has beta Python 3 support (requires Twisted >= 15.5). See Beta Python 3 Support for more details and some limitations.
- Hot new features:
- Item loaders now support nested loaders (issue 1467).
FormRequest.from_response
improvements (issue 1382, issue 1137).- Added setting
AUTOTHROTTLE_TARGET_CONCURRENCY
and improved AutoThrottle docs (issue 1324). - Added
response.text
to get body as unicode (issue 1730). - Anonymous S3 connections (issue 1358).
- Deferreds in downloader middlewares (issue 1473). This enables better robots.txt handling (issue 1471).
- HTTP caching now follows RFC2616 more closely, added settings
HTTPCACHE_ALWAYS_STORE
andHTTPCACHE_IGNORE_RESPONSE_CACHE_CONTROLS
(issue 1151). - Selectors were extracted to the parsel library (issue 1409). This means you can use Scrapy Selectors without Scrapy and also upgrade the selectors engine without needing to upgrade Scrapy.
- HTTPS downloader now does TLS protocol negotiation by default,
instead of forcing TLS 1.0. You can also set the SSL/TLS method
using the new
DOWNLOADER_CLIENT_TLS_METHOD
.
- These bug fixes may require your attention:
- Don’t retry bad requests (HTTP 400) by default (issue 1289).
If you need the old behavior, add
400
toRETRY_HTTP_CODES
. - Fix shell files argument handling (issue 1710, issue 1550).
If you try
scrapy shell index.html
it will try to load the URL http://index.html, usescrapy shell ./index.html
to load a local file. - Robots.txt compliance is now enabled by default for newly-created projects
(issue 1724). Scrapy will also wait for robots.txt to be downloaded
before proceeding with the crawl (issue 1735). If you want to disable
this behavior, update
ROBOTSTXT_OBEY
insettings.py
file after creating a new project. - Exporters now work on unicode, instead of bytes by default (issue 1080).
If you use
PythonItemExporter
, you may want to update your code to disable binary mode which is now deprecated. - Accept XML node names containing dots as valid (issue 1533).
- When uploading files or images to S3 (with
FilesPipeline
orImagesPipeline
), the default ACL policy is now “private” instead of “public” Warning: backwards incompatible!. You can useFILES_STORE_S3_ACL
to change it. - We’ve reimplemented
canonicalize_url()
for more correct output, especially for URLs with non-ASCII characters (issue 1947). This could change link extractors output compared to previous scrapy versions. This may also invalidate some cache entries you could still have from pre-1.1 runs. Warning: backwards incompatible!.
- Don’t retry bad requests (HTTP 400) by default (issue 1289).
If you need the old behavior, add
Keep reading for more details on other improvements and bug fixes.
Beta Python 3 Support¶
We have been hard at work to make Scrapy run on Python 3. As a result, now you can run spiders on Python 3.3, 3.4 and 3.5 (Twisted >= 15.5 required). Some features are still missing (and some may never be ported).
Almost all builtin extensions/middlewares are expected to work. However, we are aware of some limitations in Python 3:
- Scrapy does not work on Windows with Python 3
- Sending emails is not supported
- FTP download handler is not supported
- Telnet console is not supported
Additional New Features and Enhancements¶
- Scrapy now has a Code of Conduct (issue 1681).
- Command line tool now has completion for zsh (issue 934).
- Improvements to
scrapy shell
:- Support for bpython and configure preferred Python shell via
SCRAPY_PYTHON_SHELL
(issue 1100, issue 1444). - Support URLs without scheme (issue 1498) Warning: backwards incompatible!
- Bring back support for relative file path (issue 1710, issue 1550).
- Support for bpython and configure preferred Python shell via
- Added
MEMUSAGE_CHECK_INTERVAL_SECONDS
setting to change default check interval (issue 1282). - Download handlers are now lazy-loaded on first request using their scheme (issue 1390, issue 1421).
- HTTPS download handlers do not force TLS 1.0 anymore; instead,
OpenSSL’s
SSLv23_method()/TLS_method()
is used allowing to try negotiating with the remote hosts the highest TLS protocol version it can (issue 1794, issue 1629). RedirectMiddleware
now skips the status codes fromhandle_httpstatus_list
on spider attribute or inRequest
‘smeta
key (issue 1334, issue 1364, issue 1447).- Form submission:
- now works with
<button>
elements too (issue 1469). - an empty string is now used for submit buttons without a value (issue 1472)
- now works with
- Dict-like settings now have per-key priorities (issue 1135, issue 1149 and issue 1586).
- Sending non-ASCII emails (issue 1662)
CloseSpider
andSpiderState
extensions now get disabled if no relevant setting is set (issue 1723, issue 1725).- Added method
ExecutionEngine.close
(issue 1423). - Added method
CrawlerRunner.create_crawler
(issue 1528). - Scheduler priority queue can now be customized via
SCHEDULER_PRIORITY_QUEUE
(issue 1822). .pps
links are now ignored by default in link extractors (issue 1835).- temporary data folder for FTP and S3 feed storages can be customized
using a new
FEED_TEMPDIR
setting (issue 1847). FilesPipeline
andImagesPipeline
settings are now instance attributes instead of class attributes, enabling spider-specific behaviors (issue 1891).JsonItemExporter
now formats opening and closing square brackets on their own line (first and last lines of output file) (issue 1950).- If available,
botocore
is used forS3FeedStorage
,S3DownloadHandler
andS3FilesStore
(issue 1761, issue 1883). - Tons of documentation updates and related fixes (issue 1291, issue 1302, issue 1335, issue 1683, issue 1660, issue 1642, issue 1721, issue 1727, issue 1879).
- Other refactoring, optimizations and cleanup (issue 1476, issue 1481, issue 1477, issue 1315, issue 1290, issue 1750, issue 1881).
Deprecations and Removals¶
- Added
to_bytes
andto_unicode
, deprecatedstr_to_unicode
andunicode_to_str
functions (issue 778). binary_is_text
is introduced, to replace use ofisbinarytext
(but with inverse return value) (issue 1851)- The
optional_features
set has been removed (issue 1359). - The
--lsprof
command line option has been removed (issue 1689). Warning: backward incompatible, but doesn’t break user code. - The following datatypes were deprecated (issue 1720):
scrapy.utils.datatypes.MultiValueDictKeyError
scrapy.utils.datatypes.MultiValueDict
scrapy.utils.datatypes.SiteNode
- The previously bundled
scrapy.xlib.pydispatch
library was deprecated and replaced by pydispatcher.
Relocations¶
telnetconsole
was relocated toextensions/
(issue 1524).- Note: telnet is not enabled on Python 3 (https://github.com/scrapy/scrapy/pull/1524#issuecomment-146985595)
Bugfixes¶
- Scrapy does not retry requests that got a
HTTP 400 Bad Request
response anymore (issue 1289). Warning: backwards incompatible! - Support empty password for http_proxy config (issue 1274).
- Interpret
application/x-json
asTextResponse
(issue 1333). - Support link rel attribute with multiple values (issue 1201).
- Fixed
scrapy.http.FormRequest.from_response
when there is a<base>
tag (issue 1564). - Fixed
TEMPLATES_DIR
handling (issue 1575). - Various
FormRequest
fixes (issue 1595, issue 1596, issue 1597). - Makes
_monkeypatches
more robust (issue 1634). - Fixed bug on
XMLItemExporter
with non-string fields in items (issue 1738). - Fixed startproject command in OS X (issue 1635).
- Fixed PythonItemExporter and CSVExporter for non-string item types (issue 1737).
- Various logging related fixes (issue 1294, issue 1419, issue 1263, issue 1624, issue 1654, issue 1722, issue 1726 and issue 1303).
- Fixed bug in
utils.template.render_templatefile()
(issue 1212). - sitemaps extraction from
robots.txt
is now case-insensitive (issue 1902). - HTTPS+CONNECT tunnels could get mixed up when using multiple proxies to same remote host (issue 1912).
Scrapy 1.0.6 (2016-05-04)¶
- FIX: RetryMiddleware is now robust to non-standard HTTP status codes (issue 1857)
- FIX: Filestorage HTTP cache was checking wrong modified time (issue 1875)
- DOC: Support for Sphinx 1.4+ (issue 1893)
- DOC: Consistency in selectors examples (issue 1869)
Scrapy 1.0.5 (2016-02-04)¶
- FIX: [Backport] Ignore bogus links in LinkExtractors (fixes issue 907, commit 108195e)
- TST: Changed buildbot makefile to use ‘pytest’ (commit 1f3d90a)
- DOC: Fixed typos in tutorial and media-pipeline (commit 808a9ea and commit 803bd87)
- DOC: Add AjaxCrawlMiddleware to DOWNLOADER_MIDDLEWARES_BASE in settings docs (commit aa94121)
Scrapy 1.0.4 (2015-12-30)¶
- Ignoring xlib/tx folder, depending on Twisted version. (commit 7dfa979)
- Run on new travis-ci infra (commit 6e42f0b)
- Spelling fixes (commit 823a1cc)
- escape nodename in xmliter regex (commit da3c155)
- test xml nodename with dots (commit 4418fc3)
- TST don’t use broken Pillow version in tests (commit a55078c)
- disable log on version command. closes #1426 (commit 86fc330)
- disable log on startproject command (commit db4c9fe)
- Add PyPI download stats badge (commit df2b944)
- don’t run tests twice on Travis if a PR is made from a scrapy/scrapy branch (commit a83ab41)
- Add Python 3 porting status badge to the README (commit 73ac80d)
- fixed RFPDupeFilter persistence (commit 97d080e)
- TST a test to show that dupefilter persistence is not working (commit 97f2fb3)
- explicit close file on file:// scheme handler (commit d9b4850)
- Disable dupefilter in shell (commit c0d0734)
- DOC: Add captions to toctrees which appear in sidebar (commit aa239ad)
- DOC Removed pywin32 from install instructions as it’s already declared as dependency. (commit 10eb400)
- Added installation notes about using Conda for Windows and other OSes. (commit 1c3600a)
- Fixed minor grammar issues. (commit 7f4ddd5)
- fixed a typo in the documentation. (commit b71f677)
- Version 1 now exists (commit 5456c0e)
- fix another invalid xpath error (commit 0a1366e)
- fix ValueError: Invalid XPath: //div/[id=”not-exists”]/text() on selectors.rst (commit ca8d60f)
- Typos corrections (commit 7067117)
- fix typos in downloader-middleware.rst and exceptions.rst, middlware -> middleware (commit 32f115c)
- Add note to ubuntu install section about debian compatibility (commit 23fda69)
- Replace alternative OSX install workaround with virtualenv (commit 98b63ee)
- Reference Homebrew’s homepage for installation instructions (commit 1925db1)
- Add oldest supported tox version to contributing docs (commit 5d10d6d)
- Note in install docs about pip being already included in python>=2.7.9 (commit 85c980e)
- Add non-python dependencies to Ubuntu install section in the docs (commit fbd010d)
- Add OS X installation section to docs (commit d8f4cba)
- DOC(ENH): specify path to rtd theme explicitly (commit de73b1a)
- minor: scrapy.Spider docs grammar (commit 1ddcc7b)
- Make common practices sample code match the comments (commit 1b85bcf)
- nextcall repetitive calls (heartbeats). (commit 55f7104)
- Backport fix compatibility with Twisted 15.4.0 (commit b262411)
- pin pytest to 2.7.3 (commit a6535c2)
- Merge pull request #1512 from mgedmin/patch-1 (commit 8876111)
- Merge pull request #1513 from mgedmin/patch-2 (commit 5d4daf8)
- Typo (commit f8d0682)
- Fix list formatting (commit 5f83a93)
- fix scrapy squeue tests after recent changes to queuelib (commit 3365c01)
- Merge pull request #1475 from rweindl/patch-1 (commit 2d688cd)
- Update tutorial.rst (commit fbc1f25)
- Merge pull request #1449 from rhoekman/patch-1 (commit 7d6538c)
- Small grammatical change (commit 8752294)
- Add openssl version to version command (commit 13c45ac)
Scrapy 1.0.3 (2015-08-11)¶
- add service_identity to scrapy install_requires (commit cbc2501)
- Workaround for travis#296 (commit 66af9cd)
Scrapy 1.0.2 (2015-08-06)¶
- Twisted 15.3.0 does not raises PicklingError serializing lambda functions (commit b04dd7d)
- Minor method name fix (commit 6f85c7f)
- minor: scrapy.Spider grammar and clarity (commit 9c9d2e0)
- Put a blurb about support channels in CONTRIBUTING (commit c63882b)
- Fixed typos (commit a9ae7b0)
- Fix doc reference. (commit 7c8a4fe)
Scrapy 1.0.1 (2015-07-01)¶
- Unquote request path before passing to FTPClient, it already escape paths (commit cc00ad2)
- include tests/ to source distribution in MANIFEST.in (commit eca227e)
- DOC Fix SelectJmes documentation (commit b8567bc)
- DOC Bring Ubuntu and Archlinux outside of Windows subsection (commit 392233f)
- DOC remove version suffix from ubuntu package (commit 5303c66)
- DOC Update release date for 1.0 (commit c89fa29)
Scrapy 1.0.0 (2015-06-19)¶
You will find a lot of new features and bugfixes in this major release. Make sure to check our updated overview to get a glance of some of the changes, along with our brushed tutorial.
Support for returning dictionaries in spiders¶
Declaring and returning Scrapy Items is no longer necessary to collect the scraped data from your spider, you can now return explicit dictionaries instead.
Classic version
class MyItem(scrapy.Item):
url = scrapy.Field()
class MySpider(scrapy.Spider):
def parse(self, response):
return MyItem(url=response.url)
New version
class MySpider(scrapy.Spider):
def parse(self, response):
return {'url': response.url}
Per-spider settings (GSoC 2014)¶
Last Google Summer of Code project accomplished an important redesign of the mechanism used for populating settings, introducing explicit priorities to override any given setting. As an extension of that goal, we included a new level of priority for settings that act exclusively for a single spider, allowing them to redefine project settings.
Start using it by defining a custom_settings
class variable in your spider:
class MySpider(scrapy.Spider):
custom_settings = {
"DOWNLOAD_DELAY": 5.0,
"RETRY_ENABLED": False,
}
Read more about settings population: 設定
Python Logging¶
Scrapy 1.0 has moved away from Twisted logging to support Python built in’s as default logging system. We’re maintaining backward compatibility for most of the old custom interface to call logging functions, but you’ll get warnings to switch to the Python logging API entirely.
Old version
from scrapy import log
log.msg('MESSAGE', log.INFO)
New version
import logging
logging.info('MESSAGE')
Logging with spiders remains the same, but on top of the
log()
method you’ll have access to a custom
logger
created for the spider to issue log
events:
class MySpider(scrapy.Spider):
def parse(self, response):
self.logger.info('Response received')
Read more in the logging documentation: ロギング
Crawler API refactoring (GSoC 2014)¶
Another milestone for last Google Summer of Code was a refactoring of the internal API, seeking a simpler and easier usage. Check new core interface in: コア API
A common situation where you will face these changes is while running Scrapy from scripts. Here’s a quick example of how to run a Spider manually with the new API:
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()
Bear in mind this feature is still under development and its API may change until it reaches a stable status.
See more examples for scripts running Scrapy: 一般的なプラクティス
Module Relocations¶
There’s been a large rearrangement of modules trying to improve the general structure of Scrapy. Main changes were separating various subpackages into new projects and dissolving both scrapy.contrib and scrapy.contrib_exp into top level packages. Backward compatibility was kept among internal relocations, while importing deprecated modules expect warnings indicating their new place.
Full list of relocations¶
Outsourced packages
注釈
These extensions went through some minor changes, e.g. some setting names were changed. Please check the documentation in each new repository to get familiar with the new usage.
Old location | New location |
---|---|
scrapy.commands.deploy | scrapyd-client (See other alternatives here: スパイダーのデプロイ) |
scrapy.contrib.djangoitem | scrapy-djangoitem |
scrapy.webservice | scrapy-jsonrpc |
scrapy.contrib_exp and scrapy.contrib dissolutions
Old location | New location |
---|---|
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.extensions.* |
Plural renames and Modules unification
Old location | New location |
---|---|
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 |
Class renames
Old location | New location |
---|---|
scrapy.spidermanager.SpiderManager | scrapy.spiderloader.SpiderLoader |
Settings renames
Old location | New location |
---|---|
SPIDER_MANAGER_CLASS | SPIDER_LOADER_CLASS |
Changelog¶
New Features and Enhancements
- Python logging (issue 1060, issue 1235, issue 1236, issue 1240, issue 1259, issue 1278, issue 1286)
- FEED_EXPORT_FIELDS option (issue 1159, issue 1224)
- Dns cache size and timeout options (issue 1132)
- support namespace prefix in xmliter_lxml (issue 963)
- Reactor threadpool max size setting (issue 1123)
- Allow spiders to return dicts. (issue 1081)
- Add Response.urljoin() helper (issue 1086)
- look in ~/.config/scrapy.cfg for user config (issue 1098)
- handle TLS SNI (issue 1101)
- Selectorlist extract first (issue 624, issue 1145)
- Added JmesSelect (issue 1016)
- add gzip compression to filesystem http cache backend (issue 1020)
- CSS support in link extractors (issue 983)
- httpcache dont_cache meta #19 #689 (issue 821)
- add signal to be sent when request is dropped by the scheduler (issue 961)
- avoid download large response (issue 946)
- Allow to specify the quotechar in CSVFeedSpider (issue 882)
- Add referer to “Spider error processing” log message (issue 795)
- process robots.txt once (issue 896)
- GSoC Per-spider settings (issue 854)
- Add project name validation (issue 817)
- GSoC API cleanup (issue 816, issue 1128, issue 1147, issue 1148, issue 1156, issue 1185, issue 1187, issue 1258, issue 1268, issue 1276, issue 1285, issue 1284)
- Be more responsive with IO operations (issue 1074 and issue 1075)
- Do leveldb compaction for httpcache on closing (issue 1297)
Deprecations and Removals
- Deprecate htmlparser link extractor (issue 1205)
- remove deprecated code from FeedExporter (issue 1155)
- a leftover for.15 compatibility (issue 925)
- drop support for CONCURRENT_REQUESTS_PER_SPIDER (issue 895)
- Drop old engine code (issue 911)
- Deprecate SgmlLinkExtractor (issue 777)
Relocations
- Move exporters/__init__.py to exporters.py (issue 1242)
- Move base classes to their packages (issue 1218, issue 1233)
- Module relocation (issue 1181, issue 1210)
- rename SpiderManager to SpiderLoader (issue 1166)
- Remove djangoitem (issue 1177)
- remove scrapy deploy command (issue 1102)
- dissolve contrib_exp (issue 1134)
- Deleted bin folder from root, fixes #913 (issue 914)
- Remove jsonrpc based webservice (issue 859)
- Move Test cases under project root dir (issue 827, issue 841)
- Fix backward incompatibility for relocated paths in settings (issue 1267)
Documentation
- CrawlerProcess documentation (issue 1190)
- Favoring web scraping over screen scraping in the descriptions (issue 1188)
- Some improvements for Scrapy tutorial (issue 1180)
- Documenting Files Pipeline together with Images Pipeline (issue 1150)
- deployment docs tweaks (issue 1164)
- Added deployment section covering scrapyd-deploy and shub (issue 1124)
- Adding more settings to project template (issue 1073)
- some improvements to overview page (issue 1106)
- Updated link in docs/topics/architecture.rst (issue 647)
- DOC reorder topics (issue 1022)
- updating list of Request.meta special keys (issue 1071)
- DOC document download_timeout (issue 898)
- DOC simplify extension docs (issue 893)
- Leaks docs (issue 894)
- DOC document from_crawler method for item pipelines (issue 904)
- Spider_error doesn’t support deferreds (issue 1292)
- Corrections & Sphinx related fixes (issue 1220, issue 1219, issue 1196, issue 1172, issue 1171, issue 1169, issue 1160, issue 1154, issue 1127, issue 1112, issue 1105, issue 1041, issue 1082, issue 1033, issue 944, issue 866, issue 864, issue 796, issue 1260, issue 1271, issue 1293, issue 1298)
Bugfixes
- Item multi inheritance fix (issue 353, issue 1228)
- ItemLoader.load_item: iterate over copy of fields (issue 722)
- Fix Unhandled error in Deferred (RobotsTxtMiddleware) (issue 1131, issue 1197)
- Force to read DOWNLOAD_TIMEOUT as int (issue 954)
- scrapy.utils.misc.load_object should print full traceback (issue 902)
- Fix bug for ”.local” host name (issue 878)
- Fix for Enabled extensions, middlewares, pipelines info not printed anymore (issue 879)
- fix dont_merge_cookies bad behaviour when set to false on meta (issue 846)
Python 3 In Progress Support
- disable scrapy.telnet if twisted.conch is not available (issue 1161)
- fix Python 3 syntax errors in ajaxcrawl.py (issue 1162)
- more python3 compatibility changes for urllib (issue 1121)
- assertItemsEqual was renamed to assertCountEqual in Python 3. (issue 1070)
- Import unittest.mock if available. (issue 1066)
- updated deprecated cgi.parse_qsl to use six’s parse_qsl (issue 909)
- Prevent Python 3 port regressions (issue 830)
- PY3: use MutableMapping for python 3 (issue 810)
- PY3: use six.BytesIO and six.moves.cStringIO (issue 803)
- PY3: fix xmlrpclib and email imports (issue 801)
- PY3: use six for robotparser and urlparse (issue 800)
- PY3: use six.iterkeys, six.iteritems, and tempfile (issue 799)
- PY3: fix has_key and use six.moves.configparser (issue 798)
- PY3: use six.moves.cPickle (issue 797)
- PY3 make it possible to run some tests in Python3 (issue 776)
Tests
- remove unnecessary lines from py3-ignores (issue 1243)
- Fix remaining warnings from pytest while collecting tests (issue 1206)
- Add docs build to travis (issue 1234)
- TST don’t collect tests from deprecated modules. (issue 1165)
- install service_identity package in tests to prevent warnings (issue 1168)
- Fix deprecated settings API in tests (issue 1152)
- Add test for webclient with POST method and no body given (issue 1089)
- py3-ignores.txt supports comments (issue 1044)
- modernize some of the asserts (issue 835)
- selector.__repr__ test (issue 779)
Code refactoring
- CSVFeedSpider cleanup: use iterate_spider_output (issue 1079)
- remove unnecessary check from scrapy.utils.spider.iter_spider_output (issue 1078)
- Pydispatch pep8 (issue 992)
- Removed unused ‘load=False’ parameter from walk_modules() (issue 871)
- For consistency, use job_dir helper in SpiderState extension. (issue 805)
- rename “sflo” local variables to less cryptic “log_observer” (issue 775)
Scrapy 0.24.6 (2015-04-20)¶
- encode invalid xpath with unicode_escape under PY2 (commit 07cb3e5)
- fix IPython shell scope issue and load IPython user config (commit 2c8e573)
- Fix small typo in the docs (commit d694019)
- Fix small typo (commit f92fa83)
- Converted sel.xpath() calls to response.xpath() in Extracting the data (commit c2c6d15)
Scrapy 0.24.5 (2015-02-25)¶
- Support new _getEndpoint Agent signatures on Twisted 15.0.0 (commit 540b9bc)
- DOC a couple more references are fixed (commit b4c454b)
- DOC fix a reference (commit e3c1260)
- t.i.b.ThreadedResolver is now a new-style class (commit 9e13f42)
- S3DownloadHandler: fix auth for requests with quoted paths/query params (commit cdb9a0b)
- fixed the variable types in mailsender documentation (commit bb3a848)
- Reset items_scraped instead of item_count (commit edb07a4)
- Tentative attention message about what document to read for contributions (commit 7ee6f7a)
- mitmproxy 0.10.1 needs netlib 0.10.1 too (commit 874fcdd)
- pin mitmproxy 0.10.1 as >0.11 does not work with tests (commit c6b21f0)
- Test the parse command locally instead of against an external url (commit c3a6628)
- Patches Twisted issue while closing the connection pool on HTTPDownloadHandler (commit d0bf957)
- Updates documentation on dynamic item classes. (commit eeb589a)
- Merge pull request #943 from Lazar-T/patch-3 (commit 5fdab02)
- typo (commit b0ae199)
- pywin32 is required by Twisted. closes #937 (commit 5cb0cfb)
- Update install.rst (commit 781286b)
- Merge pull request #928 from Lazar-T/patch-1 (commit b415d04)
- comma instead of fullstop (commit 627b9ba)
- Merge pull request #885 from jsma/patch-1 (commit de909ad)
- Update request-response.rst (commit 3f3263d)
- SgmlLinkExtractor - fix for parsing <area> tag with Unicode present (commit 49b40f0)
Scrapy 0.24.4 (2014-08-09)¶
- pem file is used by mockserver and required by scrapy bench (commit 5eddc68)
- scrapy bench needs scrapy.tests* (commit d6cb999)
Scrapy 0.24.3 (2014-08-09)¶
- no need to waste travis-ci time on py3 for 0.24 (commit 8e080c1)
- Update installation docs (commit 1d0c096)
- There is a trove classifier for Scrapy framework! (commit 4c701d7)
- update other places where w3lib version is mentioned (commit d109c13)
- Update w3lib requirement to 1.8.0 (commit 39d2ce5)
- Use w3lib.html.replace_entities() (remove_entities() is deprecated) (commit 180d3ad)
- set zip_safe=False (commit a51ee8b)
- do not ship tests package (commit ee3b371)
- scrapy.bat is not needed anymore (commit c3861cf)
- Modernize setup.py (commit 362e322)
- headers can not handle non-string values (commit 94a5c65)
- fix ftp test cases (commit a274a7f)
- The sum up of travis-ci builds are taking like 50min to complete (commit ae1e2cc)
- Update shell.rst typo (commit e49c96a)
- removes weird indentation in the shell results (commit 1ca489d)
- improved explanations, clarified blog post as source, added link for XPath string functions in the spec (commit 65c8f05)
- renamed UserTimeoutError and ServerTimeouterror #583 (commit 037f6ab)
- adding some xpath tips to selectors docs (commit 2d103e0)
- fix tests to account for https://github.com/scrapy/w3lib/pull/23 (commit f8d366a)
- get_func_args maximum recursion fix #728 (commit 81344ea)
- Updated input/ouput processor example according to #560. (commit f7c4ea8)
- Fixed Python syntax in tutorial. (commit db59ed9)
- Add test case for tunneling proxy (commit f090260)
- Bugfix for leaking Proxy-Authorization header to remote host when using tunneling (commit d8793af)
- Extract links from XHTML documents with MIME-Type “application/xml” (commit ed1f376)
- Merge pull request #793 from roysc/patch-1 (commit 91a1106)
- Fix typo in commands.rst (commit 743e1e2)
- better testcase for settings.overrides.setdefault (commit e22daaf)
- Using CRLF as line marker according to http 1.1 definition (commit 5ec430b)
Scrapy 0.24.2 (2014-07-08)¶
- Use a mutable mapping to proxy deprecated settings.overrides and settings.defaults attribute (commit e5e8133)
- there is not support for python3 yet (commit 3cd6146)
- Update python compatible version set to debian packages (commit fa5d76b)
- DOC fix formatting in release notes (commit c6a9e20)
Scrapy 0.24.1 (2014-06-27)¶
- Fix deprecated CrawlerSettings and increase backwards compatibility with .defaults attribute (commit 8e3f20a)
Scrapy 0.24.0 (2014-06-26)¶
Enhancements¶
- Improve Scrapy top-level namespace (issue 494, issue 684)
- Add selector shortcuts to responses (issue 554, issue 690)
- Add new lxml based LinkExtractor to replace unmantained SgmlLinkExtractor (issue 559, issue 761, issue 763)
- Cleanup settings API - part of per-spider settings GSoC project (issue 737)
- Add UTF8 encoding header to templates (issue 688, issue 762)
- Telnet console now binds to 127.0.0.1 by default (issue 699)
- Update debian/ubuntu install instructions (issue 509, issue 549)
- Disable smart strings in lxml XPath evaluations (issue 535)
- Restore filesystem based cache as default for http cache middleware (issue 541, issue 500, issue 571)
- Expose current crawler in Scrapy shell (issue 557)
- Improve testsuite comparing CSV and XML exporters (issue 570)
- New offsite/filtered and offsite/domains stats (issue 566)
- Support process_links as generator in CrawlSpider (issue 555)
- Verbose logging and new stats counters for DupeFilter (issue 553)
- Add a mimetype parameter to MailSender.send() (issue 602)
- Generalize file pipeline log messages (issue 622)
- Replace unencodeable codepoints with html entities in SGMLLinkExtractor (issue 565)
- Converted SEP documents to rst format (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)
- Tests and docs for clickdata’s nr index in FormRequest (issue 646, issue 645)
- Allow to disable a downloader handler just like any other component (issue 650)
- Log when a request is discarded after too many redirections (issue 654)
- Log error responses if they are not handled by spider callbacks (issue 612, issue 656)
- Add content-type check to http compression mw (issue 193, issue 660)
- Run pypy tests using latest pypi from ppa (issue 674)
- Run test suite using pytest instead of trial (issue 679)
- Build docs and check for dead links in tox environment (issue 687)
- Make scrapy.version_info a tuple of integers (issue 681, issue 692)
- Infer exporter’s output format from filename extensions (issue 546, issue 659, issue 760)
- Support case-insensitive domains in url_is_from_any_domain() (issue 693)
- Remove pep8 warnings in project and spider templates (issue 698)
- Tests and docs for request_fingerprint function (issue 597)
- Update SEP-19 for GSoC project per-spider settings (issue 705)
- Set exit code to non-zero when contracts fails (issue 727)
- Add a setting to control what class is instanciated as Downloader component (issue 738)
- Pass response in item_dropped signal (issue 724)
- Improve scrapy check contracts command (issue 733, issue 752)
- Document spider.closed() shortcut (issue 719)
- Document request_scheduled signal (issue 746)
- Add a note about reporting security issues (issue 697)
- Add LevelDB http cache storage backend (issue 626, issue 500)
- Sort spider list output of scrapy list command (issue 742)
- Multiple documentation enhancemens and fixes (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)
Bugfixes¶
- Encode unicode URL value when creating Links in RegexLinkExtractor (issue 561)
- Ignore None values in ItemLoader processors (issue 556)
- Fix link text when there is an inner tag in SGMLLinkExtractor and HtmlParserLinkExtractor (issue 485, issue 574)
- Fix wrong checks on subclassing of deprecated classes (issue 581, issue 584)
- Handle errors caused by inspect.stack() failures (issue 582)
- Fix a reference to unexistent engine attribute (issue 593, issue 594)
- Fix dynamic itemclass example usage of type() (issue 603)
- Use lucasdemarchi/codespell to fix typos (issue 628)
- Fix default value of attrs argument in SgmlLinkExtractor to be tuple (issue 661)
- Fix XXE flaw in sitemap reader (issue 676)
- Fix engine to support filtered start requests (issue 707)
- Fix offsite middleware case on urls with no hostnames (issue 745)
- Testsuite doesn’t require PIL anymore (issue 585)
Scrapy 0.22.2 (released 2014-02-14)¶
- fix a reference to unexistent engine.slots. closes #593 (commit 13c099a)
- downloaderMW doc typo (spiderMW doc copy remnant) (commit 8ae11bf)
- Correct typos (commit 1346037)
Scrapy 0.22.1 (released 2014-02-08)¶
- localhost666 can resolve under certain circumstances (commit 2ec2279)
- test inspect.stack failure (commit cc3eda3)
- Handle cases when inspect.stack() fails (commit 8cb44f9)
- Fix wrong checks on subclassing of deprecated classes. closes #581 (commit 46d98d6)
- Docs: 4-space indent for final spider example (commit 13846de)
- Fix HtmlParserLinkExtractor and tests after #485 merge (commit 368a946)
- BaseSgmlLinkExtractor: Fixed the missing space when the link has an inner tag (commit b566388)
- BaseSgmlLinkExtractor: Added unit test of a link with an inner tag (commit c1cb418)
- BaseSgmlLinkExtractor: Fixed unknown_endtag() so that it only set current_link=None when the end tag match the opening tag (commit 7e4d627)
- Fix tests for Travis-CI build (commit 76c7e20)
- replace unencodeable codepoints with html entities. fixes #562 and #285 (commit 5f87b17)
- RegexLinkExtractor: encode URL unicode value when creating Links (commit d0ee545)
- Updated the tutorial crawl output with latest output. (commit 8da65de)
- Updated shell docs with the crawler reference and fixed the actual shell output. (commit 875b9ab)
- PEP8 minor edits. (commit f89efaf)
- Expose current crawler in the scrapy shell. (commit 5349cec)
- Unused re import and PEP8 minor edits. (commit 387f414)
- Ignore None’s values when using the ItemLoader. (commit 0632546)
- DOC Fixed HTTPCACHE_STORAGE typo in the default value which is now Filesystem instead Dbm. (commit cde9a8c)
- show ubuntu setup instructions as literal code (commit fb5c9c5)
- Update Ubuntu installation instructions (commit 70fb105)
- Merge pull request #550 from stray-leone/patch-1 (commit 6f70b6a)
- modify the version of scrapy ubuntu package (commit 725900d)
- fix 0.22.0 release date (commit af0219a)
- fix typos in news.rst and remove (not released yet) header (commit b7f58f4)
Scrapy 0.22.0 (released 2014-01-17)¶
Enhancements¶
- [Backwards incompatible] Switched HTTPCacheMiddleware backend to filesystem (issue 541) To restore old backend set HTTPCACHE_STORAGE to scrapy.contrib.httpcache.DbmCacheStorage
- Proxy https:// urls using CONNECT method (issue 392, issue 397)
- Add a middleware to crawl ajax crawleable pages as defined by google (issue 343)
- Rename scrapy.spider.BaseSpider to scrapy.spider.Spider (issue 510, issue 519)
- Selectors register EXSLT namespaces by default (issue 472)
- Unify item loaders similar to selectors renaming (issue 461)
- Make RFPDupeFilter class easily subclassable (issue 533)
- Improve test coverage and forthcoming Python 3 support (issue 525)
- Promote startup info on settings and middleware to INFO level (issue 520)
- Support partials in get_func_args util (issue 506, issue:504)
- Allow running indiviual tests via tox (issue 503)
- Update extensions ignored by link extractors (issue 498)
- Add middleware methods to get files/images/thumbs paths (issue 490)
- Improve offsite middleware tests (issue 478)
- Add a way to skip default Referer header set by RefererMiddleware (issue 475)
- Do not send x-gzip in default Accept-Encoding header (issue 469)
- Support defining http error handling using settings (issue 466)
- Use modern python idioms wherever you find legacies (issue 497)
- Improve and correct documentation (issue 527, issue 524, issue 521, issue 517, issue 512, issue 505, issue 502, issue 489, issue 465, issue 460, issue 425, issue 536)
Fixes¶
- Update Selector class imports in CrawlSpider template (issue 484)
- Fix unexistent reference to engine.slots (issue 464)
- Do not try to call body_as_unicode() on a non-TextResponse instance (issue 462)
- Warn when subclassing XPathItemLoader, previously it only warned on instantiation. (issue 523)
- Warn when subclassing XPathSelector, previously it only warned on instantiation. (issue 537)
- Multiple fixes to memory stats (issue 531, issue 530, issue 529)
- Fix overriding url in FormRequest.from_response() (issue 507)
- Fix tests runner under pip 1.5 (issue 513)
- Fix logging error when spider name is unicode (issue 479)
Scrapy 0.20.2 (released 2013-12-09)¶
- Update CrawlSpider Template with Selector changes (commit 6d1457d)
- fix method name in tutorial. closes GH-480 (commit b4fc359
Scrapy 0.20.1 (released 2013-11-28)¶
- include_package_data is required to build wheels from published sources (commit 5ba1ad5)
- process_parallel was leaking the failures on its internal deferreds. closes #458 (commit 419a780)
Scrapy 0.20.0 (released 2013-11-08)¶
Enhancements¶
- New Selector’s API including CSS selectors (issue 395 and issue 426),
- Request/Response url/body attributes are now immutable (modifying them had been deprecated for a long time)
ITEM_PIPELINES
is now defined as a dict (instead of a list)- Sitemap spider can fetch alternate URLs (issue 360)
- Selector.remove_namespaces() now remove namespaces from element’s attributes. (issue 416)
- Paved the road for Python 3.3+ (issue 435, issue 436, issue 431, issue 452)
- New item exporter using native python types with nesting support (issue 366)
- Tune HTTP1.1 pool size so it matches concurrency defined by settings (commit b43b5f575)
- scrapy.mail.MailSender now can connect over TLS or upgrade using STARTTLS (issue 327)
- New FilesPipeline with functionality factored out from ImagesPipeline (issue 370, issue 409)
- Recommend Pillow instead of PIL for image handling (issue 317)
- Added debian packages for Ubuntu quantal and raring (commit 86230c0)
- Mock server (used for tests) can listen for HTTPS requests (issue 410)
- Remove multi spider support from multiple core components (issue 422, issue 421, issue 420, issue 419, issue 423, issue 418)
- Travis-CI now tests Scrapy changes against development versions of w3lib and queuelib python packages.
- Add pypy 2.1 to continuous integration tests (commit ecfa7431)
- Pylinted, pep8 and removed old-style exceptions from source (issue 430, issue 432)
- Use importlib for parametric imports (issue 445)
- Handle a regression introduced in Python 2.7.5 that affects XmlItemExporter (issue 372)
- Bugfix crawling shutdown on SIGINT (issue 450)
- Do not submit reset type inputs in FormRequest.from_response (commit b326b87)
- Do not silence download errors when request errback raises an exception (commit 684cfc0)
Bugfixes¶
- Fix tests under Django 1.6 (commit b6bed44c)
- Lot of bugfixes to retry middleware under disconnections using HTTP 1.1 download handler
- Fix inconsistencies among Twisted releases (issue 406)
- Fix scrapy shell bugs (issue 418, issue 407)
- Fix invalid variable name in setup.py (issue 429)
- Fix tutorial references (issue 387)
- Improve request-response docs (issue 391)
- Improve best practices docs (issue 399, issue 400, issue 401, issue 402)
- Improve django integration docs (issue 404)
- Document bindaddress request meta (commit 37c24e01d7)
- Improve Request class documentation (issue 226)
Other¶
- Dropped Python 2.6 support (issue 448)
- Add cssselect python package as install dependency
- Drop libxml2 and multi selector’s backend support, lxml is required from now on.
- Minimum Twisted version increased to 10.0.0, dropped Twisted 8.0 support.
- Running test suite now requires mock python library (issue 390)
Thanks¶
Thanks to everyone who contribute to this release!
List of contributors sorted by number of commits:
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 refuses to update the namespace. fix #396 (commit 3d32c4f)
- Fix AlreadyCalledError replacing a request in shell command. closes #407 (commit b1d8919)
- Fix start_requests laziness and early hangs (commit 89faf52)
Scrapy 0.18.3 (released 2013-10-03)¶
- fix regression on lazy evaluation of start requests (commit 12693a5)
- forms: do not submit reset inputs (commit e429f63)
- increase unittest timeouts to decrease travis false positive failures (commit 912202e)
- backport master fixes to json exporter (commit cfc2d46)
- Fix permission and set umask before generating sdist tarball (commit 06149e0)
Scrapy 0.18.2 (released 2013-09-03)¶
- Backport scrapy check command fixes and backward compatible multi crawler process(issue 339)
Scrapy 0.18.1 (released 2013-08-27)¶
- remove extra import added by cherry picked changes (commit d20304e)
- fix crawling tests under twisted pre 11.0.0 (commit 1994f38)
- py26 can not format zero length fields {} (commit abf756f)
- test PotentiaDataLoss errors on unbound responses (commit b15470d)
- Treat responses without content-length or Transfer-Encoding as good responses (commit c4bf324)
- do no include ResponseFailed if http11 handler is not enabled (commit 6cbe684)
- New HTTP client wraps connection losts in ResponseFailed exception. fix #373 (commit 1a20bba)
- limit travis-ci build matrix (commit 3b01bb8)
- Merge pull request #375 from peterarenot/patch-1 (commit fa766d7)
- Fixed so it refers to the correct folder (commit 3283809)
- added quantal & raring to support ubuntu releases (commit 1411923)
- fix retry middleware which didn’t retry certain connection errors after the upgrade to http1 client, closes GH-373 (commit bb35ed0)
- fix XmlItemExporter in Python 2.7.4 and 2.7.5 (commit de3e451)
- minor updates to 0.18 release notes (commit c45e5f1)
- fix contributters list format (commit 0b60031)
Scrapy 0.18.0 (released 2013-08-09)¶
- Lot of improvements to testsuite run using Tox, including a way to test on pypi
- Handle GET parameters for AJAX crawleable urls (commit 3fe2a32)
- Use lxml recover option to parse sitemaps (issue 347)
- Bugfix cookie merging by hostname and not by netloc (issue 352)
- Support disabling HttpCompressionMiddleware using a flag setting (issue 359)
- Support xml namespaces using iternodes parser in XMLFeedSpider (issue 12)
- Support dont_cache request meta flag (issue 19)
- Bugfix scrapy.utils.gz.gunzip broken by changes in python 2.7.4 (commit 4dc76e)
- Bugfix url encoding on SgmlLinkExtractor (issue 24)
- Bugfix TakeFirst processor shouldn’t discard zero (0) value (issue 59)
- Support nested items in xml exporter (issue 66)
- Improve cookies handling performance (issue 77)
- Log dupe filtered requests once (issue 105)
- Split redirection middleware into status and meta based middlewares (issue 78)
- Use HTTP1.1 as default downloader handler (issue 109 and issue 318)
- Support xpath form selection on FormRequest.from_response (issue 185)
- Bugfix unicode decoding error on SgmlLinkExtractor (issue 199)
- Bugfix signal dispatching on pypi interpreter (issue 205)
- Improve request delay and concurrency handling (issue 206)
- Add RFC2616 cache policy to HttpCacheMiddleware (issue 212)
- Allow customization of messages logged by engine (issue 214)
- Multiples improvements to DjangoItem (issue 217, issue 218, issue 221)
- Extend Scrapy commands using setuptools entry points (issue 260)
- Allow spider allowed_domains value to be set/tuple (issue 261)
- Support settings.getdict (issue 269)
- Simplify internal scrapy.core.scraper slot handling (issue 271)
- Added Item.copy (issue 290)
- Collect idle downloader slots (issue 297)
- Add ftp:// scheme downloader handler (issue 329)
- Added downloader benchmark webserver and spider tools ベンチマーク
- Moved persistent (on disk) queues to a separate project (queuelib) which scrapy now depends on
- Add scrapy commands using external libraries (issue 260)
- Added
--pdb
option toscrapy
command line tool - Added
XPathSelector.remove_namespaces()
which allows to remove all namespaces from XML documents for convenience (to work with namespace-less XPaths). Documented in セレクタ. - Several improvements to spider contracts
- New default middleware named MetaRefreshMiddldeware that handles meta-refresh html tag redirections,
- MetaRefreshMiddldeware and RedirectMiddleware have different priorities to address #62
- added from_crawler method to spiders
- added system tests with mock server
- more improvements to Mac OS compatibility (thanks Alex Cepoi)
- several more cleanups to singletons and multi-spider support (thanks Nicolas Ramirez)
- support custom download slots
- added –spider option to “shell” command.
- log overridden settings when scrapy starts
Thanks to everyone who contribute to this release. Here is a list of contributors sorted by number of commits:
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)¶
- obey request method when scrapy deploy is redirected to a new endpoint (commit 8c4fcee)
- fix inaccurate downloader middleware documentation. refs #280 (commit 40667cb)
- doc: remove links to diveintopython.org, which is no longer available. closes #246 (commit bd58bfa)
- Find form nodes in invalid html5 documents (commit e3d6945)
- Fix typo labeling attrs type bool instead of list (commit a274276)
Scrapy 0.16.4 (released 2013-01-23)¶
- fixes spelling errors in documentation (commit 6d2b3aa)
- add doc about disabling an extension. refs #132 (commit c90de33)
- Fixed error message formatting. log.err() doesn’t support cool formatting and when error occurred, the message was: “ERROR: Error processing %(item)s” (commit c16150c)
- lint and improve images pipeline error logging (commit 56b45fc)
- fixed doc typos (commit 243be84)
- add documentation topics: Broad Crawls & Common Practies (commit 1fbb715)
- fix bug in scrapy parse command when spider is not specified explicitly. closes #209 (commit c72e682)
- Update docs/topics/commands.rst (commit 28eac7a)
Scrapy 0.16.3 (released 2012-12-07)¶
- Remove concurrency limitation when using download delays and still ensure inter-request delays are enforced (commit 487b9b5)
- add error details when image pipeline fails (commit 8232569)
- improve mac os compatibility (commit 8dcf8aa)
- setup.py: use README.rst to populate long_description (commit 7b5310d)
- doc: removed obsolete references to ClientForm (commit 80f9bb6)
- correct docs for default storage backend (commit 2aa491b)
- doc: removed broken proxyhub link from FAQ (commit bdf61c4)
- Fixed docs typo in SpiderOpenCloseLogging example (commit 7184094)
Scrapy 0.16.2 (released 2012-11-09)¶
- scrapy contracts: python2.6 compat (commit a4a9199)
- scrapy contracts verbose option (commit ec41673)
- proper unittest-like output for scrapy contracts (commit 86635e4)
- added open_in_browser to debugging doc (commit c9b690d)
- removed reference to global scrapy stats from settings doc (commit dd55067)
- Fix SpiderState bug in Windows platforms (commit 58998f4)
Scrapy 0.16.1 (released 2012-10-26)¶
- fixed LogStats extension, which got broken after a wrong merge before the 0.16 release (commit 8c780fd)
- better backwards compatibility for scrapy.conf.settings (commit 3403089)
- extended documentation on how to access crawler stats from extensions (commit c4da0b5)
- removed .hgtags (no longer needed now that scrapy uses git) (commit d52c188)
- fix dashes under rst headers (commit fa4f7f9)
- set release date for 0.16.0 in news (commit e292246)
Scrapy 0.16.0 (released 2012-10-18)¶
Scrapy changes:
- added スパイダーコントラクト, a mechanism for testing spiders in a formal/reproducible way
- added options
-o
and-t
to therunspider
command - documented AutoThrottle 拡張機能 and added to extensions installed by default. You still need to enable it with
AUTOTHROTTLE_ENABLED
- major Stats Collection refactoring: removed separation of global/per-spider stats, removed stats-related signals (
stats_spider_opened
, etc). Stats are much simpler now, backwards compatibility is kept on the Stats Collector API and signals. - added
process_start_requests()
method to spider middlewares - dropped Signals singleton. Signals should now be accesed through the Crawler.signals attribute. See the signals documentation for more info.
- dropped Signals singleton. Signals should now be accesed through the Crawler.signals attribute. See the signals documentation for more info.
- dropped Stats Collector singleton. Stats can now be accessed through the Crawler.stats attribute. See the stats collection documentation for more info.
- documented コア API
- lxml is now the default selectors backend instead of libxml2
- ported FormRequest.from_response() to use lxml instead of ClientForm
- removed modules:
scrapy.xlib.BeautifulSoup
andscrapy.xlib.ClientForm
- SitemapSpider: added support for sitemap urls ending in .xml and .xml.gz, even if they advertise a wrong content type (commit 10ed28b)
- StackTraceDump extension: also dump trackref live references (commit fe2ce93)
- nested items now fully supported in JSON and JSONLines exporters
- added
cookiejar
Request meta key to support multiple cookie sessions per spider - decoupled encoding detection code to w3lib.encoding, and ported Scrapy code to use that module
- dropped support for Python 2.5. See https://blog.scrapinghub.com/2012/02/27/scrapy-0-15-dropping-support-for-python-2-5/
- dropped support for Twisted 2.5
- added
REFERER_ENABLED
setting, to control referer middleware - changed default user agent to:
Scrapy/VERSION (+http://scrapy.org)
- removed (undocumented)
HTMLImageLinkExtractor
class fromscrapy.contrib.linkextractors.image
- removed per-spider settings (to be replaced by instantiating multiple crawler objects)
USER_AGENT
spider attribute will no longer work, useuser_agent
attribute insteadDOWNLOAD_TIMEOUT
spider attribute will no longer work, usedownload_timeout
attribute instead- removed
ENCODING_ALIASES
setting, as encoding auto-detection has been moved to the w3lib library - promoted DjangoItem to main contrib
- LogFormatter method now return dicts(instead of strings) to support lazy formatting (issue 164, commit dcef7b0)
- downloader handlers (
DOWNLOAD_HANDLERS
setting) now receive settings as the first argument of the constructor - replaced memory usage acounting with (more portable) resource module, removed
scrapy.utils.memory
module - removed signal:
scrapy.mail.mail_sent
- removed
TRACK_REFS
setting, now trackrefs is always enabled - DBM is now the default storage backend for HTTP cache middleware
- number of log messages (per level) are now tracked through Scrapy stats (stat name:
log_count/LEVEL
) - number received responses are now tracked through Scrapy stats (stat name:
response_received_count
) - removed
scrapy.log.started
attribute
Scrapy 0.14.4¶
- added precise to supported ubuntu distros (commit b7e46df)
- fixed bug in json-rpc webservice reported in https://groups.google.com/forum/#!topic/scrapy-users/qgVBmFybNAQ/discussion. also removed no longer supported ‘run’ command from extras/scrapy-ws.py (commit 340fbdb)
- meta tag attributes for content-type http equiv can be in any order. #123 (commit 0cb68af)
- replace “import Image” by more standard “from PIL import Image”. closes #88 (commit 4d17048)
- return trial status as bin/runtests.sh exit value. #118 (commit b7b2e7f)
Scrapy 0.14.3¶
- forgot to include pydispatch license. #118 (commit fd85f9c)
- include egg files used by testsuite in source distribution. #118 (commit c897793)
- update docstring in project template to avoid confusion with genspider command, which may be considered as an advanced feature. refs #107 (commit 2548dcc)
- added note to docs/topics/firebug.rst about google directory being shut down (commit 668e352)
- dont discard slot when empty, just save in another dict in order to recycle if needed again. (commit 8e9f607)
- do not fail handling unicode xpaths in libxml2 backed selectors (commit b830e95)
- fixed minor mistake in Request objects documentation (commit bf3c9ee)
- fixed minor defect in link extractors documentation (commit ba14f38)
- removed some obsolete remaining code related to sqlite support in scrapy (commit 0665175)
Scrapy 0.14.2¶
- move buffer pointing to start of file before computing checksum. refs #92 (commit 6a5bef2)
- Compute image checksum before persisting images. closes #92 (commit 9817df1)
- remove leaking references in cached failures (commit 673a120)
- fixed bug in MemoryUsage extension: get_engine_status() takes exactly 1 argument (0 given) (commit 11133e9)
- fixed struct.error on http compression middleware. closes #87 (commit 1423140)
- ajax crawling wasn’t expanding for unicode urls (commit 0de3fb4)
- Catch start_requests iterator errors. refs #83 (commit 454a21d)
- Speed-up libxml2 XPathSelector (commit 2fbd662)
- updated versioning doc according to recent changes (commit 0a070f5)
- scrapyd: fixed documentation link (commit 2b4e4c3)
- extras/makedeb.py: no longer obtaining version from git (commit caffe0e)
Scrapy 0.14.1¶
- extras/makedeb.py: no longer obtaining version from git (commit caffe0e)
- bumped version to 0.14.1 (commit 6cb9e1c)
- fixed reference to tutorial directory (commit 4b86bd6)
- doc: removed duplicated callback argument from Request.replace() (commit 1aeccdd)
- fixed formatting of scrapyd doc (commit 8bf19e6)
- Dump stacks for all running threads and fix engine status dumped by StackTraceDump extension (commit 14a8e6e)
- added comment about why we disable ssl on boto images upload (commit 5223575)
- SSL handshaking hangs when doing too many parallel connections to S3 (commit 63d583d)
- change tutorial to follow changes on dmoz site (commit bcb3198)
- Avoid _disconnectedDeferred AttributeError exception in Twisted>=11.1.0 (commit 98f3f87)
- allow spider to set autothrottle max concurrency (commit 175a4b5)
Scrapy 0.14¶
New features and settings¶
- Support for AJAX crawleable urls
- New persistent scheduler that stores requests on disk, allowing to suspend and resume crawls (r2737)
- added
-o
option toscrapy crawl
, a shortcut for dumping scraped items into a file (or standard output using-
) - Added support for passing custom settings to Scrapyd
schedule.json
api (r2779, r2783) - New
ChunkedTransferMiddleware
(enabled by default) to support chunked transfer encoding (r2769) - Add boto 2.0 support for S3 downloader handler (r2763)
- Added marshal to formats supported by feed exports (r2744)
- In request errbacks, offending requests are now received in failure.request attribute (r2738)
- Big downloader refactoring to support per domain/ip concurrency limits (r2732)
CONCURRENT_REQUESTS_PER_SPIDER
setting has been deprecated and replaced by:
- check the documentation for more details
- Added builtin caching DNS resolver (r2728)
- Moved Amazon AWS-related components/extensions (SQS spider queue, SimpleDB stats collector) to a separate project: [scaws](https://github.com/scrapinghub/scaws) (r2706, r2714)
- Moved spider queues to scrapyd: scrapy.spiderqueue -> scrapyd.spiderqueue (r2708)
- Moved sqlite utils to scrapyd: scrapy.utils.sqlite -> scrapyd.sqlite (r2781)
- Real support for returning iterators on start_requests() method. The iterator is now consumed during the crawl when the spider is getting idle (r2704)
- Added
REDIRECT_ENABLED
setting to quickly enable/disable the redirect middleware (r2697) - Added
RETRY_ENABLED
setting to quickly enable/disable the retry middleware (r2694) - Added
CloseSpider
exception to manually close spiders (r2691) - Improved encoding detection by adding support for HTML5 meta charset declaration (r2690)
- Refactored close spider behavior to wait for all downloads to finish and be processed by spiders, before closing the spider (r2688)
- Added
SitemapSpider
(see documentation in Spiders page) (r2658) - Added
LogStats
extension for periodically logging basic stats (like crawled pages and scraped items) (r2657) - Make handling of gzipped responses more robust (#319, r2643). Now Scrapy will try and decompress as much as possible from a gzipped response, instead of failing with an IOError.
- Simplified !MemoryDebugger extension to use stats for dumping memory debugging info (r2639)
- Added new command to edit spiders:
scrapy edit
(r2636) and -e flag to genspider command that uses it (r2653) - Changed default representation of items to pretty-printed dicts. (r2631). This improves default logging by making log more readable in the default case, for both Scraped and Dropped lines.
- Added
spider_error
signal (r2628) - Added
COOKIES_ENABLED
setting (r2625) - Stats are now dumped to Scrapy log (default value of
STATS_DUMP
setting has been changed to True). This is to make Scrapy users more aware of Scrapy stats and the data that is collected there. - Added support for dynamically adjusting download delay and maximum concurrent requests (r2599)
- Added new DBM HTTP cache storage backend (r2576)
- Added
listjobs.json
API to Scrapyd (r2571) CsvItemExporter
: addedjoin_multivalued
parameter (r2578)- Added namespace support to
xmliter_lxml
(r2552) - Improved cookies middleware by making COOKIES_DEBUG nicer and documenting it (r2579)
- Several improvements to Scrapyd and Link extractors
Code rearranged and removed¶
- Merged item passed and item scraped concepts, as they have often proved confusing in the past. This means: (r2630)
- original item_scraped signal was removed
- original item_passed signal was renamed to item_scraped
- old log lines
Scraped Item...
were removed - old log lines
Passed Item...
were renamed toScraped Item...
lines and downgraded toDEBUG
level
- Removed unused function: scrapy.utils.request.request_info() (r2577)
- Removed googledir project from examples/googledir. There’s now a new example project called dirbot available on github: https://github.com/scrapy/dirbot
- Removed support for default field values in Scrapy items (r2616)
- Removed experimental crawlspider v2 (r2632)
- Removed scheduler middleware to simplify architecture. Duplicates filter is now done in the scheduler itself, using the same dupe fltering class as before (DUPEFILTER_CLASS setting) (r2640)
- Removed support for passing urls to
scrapy crawl
command (usescrapy parse
instead) (r2704) - Removed deprecated Execution Queue (r2704)
- Removed (undocumented) spider context extension (from scrapy.contrib.spidercontext) (r2780)
- removed
CONCURRENT_SPIDERS
setting (use scrapyd maxproc instead) (r2789) - Renamed attributes of core components: downloader.sites -> downloader.slots, scraper.sites -> scraper.slots (r2717, r2718)
- Renamed setting
CLOSESPIDER_ITEMPASSED
toCLOSESPIDER_ITEMCOUNT
(r2655). Backwards compatibility kept.
Scrapy 0.12¶
The numbers like #NNN reference tickets in the old issue tracker (Trac) which is no longer available.
New features and improvements¶
- Passed item is now sent in the
item
argument of theitem_passed
(#273) - Added verbose option to
scrapy version
command, useful for bug reports (#298) - HTTP cache now stored by default in the project data dir (#279)
- Added project data storage directory (#276, #277)
- Documented file structure of Scrapy projects (see command-line tool doc)
- New lxml backend for XPath selectors (#147)
- Per-spider settings (#245)
- Support exit codes to signal errors in Scrapy commands (#248)
- Added
-c
argument toscrapy shell
command - Made
libxml2
optional (#260) - New
deploy
command (#261) - Added
CLOSESPIDER_PAGECOUNT
setting (#253) - Added
CLOSESPIDER_ERRORCOUNT
setting (#254)
Scrapyd changes¶
- Scrapyd now uses one process per spider
- It stores one log file per spider run, and rotate them keeping the lastest 5 logs per spider (by default)
- A minimal web ui was added, available at http://localhost:6800 by default
- There is now a scrapy server command to start a Scrapyd server of the current project
Changes to settings¶
- added HTTPCACHE_ENABLED setting (False by default) to enable HTTP cache middleware
- changed HTTPCACHE_EXPIRATION_SECS semantics: now zero means “never expire”.
Deprecated/obsoleted functionality¶
- Deprecated
runserver
command in favor ofserver
command which starts a Scrapyd server. See also: Scrapyd changes - Deprecated
queue
command in favor of using Scrapydschedule.json
API. See also: Scrapyd changes - Removed the !LxmlItemLoader (experimental contrib which never graduated to main contrib)
Scrapy 0.10¶
The numbers like #NNN reference tickets in the old issue tracker (Trac) which is no longer available.
New features and improvements¶
- New Scrapy service called
scrapyd
for deploying Scrapy crawlers in production (#218) (documentation available) - Simplified Images pipeline usage which doesn’t require subclassing your own images pipeline now (#217)
- Scrapy shell now shows the Scrapy log by default (#206)
- Refactored execution queue in a common base code and pluggable backends called “spider queues” (#220)
- New persistent spider queue (based on SQLite) (#198), available by default, which allows to start Scrapy in server mode and then schedule spiders to run.
- Added documentation for Scrapy command-line tool and all its available sub-commands. (documentation available)
- Feed exporters with pluggable backends (#197) (documentation available)
- Deferred signals (#193)
- Added two new methods to item pipeline open_spider(), close_spider() with deferred support (#195)
- Support for overriding default request headers per spider (#181)
- Replaced default Spider Manager with one with similar functionality but not depending on Twisted Plugins (#186)
- Splitted Debian package into two packages - the library and the service (#187)
- Scrapy log refactoring (#188)
- New extension for keeping persistent spider contexts among different runs (#203)
- Added dont_redirect request.meta key for avoiding redirects (#233)
- Added dont_retry request.meta key for avoiding retries (#234)
Command-line tool changes¶
- New scrapy command which replaces the old scrapy-ctl.py (#199) - there is only one global scrapy command now, instead of one scrapy-ctl.py per project - Added scrapy.bat script for running more conveniently from Windows
- Added bash completion to command-line tool (#210)
- Renamed command start to runserver (#209)
API changes¶
url
andbody
attributes of Request objects are now read-only (#230)Request.copy()
andRequest.replace()
now also copies theircallback
anderrback
attributes (#231)- Removed
UrlFilterMiddleware
fromscrapy.contrib
(already disabled by default) - Offsite middelware doesn’t filter out any request coming from a spider that doesn’t have a allowed_domains attribute (#225)
- Removed Spider Manager
load()
method. Now spiders are loaded in the constructor itself. - Changes to Scrapy Manager (now called “Crawler”):
scrapy.core.manager.ScrapyManager
class renamed toscrapy.crawler.Crawler
scrapy.core.manager.scrapymanager
singleton moved toscrapy.project.crawler
- Moved module:
scrapy.contrib.spidermanager
toscrapy.spidermanager
- Spider Manager singleton moved from
scrapy.spider.spiders
to thespiders` attribute of ``scrapy.project.crawler
singleton. - moved Stats Collector classes: (#204)
scrapy.stats.collector.StatsCollector
toscrapy.statscol.StatsCollector
scrapy.stats.collector.SimpledbStatsCollector
toscrapy.contrib.statscol.SimpledbStatsCollector
- default per-command settings are now specified in the
default_settings
attribute of command object class (#201) - changed arguments of Item pipeline
process_item()
method from(spider, item)
to(item, spider)
- backwards compatibility kept (with deprecation warning)
- changed arguments of Item pipeline
- moved
scrapy.core.signals
module toscrapy.signals
- backwards compatibility kept (with deprecation warning)
- moved
- moved
scrapy.core.exceptions
module toscrapy.exceptions
- backwards compatibility kept (with deprecation warning)
- moved
- added
handles_request()
class method toBaseSpider
- dropped
scrapy.log.exc()
function (usescrapy.log.err()
instead) - dropped
component
argument ofscrapy.log.msg()
function - dropped
scrapy.log.log_level
attribute - Added
from_settings()
class methods to Spider Manager, and Item Pipeline Manager
Changes to settings¶
- Added
HTTPCACHE_IGNORE_SCHEMES
setting to ignore certain schemes on !HttpCacheMiddleware (#225) - Added
SPIDER_QUEUE_CLASS
setting which defines the spider queue to use (#220) - Added
KEEP_ALIVE
setting (#220) - Removed
SERVICE_QUEUE
setting (#220) - Removed
COMMANDS_SETTINGS_MODULE
setting (#201) - Renamed
REQUEST_HANDLERS
toDOWNLOAD_HANDLERS
and make download handlers classes (instead of functions)
Scrapy 0.9¶
The numbers like #NNN reference tickets in the old issue tracker (Trac) which is no longer available.
New features and improvements¶
- Added SMTP-AUTH support to scrapy.mail
- New settings added:
MAIL_USER
,MAIL_PASS
(r2065 | #149) - Added new scrapy-ctl view command - To view URL in the browser, as seen by Scrapy (r2039)
- Added web service for controlling Scrapy process (this also deprecates the web console. (r2053 | #167)
- Support for running Scrapy as a service, for production systems (r1988, r2054, r2055, r2056, r2057 | #168)
- Added wrapper induction library (documentation only available in source code for now). (r2011)
- Simplified and improved response encoding support (r1961, r1969)
- Added
LOG_ENCODING
setting (r1956, documentation available) - Added
RANDOMIZE_DOWNLOAD_DELAY
setting (enabled by default) (r1923, doc available) MailSender
is no longer IO-blocking (r1955 | #146)- Linkextractors and new Crawlspider now handle relative base tag urls (r1960 | #148)
- Several improvements to Item Loaders and processors (r2022, r2023, r2024, r2025, r2026, r2027, r2028, r2029, r2030)
- Added support for adding variables to telnet console (r2047 | #165)
- Support for requests without callbacks (r2050 | #166)
API changes¶
- Change
Spider.domain_name
toSpider.name
(SEP-012, r1975) Response.encoding
is now the detected encoding (r1961)HttpErrorMiddleware
now returns None or raises an exception (r2006 | #157)scrapy.command
modules relocation (r2035, r2036, r2037)- Added
ExecutionQueue
for feeding spiders to scrape (r2034) - Removed
ExecutionEngine
singleton (r2039) - Ported
S3ImagesStore
(images pipeline) to use boto and threads (r2033) - Moved module:
scrapy.management.telnet
toscrapy.telnet
(r2047)
Scrapy 0.8¶
The numbers like #NNN reference tickets in the old issue tracker (Trac) which is no longer available.
New features¶
- Added DEFAULT_RESPONSE_ENCODING setting (r1809)
- Added
dont_click
argument toFormRequest.from_response()
method (r1813, r1816) - Added
clickdata
argument toFormRequest.from_response()
method (r1802, r1803) - Added support for HTTP proxies (
HttpProxyMiddleware
) (r1781, r1785) - Offsite spider middleware now logs messages when filtering out requests (r1841)
Backwards-incompatible changes¶
- Changed
scrapy.utils.response.get_meta_refresh()
signature (r1804) - Removed deprecated
scrapy.item.ScrapedItem
class - usescrapy.item.Item instead
(r1838) - Removed deprecated
scrapy.xpath
module - usescrapy.selector
instead. (r1836) - Removed deprecated
core.signals.domain_open
signal - usecore.signals.domain_opened
instead (r1822) log.msg()
now receives aspider
argument (r1822)- Old domain argument has been deprecated and will be removed in 0.9. For spiders, you should always use the
spider
argument and pass spider references. If you really want to pass a string, use thecomponent
argument instead.
- Old domain argument has been deprecated and will be removed in 0.9. For spiders, you should always use the
- Changed core signals
domain_opened
,domain_closed
,domain_idle
- Changed Item pipeline to use spiders instead of domains
- The
domain
argument ofprocess_item()
item pipeline method was changed tospider
, the new signature is:process_item(spider, item)
(r1827 | #105) - To quickly port your code (to work with Scrapy 0.8) just use
spider.domain_name
where you previously useddomain
.
- The
- Changed Stats API to use spiders instead of domains (r1849 | #113)
StatsCollector
was changed to receive spider references (instead of domains) in its methods (set_value
,inc_value
, etc).- added
StatsCollector.iter_spider_stats()
method - removed
StatsCollector.list_domains()
method - Also, Stats signals were renamed and now pass around spider references (instead of domains). Here’s a summary of the changes:
- To quickly port your code (to work with Scrapy 0.8) just use
spider.domain_name
where you previously useddomain
.spider_stats
contains exactly the same data asdomain_stats
.
CloseDomain
extension moved toscrapy.contrib.closespider.CloseSpider
(r1833)- Its settings were also renamed:
CLOSEDOMAIN_TIMEOUT
toCLOSESPIDER_TIMEOUT
CLOSEDOMAIN_ITEMCOUNT
toCLOSESPIDER_ITEMCOUNT
- Removed deprecated
SCRAPYSETTINGS_MODULE
environment variable - useSCRAPY_SETTINGS_MODULE
instead (r1840) - Renamed setting:
REQUESTS_PER_DOMAIN
toCONCURRENT_REQUESTS_PER_SPIDER
(r1830, r1844) - Renamed setting:
CONCURRENT_DOMAINS
toCONCURRENT_SPIDERS
(r1830) - Refactored HTTP Cache middleware
- HTTP Cache middleware has been heavilty refactored, retaining the same functionality except for the domain sectorization which was removed. (r1843 )
- Renamed exception:
DontCloseDomain
toDontCloseSpider
(r1859 | #120) - Renamed extension:
DelayedCloseDomain
toSpiderCloseDelay
(r1861 | #121) - Removed obsolete
scrapy.utils.markup.remove_escape_chars
function - usescrapy.utils.markup.replace_escape_chars
instead (r1865)
Scrapy 0.7¶
First release of Scrapy.
Scrapy に貢献する¶
重要
この文書の最新版を確認してください. http://doc.scrapy.org/en/master/contributing.html
Scrapy に貢献する方法はたくさんあります. ここに幾つか示します:
- Scrapyについてのブログ. あなたがScrapyをどのように使っているかを世界に伝えてください. これは, より多くの新しい仲間と, Scrapyプロジェクトの可視性を高めるのに役立ちます.
- issue tracker にバグと、機能の要望を報告する. 下記の `Reporting bugs`_ に記載されているガイドラインに従ってください.
- 新しい機能やバグ修正のためのパッチを提出する. パッチを作成して提出する方法の詳細は `Writing patches`_ と `Submitting patches`_ を読んで下さい.
- あなたのアイデアを共有するために scrapy-users メーリングリストに参加する. 私たちは常に提案を受け入れています.
バグの報告¶
注釈
Please report security issues only to scrapy-security@googlegroups.com. This is a private list only open to trusted Scrapy developers, and its archives are not public.
Well-written bug reports are very helpful, so keep in mind the following guidelines when reporting a new bug.
- check the FAQ first to see if your issue is addressed in a well-known question
- check the open issues to see if it has already been reported. If it has, don’t dismiss the report but check the ticket history and comments, you may find additional useful information to contribute.
- search the scrapy-users list to see if it has been discussed there, or if you’re not sure if what you’re seeing is a bug. You can also ask in the #scrapy IRC channel.
- write complete, reproducible, specific bug reports. The smaller the test case, the better. Remember that other developers won’t have your project to reproduce the bug, so please include all relevant files required to reproduce it. See for example StackOverflow’s guide on creating a Minimal, Complete, and Verifiable example exhibiting the issue.
- include the output of
scrapy version -v
so developers working on your bug know exactly which version and platform it occurred on, which is often very helpful for reproducing it, or knowing if it was already fixed.
パッチを書く¶
The better written a patch is, the higher chance that it’ll get accepted and the sooner that will be merged.
Well-written patches should:
- contain the minimum amount of code required for the specific change. Small patches are easier to review and merge. So, if you’re doing more than one change (or bug fix), please consider submitting one patch per change. Do not collapse multiple changes into a single patch. For big changes consider using a patch queue.
- pass all unit-tests. See `Running tests`_ below.
- include one (or more) test cases that check the bug fixed or the new functionality added. See `Writing tests`_ below.
- if you’re adding or changing a public (documented) API, please include the documentation changes in the same patch. See `Documentation policies`_ below.
パッチを提出する¶
The best way to submit a patch is to issue a pull request on GitHub, optionally creating a new issue first.
Remember to explain what was fixed or the new functionality (what it is, why it’s needed, etc). The more info you include, the easier will be for core developers to understand and accept your patch.
You can also discuss the new functionality (or bug fix) before creating the patch, but it’s always good to have a patch ready to illustrate your arguments and show that you have put some additional thought into the subject. A good starting point is to send a pull request on GitHub. It can be simple enough to illustrate your idea, and leave documentation/tests for later, after the idea has been validated and proven useful. Alternatively, you can send an email to scrapy-users to discuss your idea first. When writing GitHub pull requests, try to keep titles short but descriptive. E.g. For bug #411: “Scrapy hangs if an exception raises in start_requests” prefer “Fix hanging when exception occurs in start_requests (#411)” instead of “Fix for #411”. Complete titles make it easy to skim through the issue tracker.
Finally, try to keep aesthetic changes (PEP 8 compliance, unused imports removal, etc) in separate commits than functional changes. This will make pull requests easier to review and more likely to get merged.
コーディングスタイル¶
Please follow these coding conventions when writing code for inclusion in Scrapy:
Scrapy 寄稿者¶
Scrapy contrib shares a similar rationale as Django contrib, which is explained in this post. If you are working on a new functionality, please follow that rationale to decide whether it should be a Scrapy contrib. If unsure, you can ask in scrapy-users.
ドキュメントポリシー¶
- Don’t use docstrings for documenting classes, or methods which are
already documented in the official (sphinx) documentation. For example, the
ItemLoader.add_value()
method should be documented in the sphinx documentation, not its docstring. - Do use docstrings for documenting functions not present in the official
(sphinx) documentation, such as functions from
scrapy.utils
package and its sub-modules.
テスト¶
Tests are implemented using the Twisted unit-testing framework, running tests requires tox.
テストの実行¶
Make sure you have a recent enough tox installation:
tox --version
If your version is older than 1.7.0, please update it first:
pip install -U tox
To run all tests go to the root directory of Scrapy source code and run:
tox
To run a specific test (say tests/test_loader.py
) use:
tox -- tests/test_loader.py
To see coverage report install coverage (pip install coverage
) and run:
coverage report
see output of coverage --help
for more options like html or xml report.
テストを書く¶
All functionality (including new features and bug fixes) must include a test case to check that it works as expected, so please include tests for your patches if you want them to get accepted sooner.
Scrapy uses unit-tests, which are located in the tests/ directory. Their module name typically resembles the full path of the module they’re testing. For example, the item loaders code is in:
scrapy.loader
And their unit-tests are in:
tests/test_loader.py
バージョニングとAPIの安定性¶
バージョニング¶
Scrapyバージョンには3つの数字があります: A . B . C
- A はメジャーバージョンです. これはめったに変わらず, 非常に大きな変更を意味します.
- B はリリース番号です. これには, 後方互換性を損なう可能性のある機能やものを含む多くの変更が含まれますが, これらのケースを最小限に抑えるよう努めています.
- C はバグ修正リリース番号です.
下位互換性は明示的に リリースノート に示されていますが, アップグレードする前に特別な注意が必要な場合があります.
開発リリースは3桁のバージョンに従わず, 一般的に末尾に dev
をつけています. 例: 1.3dev
.
注釈
Scrapy 0.* シリーズでは, Scrapyは開発版に奇数バージョンを使用しました. Scrapy 1.0 以降のケースではありません. Scrapy 1.0からは、すべてのリリースがプロダクションの準備ができていると見なされるべきです.
例:
- 1.1.1 は 1.1 シリーズの最初のバグフィックスバージョンです. (製品版で安全に使用するための.)
API 安定性¶
API 安定性は 1.0 のリリースで一つのゴールを迎えました.
単一のダッシュ( _
)で始まるメソッドまたは関数はprivateであり, 決して安定したものであるべきではありません.
安定したAPIは新しいメソッドや機能を拡張する可能性がありますが、既存のメソッドは同じ方法で機能し続ける必要があります。
- リリースノート
- 最近のScrapyのバージョンで何が変わったのか見る.
- Scrapy に貢献する
- Scrapyプロジェクトに貢献する方法を学ぶ.
- バージョニングとAPIの安定性
- ScrapyのバージョニングとAPIの安定性を理解する.