ウェブスクレイピングにおいては、Pythonが豊富なツール群を提供しています。Selenium、MechanicalSoup、Scrapy、Requests、Beautiful Soup、lxmlなどがこの分野で頻繁に利用されます。ただし、これらのツールは均一ではなく、それぞれが得意とする用途が異なります。本記事で示すように、互いに補完し合う関係にあるものもあります。
本記事では、ウェブスクレイピングで人気の選択肢であるScrapyとBeautiful Soupを詳しく見ていきます。
Beautiful Soupはパースライブラリです。XPathやCSSセレクタを用いたドキュメントのナビゲーションを可能にし、HTMLやXMLなどのマークアップ言語から構造化データへの変換を容易にします。一方Scrapyは、ドキュメントを読み込み(必要に応じて)保存する完全なウェブスクレイピングフレームワークです。
Beautiful Soupを用いたウェブスクレイピングの詳細を学びましょう。
本比較では以下の側面を検討します:クローリングの使いやすさ、スクレイピングの使いやすさ、速度、複数ステップ実行、プロキシローテーション、CAPTCHAの解決。
Scrapy vs. Beautiful Soup:簡易比較
お急ぎの方向けに、PythonによるウェブスクレイピングにおけるScrapyとBeautiful Soupの簡易比較を以下に示します。
Scrapyは包括的なウェブスクレイピングフレームワークであり、大規模なデータ抽出プロジェクトに最適で、クローリングの組み込みサポートを提供します。一方、Beautiful Soupは、組み込みのクローリング機能を持たない、より小規模で単純なスクレイピングタスクに最適なパースライブラリです。
大規模なスクレイピング作業ではScrapyの速度と効率性が優れ、簡易タスクではBeautiful Soupのシンプルさと使いやすさが光ります。複雑なプロジェクトにはScrapyを、単純で直接的なパースニーズにはBeautiful Soupを選択しましょう。
Scrapy
Scrapyは、ウェブのクロール、ドキュメントのダウンロード、処理、そして結果データをアクセス可能な形式で保存するためのオールインワンスイートです。Scrapyのインストールは pipまたはcondaで簡単に実行できます:
pip install scrapy
conda install -c conda-forge scrapy
Scrapyによるウェブクローリング
Scrapyは、ページやウェブサイトの集合をクロールしてスクレイピング対象のURLを収集したり、特定の情報をページが含むかどうかを発見するのに役立ちます。 Scrapyはスパイダー(Pythonクラス)を用いて動作します。スパイダーでは、ウェブサイトのナビゲーション方法、サイト構造内の探索深度、抽出するデータ、保存方法を定義できます。URLリストを構築するため、ScrapyはHTML、XML、CSVドキュメントをナビゲートし、サイトマップの読み込みも可能です。
さらにScrapyは、特定のページでXPathやCSS式をテスト・デバッグするための対話型シェル「Scrapy shell」を提供します。シェルを使用すれば、変更のたびにスパイダーを再起動する必要がなくなり、クローリングやスクレイピングの時間を節約できます。
Scrapyによるウェブスクレイピング
スクレイピングでは通常、高い柔軟性が求められます。Scrapyではドキュメント内のアイテム選択に2つの方法を提供します:XPathとCSS式です。前者は主にXMLドキュメント向け、後者はHTMLドキュメント専用です。
Scrapyのユニークな機能として、パイプラインの定義が挙げられます。アイテムがスクレイピングされると、パイプラインに送られ、そこで一連の処理(クリーニング、検証、ハッシュ化、重複排除、エンリッチメント)が実行されます。
速度
ウェブスクレイピングのもう一つの重要な側面は所要時間です。Scrapyの速度評価は容易ではありません。処理が必要なオーバーヘッドが多数存在するからです。このため、オーバーヘッドは一度だけ読み込まれ、クロールと抽出は10回実行されます。
以下の例では、単純な(つまり非動的な)ウェブページのh2タグを抽出します。全てのコードはJupyter Notebook上で実行されます。
まず、必要なScrapyライブラリをロードします:
import scrapy
from scrapy.crawler import CrawlerProcess
次に、スクレイピング作業を記述するMySpiderクラスを定義します:
class MySpider(scrapy.Spider):
name = "myspider"
start_urls = [
'https://edition.cnn.com' # または、限界時間を計算するためにこれを10回繰り返す
]
def parse(self, response):
yield {'output': response.css('h2.container_lead-package__title_url-text::text').extract()}
process = CrawlerProcess(
settings={
"FEEDS": {
"scrapy_output.json": {"format": "json", "overwrite": True}
}
})
process.crawl(MySpider)
次に、スクリプトを実行して時間を計測します:
%%timeit -n 1 -r 1
process.start()
単一ウェブ文書のクロール、スクレイピング、保存のシーケンスは約400ミリ秒を要しました。しかし、同じプロセスを10回繰り返すと1,200ミリ秒かかりました。これは単一シーケンスが約80ミリ秒かかることを示しており、非常に効率的です。オーバーヘッドを考慮しても、高負荷な作業にはScrapyが第一選択肢となるでしょう。
Scrapyによる多段階スクレイピング
X/Twitter、Substack、LinkedInなど、最も人気のあるウェブサイトでさえ、多くのサイトは動的です。つまり、ログイン画面、検索クエリ、ポップアップ、スクロール、マウスオーバーの背後には、大量の情報が隠されています。その結果、スパイダーが単にページを訪問するだけでは、そこからデータを抽出するには不十分な場合がよくあります。
Scrapyは単独ツールとして、こうした処理に対応する様々な手法を提供します。必要なHTTPリクエストを生成したり、関連するJavaScriptスニペットを実行したりする方法があります。しかし、ヘッドレスブラウザの使用が最も柔軟性があります。例えば、動的要素との連携に利用できるPlaywrightやSeleniumのScrapy統合機能があります。
ScrapyによるローテーションプロキシとCAPTCHA対策
大規模言語モデルの登場により、多くの企業がモデルの微調整に取り組むようになりましたが、これには特定の(しばしばスクレイピングされた)データが必要です。さらに、多くの組織はボットによる自社ウェブサイトのサーバー負荷を望まず、データを共有する商業的関心も持っていません。このため、多くのウェブサイトは動的に構築されているだけでなく、自動IPブロックやCAPTCHAなどのアンチスクレイピング技術を導入しています。
ロックアウトを防ぐため、Scrapyはローテーションプロキシ(およびIPアドレス)の標準ツールを提供していません。 ただし、Scrapyはミドルウェアフレームワーク(リクエストとレスポンス処理を変更するフックの集合)を通じて拡張可能です。ローテーションプロキシには、scrapy-rotating-proxiesのような専用Pythonモジュールをアタッチできます。同様の仕組みでDeCAPTCHAモジュールもアタッチ可能です。
Beautiful Soup
Scrapyとは異なり、Beautiful SoupはWeb文書からのデータ抽出・処理のための包括的なソリューションを提供しません。スクレイピング機能のみを提供します。ダウンロードした文書をBeautiful Soupに供給するだけで、CSSやXPathセレクタを通じて構造化データに変換できます。
Beautiful Soupのインストールはpipとcondaで実行可能です:
pip install BeautifulSoup4
conda install -c anaconda beautifulsoup4
Beautiful Soupによるウェブクローリング
Scrapyがスパイダーをデプロイしてウェブサイトを巡回するのに対し、Beautiful Soupにはそのような機能はありません。ただし、Pythonの創造性を発揮し、Beautiful SoupとRequestsライブラリを併用すれば、特定の深さまでウェブサイトを巡回するスクリプトを書くことは可能です。とはいえ、Scrapyほど簡単ではないのは確かです。
Beautiful Soupによるウェブスクレイピング
ウェブスクレイピングこそがBeautiful Soup 4の本領です。CSSやXPathセレクタを提供するだけでなく、ドキュメントをトラバースするための多様なメソッドを備えています。ドキュメントの構造が複雑な場合、.parentや .next_siblingなどのメソッドを使えば、通常は到達困難な要素も抽出できます。さらにfind_all()などのメソッドを通じて、テキストフィルターや正規表現、さらにはカスタム関数まで指定して必要な要素を見つけることが可能です。
最後に、Beautiful Soupには出力整形機能も豊富で、見やすい形式での出力、エンコード、マイクロソフトのスマートクォート除去、さらにはHTMLのパースと検証まで行えます。
速度
Scrapyとは異なり、RequestsとBeautiful Soupにはオーバーヘッドがなく、単純に10回実行するだけで速度を評価できます。
まず、必要なライブラリをロードします:
import requests, json
from bs4 import BeautifulSoup
次に、timeitマジックコマンドでコードを囲み時間を計測します:
%%timeit -n 10 -r 1
page = requests.get('https://edition.cnn.com')
page_html = BeautifulSoup(page.text, 'html.parser')
page_html = page_html.select_one('h2.container_lead-package__title_url-text').text
json_object = json.dumps({'output': page_html})
with open("bs4_output.json", "w") as output_file:
output_file.write(json_object)
1回の実行には約300ミリ秒かかる。10回実行すると3,000ミリ秒かかり、Scrapyよりかなり遅い。しかし、設定が大幅に少なく、特定のフレームワークに関する知識も比較的少なくて済む。
Beautiful Soupによる多段階スクレイピング
Beautiful Soupにはクローリング機能がないため、動的ウェブページを直接処理することはできません。しかしScrapyと同様に、Playwright、Puppeteer、Seleniumなどの自動化ツールと連携することで完全に機能します。自動化ツールとBeautiful Soupの組み合わせは常に同じ方式で動作します:ヘッドレスブラウザが動的要素を処理し、Beautiful Soupがそれらのブラウザ内でレンダリングされたデータを抽出するのです。
Beautiful SoupによるローテーションプロキシとCAPTCHA対策
Beautiful Soupはスクレイピングツールでありクロールツールではないため、ウェブサイトのサーバーによるブロックを防止する機能は提供していません。この機能が必要な場合は、選択するクロールツールに組み込まれている必要があります。
結論
本稿では、Beautiful SoupとScrapyがウェブクローリングおよびウェブスクレイピングにおいて、速度、動的ウェブ文書の処理、反スクレイピング対策の回避という観点でどのように使い勝手が異なるかを概説しました。
エンドツーエンドのツールとして、日常的なスクレイピング作業にはScrapyが明らかに優れています。ただし、動的ウェブサイトのスクレイピングやブロック回避には、いくつかのミドルウェアが必要です。
Beautiful Soup(requestパッケージと併用)は処理速度が遅いものの、臨時のスクレイピング作業には非常に親しみやすくシンプルな方法を提供します。Scrapyと同様に、動的ウェブサイトのスクレイピングやブロック回避には追加ツールが必要です。
ウェブスクレイピングのワンストップソリューションをお探しなら、Bright Dataをご検討ください。Bright Dataはプロキシサービスや Web Unlockerなど、あらゆるウェブスクレイピングニーズに対応する多様な製品を提供しており、どのオプションを選択してもサポートします。
Bright Dataプロキシの統合方法に興味がありますか?Scrapyプロキシ統合ガイドとBeautifulSoupプロキシガイドをご覧ください。