LoginSignup
4
5

More than 5 years have passed since last update.

Scrapy をはじめる

Last updated at Posted at 2018-11-04

オフィシャルページなど

公式ページ https://scrapy.org/
公式ドキュメント https://docs.scrapy.org/en/latest/index.html
Github https://github.com/scrapy/scrapy

Scrapyとは?

WebサイトなどをスクレイピングするためのPythonのフレームワークです。
スクレイピング とは HTML や Javascript, CSS などから情報を収集することです。Python で usllib や re (正規表現) を組み合わせれば同じことができますが Scrapyを使うメリットとして

  • 少ない記述量
  • 複数のWebページを遷移する複雑なスクレイピングができる
  • 自動的に並列化された高速なクローリング
  • Web UI など Scrapy 向けに作れた便利ライブラリが使える

一方でデメリットとしては

  • いちいちプロジェクトを作る必要があり面倒

つまり正規表現で事足りる小規模なスクリプトでは不要と思います。

インストール

pip install scrapy

Windowsでビルドに失敗する場合Python公式の案内を参考にBuild Tools for Visual Studio をインストールします。

最初のスクリプト

最初にプロジェクトを作成する必要があり、コマンドラインでプロジェクトを作る場所に移動したら次のようにします。
myfirstproject が今回のプロジェクト名です。

scrapy startproject myfirstproject

プロジェクトのファイル一式が自動生成されます。
次に Spider (Scarpyのクローラーのクラス) を継承したクラスの定義ファイルを作ります。

cd myfirstproject
scrapy genspider myfirstspider quotes.toscrape.com
  • myfirstspider が今回のクラス名です。
  • quotes.toscrape.com がスクレイプを行う対象のサイトの ドメイン です。

myfirstproject/spiders/myfirstspider.py が生成されます。
まずは myfirstspider.pyparse 関数に次のように書き換えます。

myfirstspider.py
    def parse(self, response):
        text = response.xpath("//div[@class='quote']/span[1]/text()").extract()
        print(text)

Scrapyは spider クラスの start_urls のページをダウンロードしたあと parse 関数を呼び出します
parse 関数の response 引数にはダウンロードされたページが入っています
myfirstspider.py を編集できたらさっそく実行します。

scrapy crawl myfirstspider --loglevel WARNING

loglevelを指定したのはデフォルトではデバッグログが大量出力されるためです。
問題がなければ **スクレイプ されたテキストが表示されます。

['“The world as we have created it is a process of our thinking. It cannot be changed without changing our thinking.”', '“It is our choices, Harry, that show what we truly are, far more than our abilities.”', '“There are only two ways to live your life. One is as though nothing is a miracle. The other is as though everything is a miracle.”', '“The person, be it gentleman or lady, who has not pleasure in a good novel, must be intolerably stupid.”', "“Imperfection is beauty, madness is genius and it's better to be absolutely ridiculous than absolutely boring.”", '“Try not to become a man of success. Rather become a man of value.”', '“It is better to be hated for what you are than to be loved for what you are not.”', "“I have not failed. I've just found 10,000 ways that won't work.”", "“A woman is like a tea bag; you never know how strong it is until it's in hot water.”", '“A day without sunshine is like, you know, night.”']

parse 関数内の reponse.xpath(...).extract() にてresponse に入っているページから必要な情報を抽出しています。
xpathとはXML(HTMLなど) から特定のノード(タグ)を指定するための記述方法です。
xpathの詳細。忘れやすい人にはチートシートがオススメです。
ここで使っている xpath について簡単に説明すると

  • //div[@class='quote'] : divタグ 内の class属性 が 'quote'であるもののみを指定
  • /span[1] : そのなかのspanタグの1番目のものを指定
  • /text() : そのなかのテキスト属性 を指定

xpathで指定したもの全てを extract() 関数 で抽出します。
これで text変数には抽出されたもののリストが入ります。

デバッグの方法

デバッグをしながらスクリプトを完成させるまでの手順を示します。
前のセクションのスクリプトを修正して Author の情報("by Albert Einstein (about)" のテキスト) を抽出したいとします。

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

とするとPythonシェルが起動して、指定したアドレスをScrapyが読み込んだ後に対話モードに移行します。
ちなみに起動するPythonシェルは myfirstproject/scrapy.cfg 内の [settings] セクションにて shell = ipythonのように指定できます。ipythonが入っていると指定しなくても自動で使用されるようです。

対話シェルにて

In [1]: response.url
Out[1]: 'http://quotes.toscrape.com'

responseにはダウンロードされたページが入っています。
このページのHTMLソースを確認する(chromeならCtrl+u) と <small class="author" itemprop="author">Albert Einstein</small> の記述が見つかります。smallタグの中でclass属性がauthorであるものを抽出すればよさそうです。
次のようにためしてみます。

In [2]: response.xpath("//small[@class='author']")
Out[2]:
[<Selector xpath="//small[@class='author']" data='<small class="author" itemprop="author">'>,
 <Selector xpath="//small[@class='author']" data='<small class="author" itemprop="author">'>,
 <Selector xpath="//small[@class='author']" data='<small class="author" itemprop="author">'>,
 <Selector xpath="//small[@class='author']" data='<small class="author" itemprop="author">'>,
 <Selector xpath="//small[@class='author']" data='<small class="author" itemprop="author">'>,
 <Selector xpath="//small[@class='author']" data='<small class="author" itemprop="author">'>,
 <Selector xpath="//small[@class='author']" data='<small class="author" itemprop="author">'>,
 <Selector xpath="//small[@class='author']" data='<small class="author" itemprop="author">'>,
 <Selector xpath="//small[@class='author']" data='<small class="author" itemprop="author">'>,
 <Selector xpath="//small[@class='author']" data='<small class="author" itemprop="author">'>]

うまくいったようですが、欲しいの このsmallタグの中のテキストです。
なので次のようにしてみます。

In [3]: response.xpath("//small[@class='author']/text()").extract()
Out[3]:
['Albert Einstein',
 'J.K. Rowling',
 'Albert Einstein',
 'Jane Austen',
 'Marilyn Monroe',
 'Albert Einstein',
 'André Gide',
 'Thomas A. Edison',
 'Eleanor Roosevelt',
 'Steve Martin']

これで必要なテキストのリストを取得できました。
response.xpath("//small[@class='author']/text()").extract()をスクリプトに追加して完成させます。

結果の保存

スクレイピングした結果をファイルに保存する方法はいくつかあります。

  • parse 関数内で直接ファイルに書き込んでしまう
  • Scarpy の item, pipelines を使う
  • Scapy の Feed exports を使う

今回は Feed exports を使ってみます。
まず、parse関数にて 必要な情報を辞書にして yield で返すようにします。

 def parse(self, response):
    author_list = response.xpath("//small[@class='author']/text()").extract()
    yield {'author': author_list}

あとはコマンドラインから

scrapy crawl myfirstspider -o myfirstspider.json

とすると、json 形式で"myfirstspider.json"に保存されます。
保存するファイルの拡張子をかえれば csv, xmlなどでも保存できます。

4
5
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
5