【Python】Scrapyを使ったWebスクレイピング実装方法

開発環境
この記事は約12分で読めます。

こんにちは。岡本です。

Webスクレイピング(ウェブサイトからデータを自動的に取得する技術)をしたい場合、ツール作成に用いるプログラム言語として採用候補の筆頭となるのがPythonではないでしょうか。

PythonでWebスクレイピングを行う方法はいくつかありますが、その中でもScrapyは強力なWebスクレイピングフレームワークです。今回はScrapyを使ったスクレイピングの実装方法について、具体的な練習用サイトを使って解説します。

Scrapyとは?

Scrapyは、Pythonで書かれたオープンソースのWebスクレイピングフレームワークです。以下の特徴があります。

  • 高速なクロール
    非同期処理を用いて多数のページを高速にクロールできます。
  • 柔軟なデータ抽出
    CSSセレクターやXPathを使用して、HTMLから簡単にデータを抽出できます。
  • プラグインによる拡張性
    プロキシの使用やデータの保存形式のカスタマイズが可能です。

前述したとおり、PythonによるWebスクレイピング手法はいくつかあります。代表的なものはBeautiful Soup と Requestsを組み合わせる方法と、Seleniumを用いるものです。それらと比較した特徴をまとめると、下記のとおりです。

特徴Beautiful Soup + RequestsSeleniumScrapy
シンプルさ高い中程度低い
非同期処理なしなしあり
動的コンテンツ対応不可対応可能JavaScript実行には未対応
パフォーマンス高い低い高い
拡張性と機能低い中程度高い
Pythonによるスクレイピング手法別の特徴比較

Scrapyは、高速な非同期処理と包括的な機能を提供するため、大規模なデータ取得や複雑なスクレイピングタスクに最適です。一方で、設定やプロジェクト構成があるため学習コストがかかったり、動的コンテンツは苦手などのデメリットもあります。

スクレイピングアプリケーションの実装手順

ここからは、Scrapyを使ったWebスクレイピングアプリケーションを実装する手順について解説します。

Scrapyのインストール

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

pip install scrapy

Scrapyプロジェクトの作成

次に、Scrapyプロジェクトを作成します。コマンドラインで以下のコマンドを実行します。

scrapy startproject bookscraper

これにより、bookscraperという名前の新しいプロジェクトフォルダーが作成されます。(任意のプロジェクト名を指定できます。)このフォルダーには、Scrapyの基本構造が含まれています。

作成されたプロジェクトフォルダーの構造は以下のとおりです。

bookscraper/
 └   scrapy.cfg          # プロジェクト設定ファイル
 └   bookscraper/          # プロジェクトのPythonモジュール
__init__.py
      └  items.py       # スクレイピングしたデータの構造を定義するファイル
      └  middlewares.py # リクエストやレスポンスを処理するためのカスタムミドルウェアを定義するファイル
      └  pipelines.py   # スクレイピングしたデータを処理・保存するためのパイプラインを定義するファイル
      └  settings.py    # Scrapyプロジェクト全体の設定を管理するファイル
      └  spiders/       # スパイダー(実際にデータを収集するプログラム)を格納するディレクトリ
__init__.py

スパイダーの作成

次に、データを抽出するためのスパイダー(実際にデータを収集するプログラム)を作成します。bookscraper/spidersディレクトリに移動し、新しいPythonファイルを作成します。

以下は、Books to Scrape(スクレイピング練習用に公開されているサイト)から書籍のタイトルと価格をスクレイピングするスパイダー(例:book_spider.py)の例です。

import scrapy

class BooksSpider(scrapy.Spider):
    name = "books"
    start_urls = [
        'http://books.toscrape.com/',
    ]

    def parse(self, response):
        for book in response.css('article.product_pod'):
            yield {
                'title': book.css('h3 a::attr(title)').get(),
                'price': book.css('p.price_color::text').get(),
            }
        next_page = response.css('li.next a::attr(href)').get()
        if next_page is not None:
            yield response.follow(next_page, self.parse)

このスパイダーは、http://books.toscrape.com/をクロールし、各書籍のタイトルと価格を抽出します。

スパイダーの実行

スパイダーを実行するには、コマンドラインで以下のコマンドを実行します。

scrapy crawl books

これにより、スパイダーが起動し、指定されたURLからデータを収集します。収集されたデータはターミナルに出力されます。実行結果を一部抜粋したものが下記です。

...省略...
2024-05-16 15:29:37 [scrapy.core.scraper] DEBUG: Scraped from <200 http://books.toscrape.com/catalogue/page-35.html>
{'title': 'Animal Farm', 'price': '£57.22'}
2024-05-16 15:29:37 [scrapy.core.scraper] DEBUG: Scraped from <200 http://books.toscrape.com/catalogue/page-35.html>
{'title': 'A Walk to Remember', 'price': '£56.43'}
2024-05-16 15:29:37 [scrapy.core.scraper] DEBUG: Scraped from <200 http://books.toscrape.com/catalogue/page-35.html>
{'title': "A New Earth: Awakening to Your Life's Purpose", 'price': '£55.65'}
...省略...

