Scrapyのアーキテクチャ

Scrapyのアーキテクチャ

Scrapy続編。Scrapyは、Python製のwebスクレイピングのためのフレームワークです。
フレームワークを理解するには、アーキテクチャを理解する必要があります。Djangoもそうですが、Python製のフレームワークは各コンポーネントの役割分担が明瞭で分かりやすいですね。
このアーキテクチャを理解すれば、割と簡単に使いこなすことができます。

概略図 f:id:kimoppy126:20181111044240p:plain

一連の流れ

① EngineがRequestをSpiderから受け取る。
② EngineはRequestsを処理するためのスケジュールをScheduler中に作成し、次に実行すべきRequestを要求する。
③ Schedulerは、次に実行すべきRequestを返す。
④ Engineは、Downloader Middlewares中のprocess_request()関数を介してDownloaderにRequestを送る。
⑤ ページのダウンロードが終わると、Downloaderは、Downloader Middlewares中のprocess_response()を介してEngineに対しResponseを返す。
⑥ EngineがDownloaderからResponseを受け取ると、その内容をスクレイピングしてもらうためSpider Middleware中のprocess_spider_input()を介してSpiderに受け渡す。
⑦ Spider はResponseを適切に処理し、スクレイピング結果のitemsと新しいRequestをSpider Middleware中のprocess_spider_output()を介してEngineに対して返す。
⑧ Engine はプロセシングが行われたitemをItem Pipelinesに渡した後、プロセシングが行われたRequestをSchedulerに送り次のクロールすべきRequestを要求する。
⑨ Schedulerから送られてくるRequestがなくなるまで繰り返す。

各要素の役割

上記フローを見れば大体各コンポーネントの役割はわかるが、一つ一つ見ていく。

Scrapy Engine

コンポーネント間のデータフローの制御を担当しており、特定のアクションが発生したら、イベントを発生させる。

Scheduler

EngineからRequestを受け取り、キューイングを行う。

Downloader

webページのダウンロードを担当。ダウンロードしたオブジェクトは、spiderに渡す。

Spiders

ユーザーが作成するカスタムクラスです。ここに取得したいURL、抽出したい部分を記述します。 ダウンロードしたコンテンツをスクレイピングして、Itemを作成する役割を持ちます。

Item Pipeline

スパイダーによって抽出されたitemのプロセシングを行います。
ここでいうプロセシングは、データのクレンジング、検証、永続化といったことが該当することになります。

Downloader middlewares

EngineとDownloaderの間を媒介し、

  • Engine からDownloaderへRequestが送られる際にプロセシング
  • DownloaderからEngineへResponse が送られる際にプロセシング

を行います。

具体的には以下のような用途で使用されます。

  • Downloaderに渡す前にRequestを処理する。
  • 受け取ったResponseをSpiderに渡す前に処理する。
  • Response をSpiderに渡す代わりに新しいRequestを送る。
  • webページにアクセスすることなく、ResponseをSpiderに渡す。
  • いくつかのRequestについて消去する。

Spider middlewares

EngineとSpidersの間を媒介し、

  • Spiderのコールバック関数の出力をプロセシングする。 - Requestやitemの変更/追加/削除ができる。
  • start_requests(最初のRequest)後の処理を行う。
  • Spiderから投げられた例外をキャッチする。
  • Responseの内容によってコールバック関数を呼ぶ代わりに例外を呼び出す。

といったことを行います。

Scrapyが並列処理可能な所以

Scrapyは、Twistedというイベント駆動型のフレームワークを使用して書かれており、並列実行ためのノンブロッキングコードを使用して実装されています。
これにより並列でスクレイピングを回すことが可能となっているのでした。