Python + Scrapy でWebサイトからデータを取得してみました

Pythonを使ってWebサイトの情報を収集する方法を調べていたところ、
Scrapyというフレームワークを使うと簡単にスクレイピングできることがわかりました。
使ったことがなかったので、今回はこのフレームワークスクレイピングをしてみました。




  • 参考




Scrapy Tutorial — Scrapy 1.2.3 documentation



Scrapy でクローリング、スクレイピングする - Tech見習い





ちなみにスクレイピングの方法によっては法に触れる可能性もあるので、
注意事項を守って使うようにしないといけないようです。



qiita.com






Scrapy(スクラピー)とは



クローリング、スクレイピングを簡単に行うためのPythonフレームワークです。

しばらくはPython2でしか対応していませんでしたが、2016年からPython3に対応しました。




  • クローリング:Webページのリンクを辿りながら保存する処理のこと。


  • スクレイピング:保存したページから特定の情報を抽出する処理のこと。





環境



MacOS / Python 3.6.3 / Scrapy 1.4.0






Scrapyをインストール



pipでインストールします。



$ pip install scrapy






初期ファイルを生成



scrapy startproject {プロジェクト名} コマンドを実行することで必要なファイルを生成してくれます。
今回はプロジェクト名を first_scrapy としています。



$ scrapy startproject first_scrapy






Spiderの作成



Scrapyでクローリング・スクレイピングをするためには、このSpiderというクラスが必要になります。
対象となるURLの設定や、収集データの条件の設定、スクレイピングの処理を実装します。





Scrapyのgenspiderコマンドを使うと、Spiderの雛形を生成することができます。
scrapy genspider {Spider名} {クロール対象のドメイン} コマンドを実行します。
今回は、はてなブログの人気記事をスクレイピングしたかったので、
Spider名をhatena 、ドメイン名を b.hatena.ne.jp としています。



$ scrapy genspider hatena b.hatena.ne.jp





コマンド実行後、spidersフォルダ配下にコマンドで指定したSpider名のpyファイルが作成されます。






Spiderの実装



作成したSpiderファイルを修正します。
start_urlsへHTTPリクエストした結果がresponseに渡されparseメソッドが処理されます。

今回は、クロールを開始するURL(start_urls)を修正し、
タイトルを抽出して出力する処理をparseメソッドに追加します。




# -*- coding: utf-8 -*-
import scrapy


class CotucotuSpider(scrapy.Spider):

# Spiderの名前(初期設定のまま)
name = 'hatena'
# クロール対象のドメイン(初期設定のまま)
allowed_domains = ['b.hatena.ne.jp']
# クロールを開始するURLをリストで指定
start_urls = ['http://b.hatena.ne.jp/ctop/it']

# start_urlsで指定したページを取得後に呼ばれるメソッド。spider.Responseオブジェクトを受け取る。
def parse(self, response):

# 記事のタイトルを抜き出す
titles = response.xpath('//h3/a[@class="entry-link"]//text()')
[ print(title) for title in titles.extract()]






XPATHの指定について



parseメソッドで記事を抽出するためにXPATHを指定する必要があります。
XPATHXML からパスを指定してタグや属性、値を抽出する記法です。





これは実際にWebサイトのHTMLをみて、抽出したい情報のタグを調べました。
今回はclassが entry-link のaタグのtextを抽出したかったので、下記のように指定しました。



titles = response.xpath('//h3/a[@class="entry-link"]//text()')



他にも指定の方法が色々あります。





全てのdivタグ



//div





全ての、classに'aaa'を持つdivタグ



//div[@class='aaa']





全ての、idが'aaa'のdivタグ -> の本文



//div[@id='aaa']/text()





全ての、本文が'aaa'のaタグ -> のhref属性値



//a[text()='aaa']/@href





全てのdiv -> 子要素のtrタグ



//div/tr






XPATHの結果取得方法について



XPATHで指定した結果として、responseから値を取得するにはextract()を使います。




  • extract() :複数のノードからテキストを取得するにはextract()を使用します。結果は文字列のリストです。


  • extract_first() :1つのノードからテキストを取得するにはextract_first()を使用します。結果は文字列です。








Spiderを実行



runspiderコマンドを実行します。



$ scrapy runspider --nolog first_scrapy/spiders/hatena.py





タイトルを取得することができました。

次は取得したデータを整形したりもう少し手を加えてみようと思います。