第4章 Scrapy Tutorial1
はじめに
ここでは、Scrapyのドキュメントに載っているチュートリアルを参考に、Scrapyでクローラーを作成する。チュートリアルを完全に再現するわけではなく、チュートリアルを題材にしながら寄り道しながら進めていきます。チュートリアルを実行されたい方はドキュメントを参照ください。スクレイピングの対象にするサイトは、チュートリアルと同じで下記の有名人の名言サイトです。
プロジェクトの作成
まずはプロジェクトを作成します。ここではプロジェクトの名前は「sample_quotes」で、クローラーの名前を「quotes_spider」としています。プロジェクトを作ったら、settings.pyの中身を礼儀が正しいように書き換えるのは忘れずに行います。
今回は「spiders/quotes_spider.py」と「settings.py」だけ使います。これだけでも動かせるので。
$ scrapy startproject sample_quotes
$ cd sample_quotes
$ scrapy genspider quotes_spider quotes.toscrape.com
$ tree
.
├── sample_quotes
│ ├── __init__.py
│ ├── items.py
│ ├── middlewares.py
│ ├── pipelines.py
│ ├── settings.py **これ**
│ └── spiders
│ ├── __init__.py
│ └── quotes_spider.py **これ**
└── scrapy.cfgHTML構造の調査とクローラーの設計
スクレイピングする前に、スクレイピングするページのHTML構造を確認します。こんページであれば、黒枠のブロックごとに青い線の「名言」、赤い線の「名前」、黄色い線の「タグ」が同じようなレイアウトで表示されています。

同じようなレイアウトで表示されているということは、HTMLの書き方も同じようになっているということです。実際にブラウザの検証機能で確認すると、同じようなHTML構造になっています。

これであれば、「ブロックを取得→詳細をスクレイピング→次のブロック→詳細をスクレイピング」ということを繰り返せば取得できそうです。実際に値がとれるか、Scrapy Shellを利用して確認します。
Scrapy Shell
URLを渡して、Scrapy Shellでレスポンスを受け取ります。
まずはブロックの部分を取得します。ブロックの部分は、classがすべて「quote」なので、それをxpathに渡します。cssセレクタで指定することも可能ですが、ここでは、xpathにしぼります。xpathセレクターの使い方は、ドキュメントのSelectorsを参照してください。
数を数えてみると、10が返ってきます。ページの名言ブロックと一致しているのでOKですね。次は詳細部分をスクレイピングします。
まずは名言を取得します。まずは、1番上のブロックをquoteに格納します。そして、quoteを使って、名言部分を先ほどと同じようにxpathで指定します。名言は、classがすべて「text」なので、それをxpathに渡します。
次は、同じ要領で「名前」と「タグ」をスクレイピングします。
これでスクレイピングしたい情報のコードが書けました。これをブロックごとに繰り返したいので、下記のようにfor-loopで書き直し、取得した値はyieldで出力します。
このページ1枚であればこれで良いのですが、全部で10ページあるので、次のページにクローラーを動かせるように、コードを追加します。次のページへの判断は「Next」があるかどうかで判断させます。10ページを見ると「Next」がないので、これ以上はクローラーは進まなくなります。
「Next」があるかどうかを調べるためにScrapy Shellで確認します。このボタンはclassが「next」でa要素に次のページへのURLがついているので、それがあるかないかで判定します。
URLがあるかどうかで判定するのはこれで良いのですが、クローラーがこの相対パスのURLでは移動できません。なので、完全パスにURLをurljoinで修正します。
これで10ページ文の名言100個をスクレイピングする準備ができました。これを実行していきます。ページの移動のさせ方は下記のようにページ番号をインクリメントするように書いても問題ないです。
クローラーの実行
ここまでのコードを「spiders/quotes_spider.py」に書き込むと下記のようになります。
このクローラーのイメージを書くとこんな感じになります。

では、scrapy crawlコマンドでクローラーを実行します。ここではJSONで書き出します。大量のログとともに、スクレイピングされていきます。
アウトレットされたJSONを確認してみます。プロジェクト内に書き出されているはずです。

結果を確認すると、どうやら期待通りに動いてくれているようです。jqコマンドはJSONを整形して表示してくれるものです。
ログ情報
scrapy crawlコマンドでクローラーを実行すると大量のログが出力されますが、これがどのようなログなのか、まとめていきます。ある程度のブロックごとに小分けして内容をまとめます。
まずは最初の数行を確認します。ここらへんは、scrapyのバージョンとか、関連するライブラリのバージョン、クローラーの名前、書き出し形式やそのファイル名、robots.txtに従うかどうか、みたいなことが書いてあります。
ここらへんの行は、middlewareの設定が書いてあります。さきほどの部分でROBOTSTXT_OBEYがTrueになっていましたが、このmiddlewareの中で、RobotsTxtMiddleware(9行目)が有効になっていることもわかります。どのタイミングでMidllewareによってパイプラインが拡張されるのかは、ScrapyのアーキテクチャのMiddlewareの部分を見ればわかると思います。
続きを進めていきます。4行目でrobotx.txtのページにリクエストを送っています。6行目を見るとスクレイピングが開始され、7行目からその結果が出力されています。
100個目のスクレイピングが終わったところから、ログを眺めていきます。「'downloader/request_count': 11」「'downloader/request_method_count/GET': 11」なのはrobot.txtが1ページと名言が10ページの合計11ページにリクエスト(GET)したということです。
「'downloader/response_status_count/200':10」「'downloader/response_status_count/404': 1」なのはrobot.txtが1ページが404で名言の10ページは200で正常に返ってきたからですね。
終了時刻の後にある「'item_scraped_count': 100」は100個のアイテムをスクレイピングしたことを意味します。その他のログは書いてあるとおりです。
最終更新
役に立ちましたか?