データの保存

スクレイピングしたデータはJSONやCSVファイルなど、さまざまな形式で保存可能です。例えば、スクレイピング結果がbooks.jsonというファイルに保存する場合は、以下のコマンドを使うことで実現できます。

scrapy crawl books -o books.json

出力結果を一部抜粋したものが下記です。

[
{"title": "A Light in the Attic", "price": "£51.77"},
{"title": "Tipping the Velvet", "price": "£53.74"},
{"title": "Soumission", "price": "£50.10"},
{"title": "Sharp Objects", "price": "£47.82"},
 ...省略...
]

データ保存の設定

データの保存形式は、-oオプションの後に続けてファイル名を指定することで変更できます。例えば、CSV形式で保存したい場合は以下のようにします。

scrapy crawl books -o books.csv

また、設定ファイル(settings.py)でデフォルトのエクスポート形式を設定することも可能です。

FEED_FORMAT = 'json'
FEED_URI = 'output/books.json'

具体例: Books to Scrapeサイトからのデータ抽出

ここでは、具体的な例としてBooks to Scrapeサイトから書籍の詳細情報(タイトル、価格、在庫状況、評価)を抽出する方法を紹介します。

スパイダーの詳細設定

以下は、より詳細な情報を抽出するスパイダーの例です。(例:book_spider_detail.py)

import scrapy

class BooksSpider(scrapy.Spider):
    name = "books_detailed"
    start_urls = [
        'http://books.toscrape.com/',
    ]

    def parse(self, response):
        for book in response.css('article.product_pod'):
            yield {
                'title': book.css('h3 a::attr(title)').get(),
                'price': book.css('p.price_color::text').get(),
                'availability': book.css('p.availability::text').re_first('\n\s*(\S.*\S)\s*\n'),
                'rating': book.css('p.star-rating::attr(class)').re_first('star-rating (\w+)')
            }
        next_page = response.css('li.next a::attr(href)').get()
        if next_page is not None:
            yield response.follow(next_page, self.parse)
詳細情報の抽出方法
  • タイトル: book.css('h3 a::attr(title)').get()
  • 価格: book.css('p.price_color::text').get()
  • 在庫状況: book.css('p.availability::text').re_first('\n\s*(\S.*\S)\s*\n')
    • re_firstを使用して正規表現で前後の空白をトリムしています。
  • 評価: book.css('p.star-rating::attr(class)').re_first('star-rating (\w+)')
    • クラス名から評価の文字列(One, Two, Three, Four, Five)を抽出しています

実行結果の確認

スパイダーの実行結果をJSONファイルとして保存してみると、以下のようなデータが含まれています。

[
{"title": "A Light in the Attic", "price": "£51.77", "availability": "In stock", "rating": "Three"},
{"title": "Tipping the Velvet", "price": "£53.74", "availability": "In stock", "rating": "One"},
{"title": "Soumission", "price": "£50.10", "availability": "In stock", "rating": "One"},
{"title": "Sharp Objects", "price": "£47.82", "availability": "In stock", "rating": "Four"},
...省略...
]

実運用時に考慮すべきポイント

以上の手順で比較的簡単にWebスクレイピングアプリケーションは実装できますが、実際にプロジェクトでScrapyを運用する際には、いくつかの考慮事項があります。

サーバーへの負荷軽減

Webスクレイピングを行う際には、対象のウェブサイトに過度な負荷をかけないようにすることが重要です。Scrapyでは、リクエストの間隔を設定することでサーバーへの負荷を軽減できます。

# settings.pyに追加
DOWNLOAD_DELAY = 2  # 各リクエストの間隔を2秒に設定

ユーザーエージェントの設定

一部のウェブサイトは、ユーザーエージェントをチェックしてボットのアクセスを拒否する場合があります。Scrapyでユーザーエージェントをカスタマイズする方法は以下の通りです。

# settings.pyに追加
USER_AGENT = 'my-custom-user-agent'

まとめ

Pythonを用いてWebスクレイピングをする場合、Scrapyは非常に有用です。本記事では基本的なセットアップから、練習用サイト「Books to Scrape」を使った例までを簡単に紹介しました。

Scrapyをマスターすることで、ウェブから必要なデータを取得し、さまざまなプロジェクトに活用できます。スクレイピングを行う際は、ウェブサイトの利用規約や法律を遵守し、適切なマナーで行うよう心がけましょう!

コメント

タイトルとURLをコピーしました