第31回「スクレイピング(3)」BeautifulSoupを使うときの基本パターン

こんにちは、小澤です。

前回は、HTMLの構造とBeautifulSoupの役割を整理しました。スクレイピングは「画面を読む」のではなく、HTMLという構造データを読み解く作業であることも確認しました。

今回は、その続きとして、BeautifulSoupを実際に使いこなすための基本パターンを整理しながら、実際のプログラムの書き方を紹介したいと思います。整理する点は以下です。

  • BeautifulSoupを使うときの基本テンプレート
  • find と find_all の使い分け
  • class や id を使った絞り込み
  • 複数要素を扱うときの考え方
  • よくあるエラーと対処法

教科書『Pythonによる新しいデータ分析の教科書(第2版)』では「スクレイピング」(274ページ〜284ページ)の続きにあたる部分です。

BeautifulSoupを使う基本テンプレート

まずは、BeautifulSoupの基本的な使い方です。

import requests
from bs4 import BeautifulSoup

url = “<https://example.com>”
response = requests.get(url)
response.raise_for_status()

soup = BeautifulSoup(response.text, “html.parser”)

スクレイピングをするときは、このような書き方になります。

  • requestsでページを取得
  • response.text でHTMLを取り出す
  • BeautifulSoupで解析する

find と find_all の使い分け

BeautifulSoupで最もよく使うのが、find() と find_all() です。

find() は、条件に一致する最初の要素を1つだけ返します。ページに1つしか存在しないと分かっている要素、たとえばページタイトルなどを取得する場合に向いています。

title = soup.find(“h1”)
print(title.text)

一方、find_all() は、条件に一致する要素をすべてリストで返すものです。ニュース一覧や商品一覧のように、同じ構造が繰り返されているページで使います。一覧ページは find_all と覚えておくとよいでしょう。

items = soup.find_all(“a”)

for item in items:
    print(item.text)

class や id を指定して絞り込む

タグ名だけでは不十分なことが多く、実際には class や id を使って要素を絞り込みます。ここで注意したいのは、class ではなく 「class_」と書く点です。これは、class がPythonの予約語であるためです。

items = soup.find_all(“div”, class_=”item”)

また、id を指定する場合は次のように書きます。

main = soup.find(“div”, id=”main-content”)

HTML構造を確認しながら、どのタグに、どのclassやidが付いているかを見極めることが重要です。

ブロック単位で処理する

実際のスクレイピングでは、1つのまとまりを単位として処理することが多くなります。たとえば、次のようなHTMLがあったとします。

<div class=”item”>
  <h2>商品A</h2>
  <span class=”price”>1000円</span>
</div>

この場合、まず item というブロックをすべて取得し、その中をさらに探します。

items = soup.find_all(“div”, class_=”item”)

for item in items:
    name = item.find(“h2”).text.strip()
    price = item.find(“span”, class_=”price”).text.strip()
    print(name, price)

ポイントは、先に「まとまり」を取得し、その中を探す、という流れです。ページ全体から毎回検索するよりも、構造に沿った自然な処理になります。

よくあるエラーと対処

スクレイピングでよくあるエラーの一つが、「NoneTypeエラー」です。

price = soup.find(“span”, class_=”price”)
print(price.text)

この場合、もし該当する要素が存在しなければ、price は None になります。その状態で .text を呼び出すとエラーになります。エラーを発生させないように書くには、次のようにします。

price = soup.find(“span”, class_=”price”)
if price:
    print(price.text.strip())

また、思ったように取得できない場合は、以下のようにすると、HTML構造を整形表示し、実際の構造を確認すると原因が見つかりやすくなります。

print(soup.prettify())

今回のまとめ

今回は、BeautifulSoupを実際に使うための基本パターンについて整理しました。ポイントは次のとおりです。

  • スクレイピングの基本形はテンプレート化できる
  • find は1件、find_all は複数取得
  • class_ や id を使って絞り込む
  • ブロック単位で処理する
  • Noneチェックを忘れない

BeautifulSoup は多機能なライブラリですが、実際に使うときのパターンはある程度決まっています。今回紹介した方法を使うと、多くの一覧ページや情報抽出に対応できるようになります。

次回は、この流れをさらに発展させて、複数ページの自動巡回(ページネーション)に取り組んでみましょう。ページをまたいで情報を取得できるようになると、スクレイピングの実用性が一段と高まると思います。次回もお楽しみに。

Related post

  1. 初学者向けIPv6解説コラム第3回「IPv6アドレスの表記方法と…
  2. 初学者向けIPv6解説コラム第4回「IPv6ヘッダの各フィールド…
  3. 第9 回「近隣探索プロトコル(2)ルータとプレフィックス情報の発…
  4. 初学者向けIPv6解説コラム第一回「IPv6、IPアドレスの構成…
  5. 第8 回「近隣探索プロトコル(1)」
  6. 第42回「Pythonとネットワーク自動化基礎検定 模擬問題解説…
  7. 第10 回「近隣探索プロトコル(3)リンク層アドレスの解決と近隣…
  8. 初学者向けIPv6解説コラム第5回「IPv6拡張ヘッダ」

最近の記事

PAGE TOP