Scrapyを使ったシンプルなスクレイピング

こんにちは。プラットフォーム事業部のKです。
本稿ではScrapyを用いたシンプルなWebスクレイピングについて紹介します。

この記事は以下の方を対象としています。

★5 Djangoの開発経験が3年以上。
★4 Djangoの開発経験が1年以上。
★3 Webサイト開発経験あり。これからDjangoを学習します。
★2 Python初級者。簡単なプログラムコードが書けます。
★1プログラミング未経験。

Scrapyとは?

Scrapyとは、Pythonで記述されている「効率よく、簡単に」データを収集するためのスクレイピングに必要な機能をまとめたライブラリです。
複数ページの非同期処理や大量のデータを処理する仕組みを提供してくれるため、利用者は「リクエスト対象の設定」、ページからの「データ抽出・加工」、収集されたデータの「保存」などに専念できます。

注意!
Webスクレイピングを行う場合は対象のWebサイトの利用規約などを確認し、許可されている場合でも相手サーバーに負荷をかけないようにしてください。

Scrapyを使ってみる

非常に多機能なライブラリですので、まずはもっとも単純な「データを収集し、保存する」までの流れを紹介します。

1. 準備:Scrapyのインストール

まずは以下のコマンドを実行し、Scrapyをインストールします。

pip install scrapy

2. プロジェクト作成

Scrapy用のプロジェクトを作成します。
ここで作成したフォルダ内に、基本構成となるファイル群が作成されるため、Scrapyでの作業はプロジェクトフォルダ内で行うことになります。

scrapy startproject myproject
cd myproject

3. スパイダー(実行プログラム)作成

実際にスクレイピングを実行するプログラム「スパイダー」を作成します。
今回は例として、Scrapy公式のチュートリアルでも使用されている「Quotes to Scrape」を対象とします。

scrapy genspider example quotes.toscrape.com

これにより、myproject/spiders/example.py にスパイダーのひな形が作成されます。

4. スクレイピング処理の実装

myproject/spiders/example.pyの中身を記載します。

import scrapy


class ExampleSpider(scrapy.Spider):
    name = "example"
    allowed_domains = ["quotes.toscrape.com"]
    start_urls = ["https://quotes.toscrape.com"]

    def parse(self, response):
        for quote in response.css("div.quote"):
            yield {
                "text": quote.css("span.text::text").get(),
                "author": quote.css("small.author::text").get(),
            }

この実装で行われていることは、以下の通りです、

  1. 「start_urls」に記載されたURLに対して、リクエストが行われます。
  2. 「parse」メソッドにて、リクエストの結果を処理します。
  3. 「response.css」メソッドは、リクエスト結果のHTMLに対してCSSセレクタで要素取得を行います。
  4. 「parse」メソッドからは、リクエスト結果から抽出した結果を返すことができます。今回は”text”と”author”の2項目を取得しています。

5. スクレイピング処理の実行、結果の保存

実装したSpiderを実行します。簡単な結果であれば、そのままファイルとして保存することも可能です。
今回実装をした「example」を実行し、処理結果をファイルに保存します。

scrapy crawl example -o result.json

実行が完了すれば、「result.json」ファイルに、実行結果が保存されています。

スクレイピング結果に対して処理を行う

基本的な使い方では上記までで対応できますが、スクレイピングした結果を任意の形式で保存したいなど、データに対して処理を実行したい場合の対応方法を紹介します。

1. Pipelineの作成

Scrapyでスクレイピング結果を処理する仕組みをPipelineといいます。
文字通り、処理結果を通していくパイプのイメージで処理できます。
今回はCSVとして結果を保存してみます。
myproject/pipelines.pyにPipelineを記載します。

class CsvWriterPipeline:
    def open_spider(self, spider):
        self.file = open(spider.name + '.csv', 'w', encoding='utf-8', newline='')
        self.writer = csv.writer(self.file)

    def close_spider(self, spider):
        self.file.close()

    def process_item(self, item, spider):
        self.writer.writerow([item['text'], item['author']])
        return item

この実装で行われていることは、以下の通りです、

  1. 「open_spider」メソッドにてPipelineはSpiderの実行時に一度初期化が行われます。
    ファイルの作成、CSVライターの初期化を行っています。
  2. 「process_item」メソッドが、実際にスクレイピング結果を処理する部分です。
    CSVへの書き込みを行っています。
    また、returnで値を返却することで、次のパイプラインへ値を渡すことができます。
  3. 「close_spider」メソッドは、Spiderの終了後に実行されます。
    ファイルのクローズを行っています。

2. 作成したPipelineの有効化

Pipelineは作成しただけでは実行されません。設定を変更して有効にします。
Scrapyのプロジェクト設定は、settings.pyに記載されているため、 myproject/settings.py を編集します。

ITEM_PIPELINES = {
   myproject.pipelines.CsvWriterPipeline: 300,
}

ITEM_PIPELINESに実行するパイプラインを記載することで有効になります。
キーが実行対象のPipeline、値が実行の優先度となります。値が低いものから順に実行されます。

3. スクレイピング処理の実行

実装したSpiderを実行します。
今回はCSV保存を処理として記載しているので、実行のみ行います

scrapy crawl example

実行が完了すれば、「example.json」ファイルに、実行結果が保存されています。

このように、スパイダーの動作を基準に「初期化」「実行」「後処理」が可能ですので、応用すればDBへの保存なども可能です!

まとめ

いかがでしたでしょうか?
今回はScrapyの基本的でシンプルな使い方を解説させていただきました。
まだまだ多くの機能がありますし、拡張機能も数多く作られています。機会があれば、より応用的な使い方についても紹介させていただきます!

最後まで読んでいただき、ありがとうございました。

【公式サイト】
https://www.scrapy.org