見出し画像

scrapy・scrapinghub入門

Python用スクレイピングフレームワーク「scrapy」を使いはじめて、scrapinghubで使えるようにするまでの公式チュートリアル動画「Learn Scrapy」を、自分なりに書き起こした備忘録から公開できるようにしたものです。

チュートリアル動画は https://learn.scrapinghub.com/scrapy/ にあります。動画は英語で解説されていますが、画面の動きが見られるので、画面だけ見ていればだいたい何をしているかはわかると思います。動画内のサンプルコードはURL先にある動画ページに「Toggle code」と書いてある部分をクリックすると表示されます。

動作環境としてはmacOSを想定していますが、WindowsやLinux、その他UnixライクOSでも条件が整えば動くと思います。モジュールのインストールはpipを使うことを前提にしています。Pythonが動作していて、scrapyのインストールも「pip install scrapy」コマンドでインストールした状態から読みはじめてください。

目次

Chap. 1 事始め
Chap. 2 はじめてのスパイダー作成
Chap. 3 複数アイテムの取得
Chap. 4 ページネーションの対応
Chap. 5 詳細ページのスクレイピング
Chap. 6 無限にスクロールをするページのスクレイピング
Chap. 7 スパイダーでフォームの送信をする
Chap. 8 JavaScriptページをスクレイピングする
Chap. 9 scrapinghubにデプロイして実行する

Chap. 1 事始め

Getting Started with Web Scraping

スクレイピングしたいURLを、scrapy shellというCLIから開きます。うまく接続できればWebブラウザのコンソールのように使うことができます。CSSセレクタでページ内の内容を取得できます。IPythonが入っていればIPythonのプロンプトが表示されます。IPythonも入れておくと便利でしょう。

$ scrapy shell <URL>
>>> print(response.text)
レスポンスの内容のテキスト表現

>>> response.css(CSSセレクタ)
[セレクタオブジェクト, ...]

>>> response.css(CSSセレクタ).extract()
[選択された内容, ...]

>>> response.css(CSSセレクタ)[0].extract()
または
>>> response.css(CSSセレクタ).extract_first()
選択された最初の内容

>>> response.css('a::text').extract_first()
最初に出現したaタグのテキストノードの中身

Chap. 2 はじめてのスパイダー作成

Creating your First Scrapy Spider

スクレイピングをするモジュール(スパイダー)を作ります。scrapyのgenspiderサブコマンドでスケルトンコードを生成します。引数には自分がつけたい名前と対象とするドメイン名にします(後で変更できます)。
$ scrapy genspider <名前> <ドメイン名>
(名前).pyというファイルが生成されたら、エディタで編集します。

ここではチュートリアル通り「scrapy genspider quotes toscrape.com」と実行した時に生成される、quotes.pyというファイルを例にします。内容は以下のようになっています:

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

class QuotesSpider(scrapy.Spider):
    name = 'quotes'
    allowed_domains = ['toscrape.com']
    start_urls = ['http://toscrape.com/']

    def parse(self, response):
        pass

nameとallowed_domainsという値が、先程実行した値に反映されます。よく見るとクラス名も名前にあわせて生成されています(QuotesSpider)。start_urlsの中は最初にアクセスするURLで、リスト形式となっています。つまりスタート地点は複数存在してもスパイダーは1つで良いということです。

ここままの状態でも実行することもできますが、QuotesSpiderのparseメソッドがコールされた時何も行わないので、ここを編集します。実際はscrapy shellで確認しながら、想定した動作のコードをコピペしていくのが簡単でしょう。基本的には以下のようにparseメソッド内からパースした内容を辞書型のデータにまとめて、yieldステートメントで返すような動作にします:

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

class QuotesSpider(scrapy.Spider):
    name = 'quotes'
    allowed_domains = ['toscrape.com']
    start_urls = ['http://quotes.toscrape.com/random']

    def parse(self, response):
        self.log('I just visited: ' + response.url)
        yield {
            'author_name': response.css('small.author::text').extract_first(),
            'text': response.css('span.text::text').extract_first(),
            'tags': response.css('a.tag::text').extract(),
        }

作成したスパイダーはrunspiderコマンドで実行します。
$ scrapy runspider quotes.py

scrapyコマンドのオプション引数を使い、取得したデータをJSON形式で出力できます。
$ scrapy runspider quotes.py -o items.json

Chap. 3 複数アイテムの取得

Scraping Multiple Items per Page

response.css()で返った値を、さらにcss()で問い合わせられます。

response.css('div.quote')でdivタグのリストを取得できたら、それらに対してさらにcss(任意のCSSセレクタ)を実行します。

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

class MultipleQuotesSpider(scrapy.Spider):
    name = "multiple-quotes"
    allowed_domains = ["toscrape.com"]
    start_urls = ['http://quotes.toscrape.com']  # randomを削除

    def parse(self, response):
        self.log('I just visited: ' + response.url)
        for quote in response.css('div.quote'):  # divタグを列挙
            item = {
                'author_name': quote.css('small.author::text').extract_first(),
                'text': quote.css('span.text::text').extract_first(),
                'tags': quote.css('a.tag::text').extract(),
            }
            yield item

変更部分にコメントを入れてみました。(yield部分がChap. 2の動画と若干違いますが振る舞いは変わりません)

Chap. 4 ページネーションの対応

Following Pagination Links

次ページへのリンクをセレクタで取得できるようにすると、ページをたどれるようになります。これはparseメソッド内に数行追加するだけで可能です。

ここから先は

8,242字

¥ 550

この記事が気に入ったらサポートをしてみませんか?