【Python】HTMLの海から宝探し!Beautiful Soup 4 (bs4) でWebスクレイピング入門 🕵️‍♀️

【Python】HTMLの海から宝探し!Beautiful Soup 4 (bs4) でWebスクレイピング入門 🕵️‍♀️

RequestsでWebページの内容は取ってこられたけど、この大量のHTMLタグの中から欲しい情報だけ抜き出すのはどうすれば…?」

こんにちは! 前回のRequestsライブラリの解説に続き、今回はその相棒とも言える強力なライブラリ、Beautiful Soup 4 (bs4) をご紹介します。bs4を使えば、まるで魔法のようにHTMLやXMLの構造を解析し、目的のデータをピンポイントで抽出することができるようになります。

この記事では、bs4のインストールから基本的な使い方まで、サンプルコードを交えながら分かりやすく解説していきます。Requestsbs4を組み合わせれば、Webスクレイピングの世界がぐっと広がりますよ!


1. Beautiful Soup 4 (bs4) とは?

Beautiful Soup 4 (bs4) は、HTMLやXMLといったマークアップ言語のドキュメントを解析するためのPythonライブラリです。Requestsで取得したWebページ全体のHTML文字列は、そのままではただの長いテキストデータに過ぎません。bs4は、このテキストデータをタグの階層構造として理解し、特定のタグや属性、テキスト情報などを簡単に取り出せるようにしてくれます。

なぜRequestsとセットで使われるの?

  • Requests: Webサーバーと通信して、HTMLなどのデータを「取ってくる」役割。
  • Beautiful Soup 4: Requestsが取ってきたHTMLデータの中から、必要な情報を「探し出して抜き出す」役割。

この二つを組み合わせることで、Webスクレイピングの基本的な流れ(データ取得→データ抽出)が完成します。


2. Beautiful Soup 4 のインストール

まずは、bs4ライブラリをインストールしましょう。
ターミナル(コマンドプロンプトやPowerShell、ターミナル.appなど)で以下のコマンドを実行します。

pip install beautifulsoup4



これだけでbs4本体のインストールは完了です。

パーサーについて (最初は気にしなくてOK)
bs4はHTMLを解析する際に「パーサー」と呼ばれる別のライブラリを利用します。Pythonの標準ライブラリであるhtml.parserがデフォルトで使われるので、通常は追加のインストールは不要です。
(より高速なlxmlhtml5libといったパーサーもありますが、まずは標準のhtml.parserで始めてみましょう。)


3. 基本的な使い方:HTMLから情報を抜き出す

それでは、実際にbs4を使ってHTMLから情報を抽出してみましょう。

3.1. サンプルHTMLの準備

練習のために、まずは簡単なHTMLを用意します。
以下のHTMLをsample.htmlという名前で、Pythonスクリプトと同じディレクトリに保存してみてください。

<!DOCTYPE html>
<html>
<head>
    <title>テストページ</title>
</head>
<body>
    <h1 id="main-title">こんにちは、Beautiful Soup!</h1>
    <p class="content">これは最初の段落です。</p>
    <p class="content important">これは重要な情報を含む2番目の段落です。</p>
    <div>
        <a href="https://www.example.com/page1">リンク1</a>
        <a href="https://www.example.com/page2">リンク2 (特集)</a>
    </div>
    <img src="image.jpg" alt="サンプル画像">
</body>
</html>

今回はこのローカルHTMLファイルを読み込んで解析しますが、実際にはRequestsで取得したWebページのHTML文字列を解析することになります。

3.2. BeautifulSoupオブジェクトの作成

まず、bs4をインポートし、HTMLコンテンツを読み込んでBeautifulSoupオブジェクトを作成します。

サンプルコード (Python):

from bs4 import BeautifulSoup

# sample.htmlファイルを読み込む (実際にはRequestsで取得したHTML文字列)
with open("sample.html", "r", encoding="utf-8") as f:
    html_content = f.read()

# BeautifulSoupオブジェクトを作成 (パーサーには'html.parser'を指定)
soup = BeautifulSoup(html_content, "html.parser")

# オブジェクトのタイプを確認してみる
print(type(soup))

解説:

  1. from bs4 import BeautifulSoup でライブラリからBeautifulSoupクラスをインポートします。
  2. ここではローカルのHTMLファイルを読み込んでいますが、Requestsを使う場合は response = requests.get(url) の後、 html_content = response.text となります。
  3. BeautifulSoup(html_content, "html.parser") で、HTMLコンテンツと使用するパーサーを指定してsoupオブジェクトを作成します。このsoupオブジェクトを通してHTMLの各要素にアクセスしていきます。

3.3. タグ名で要素を取得する

最初の1つの要素を取得: soup.find('タグ名')

# 最初の<h1>タグを取得
h1_tag = soup.find('h1')
if h1_tag:
    print(f"h1タグの内容: {h1_tag.text}") # .textでタグ内のテキストを取得

# 最初の<p>タグを取得
p_tag = soup.find('p')
if p_tag:
    print(f"最初のpタグの内容: {p_tag.text}")

実行結果 (例):

h1タグの内容: こんにちは、Beautiful Soup!
最初のpタグの内容: これは最初の段落です。

すべての要素を取得: soup.find_all('タグ名')

# 全ての<p>タグを取得 (リストで返ってくる)
all_p_tags = soup.find_all('p')
print(f"\n見つかったpタグの数: {len(all_p_tags)}")
for p_tag in all_p_tags:
    print(f"- pタグの内容: {p_tag.text}")

実行結果 (例):

見つかったpタグの数: 2
- pタグの内容: これは最初の段落です。
- pタグの内容: これは重要な情報を含む2番目の段落です。

3.4. 属性を使って要素を取得する

find()find_all()メソッドの第2引数に辞書形式で属性を指定することで、特定の属性を持つタグを絞り込めます。

# id属性が "main-title" のタグを取得
title_tag = soup.find(id="main-title")
if title_tag:
    print(f"\nIDがmain-titleのタグの内容: {title_tag.text}")

# class属性が "content" のタグを全て取得
content_tags = soup.find_all(class_="content") # classはPythonの予約語なのでclass_と書く
print(f"classがcontentのタグの数: {len(content_tags)}")
for tag in content_tags:
    # classが複数ある場合も考慮 (ここでは .text を使う)
    print(f"- class content: {tag.text}")

# class属性が "content important" のタグを取得 (複数のクラスを持つ場合)
important_content_tag = soup.find(class_="important content") # 順不同でもOKな場合が多い
if important_content_tag:
    print(f"classがimportant contentのタグ: {important_content_tag.text}")

実行結果 (例):

IDがmain-titleのタグの内容: こんにちは、Beautiful Soup!
classがcontentのタグの数: 2
- class content: これは最初の段落です。
- class content: これは重要な情報を含む2番目の段落です。
classがimportant contentのタグ: これは重要な情報を含む2番目の段落です。

3.5. タグの属性値を取得する

取得したタグオブジェクトから、そのタグが持つ属性の値を辞書のようにアクセスできます。

# 最初の<a>タグを取得
first_a_tag = soup.find('a')
if first_a_tag:
    print(f"\n最初のaタグのhref属性: {first_a_tag['href']}")
    print(f"最初のaタグのテキスト: {first_a_tag.text}")

# <img>タグのsrc属性とalt属性を取得
img_tag = soup.find('img')
if img_tag:
    print(f"imgタグのsrc属性: {img_tag['src']}")
    print(f"imgタグのalt属性: {img_tag.get('alt')}") # .get()を使うと属性が無くてもエラーにならない

実行結果 (例):

最初のaタグのhref属性: https://www.example.com/page1
最初のaタグのテキスト: リンク1
imgタグのsrc属性: image.jpg
imgタグのalt属性: サンプル画像

3.6. CSSセレクタで要素を取得する (超便利!)

CSSセレクタは、Webページのスタイルを指定する際に使われる記法ですが、bs4ではこのセレクタを使って要素を柔軟に指定できます。個人的には一番よく使う方法です。

  • 最初の1つの要素: soup.select_one('CSSセレクタ')
  • 全てのマッチする要素: soup.select('CSSセレクタ') (リストで返ってくる)
# IDで選択
title_by_css = soup.select_one('#main-title')
if title_by_css:
    print(f"\nCSSセレクタ (ID) で取得: {title_by_css.text}")

# クラス名で選択 (ドット . を使う)
contents_by_css = soup.select('.content')
print(f"CSSセレクタ (クラス) で取得した数: {len(contents_by_css)}")
for item in contents_by_css:
    print(f"- {item.text}")

# タグ名で選択
all_links_by_css = soup.select('a')
print(f"CSSセレクタ (タグ名a) で取得した数: {len(all_links_by_css)}")
for link in all_links_by_css:
    print(f"- リンクテキスト: {link.text}, URL: {link['href']}")

# 子孫要素の選択 (div の中の a タグ)
div_links = soup.select('div a')
print(f"CSSセレクタ (divの子孫のa) で取得した数: {len(div_links)}")

実行結果 (例):

CSSセレクタ (ID) で取得: こんにちは、Beautiful Soup!
CSSセレクタ (クラス) で取得した数: 2
- これは最初の段落です。
- これは重要な情報を含む2番目の段落です。
CSSセレクタ (タグ名a) で取得した数: 2
- リンクテキスト: リンク1, URL: https://www.example.com/page1
- リンクテキスト: リンク2 (特集), URL: https://www.example.com/page2
CSSセレクタ (divの子孫のa) で取得した数: 2

CSSセレクタには様々な指定方法があり、非常に強力です。ぜひ調べてみてください!


4. RequestsBeautiful Soup 4 を組み合わせた例

では、RequestsでWebページを取得し、bs4でその中から特定の情報を抜き出す、という一連の流れを見てみましょう。
ここでは、https://httpbin.org/html というシンプルなHTMLを返すテスト用URLを使います。

import requests
from bs4 import BeautifulSoup

url = "https://httpbin.org/html" # シンプルなHTMLを返すテスト用URL

try:
    response = requests.get(url)
    response.raise_for_status() # ステータスコードが200番台以外なら例外を発生

    # BeautifulSoupオブジェクトを作成
    soup = BeautifulSoup(response.text, "html.parser")

    # <h1>タグの内容を取得
    h1_tag = soup.find('h1')
    if h1_tag:
        print(f"ページタイトル (h1): {h1_tag.text}")
    else:
        print("h1タグが見つかりませんでした。")

    # 全ての<p>タグの内容を取得
    print("\n段落の内容:")
    all_p_tags = soup.find_all('p')
    if all_p_tags:
        for p_tag in all_p_tags:
            print(f"- {p_tag.text.strip()}") # strip()で前後の空白を除去
    else:
        print("pタグが見つかりませんでした。")

except requests.exceptions.RequestException as e:
    print(f"リクエスト中にエラーが発生しました: {e}")
except Exception as e:
    print(f"その他のエラー: {e}")

実行結果 (例 - httpbin.org/htmlの内容による):

ページタイトル (h1): Herman Melville - Moby Dick
段落の内容:
- Or, The Whale
- Praesent dapibus, neque id cursus faucibus, tortor neque egestas augue, eu vulputate magna eros eu erat. Aliquam erat volutpat. Nam dui mi, tincidunt quis, accumsan porttitor, facilisis luctus, metus.
... (他のpタグの内容) ...

5. Webスクレイピングを行う上での注意点

Webスクレイピングは非常に強力な技術ですが、行う際には以下の点に注意しましょう。

  • サイトの利用規約を確認する: スクレイピングを禁止しているサイトもあります。必ず利用規約を確認しましょう。
  • robots.txtを確認する: サイトのルートディレクトリにあるrobots.txtファイルには、クローラー(プログラムによるアクセス)に対する許可/不許可のルールが書かれています。尊重しましょう。
  • サーバーに負荷をかけすぎない: 短時間に大量のリクエストを送ると、相手のサーバーに大きな負荷をかけてしまいます。time.sleep() などを使って、アクセス間隔を適切に空けましょう。
  • 取得した情報の取り扱いに注意: 著作権や個人情報などに配慮し、法律やマナーを守って利用しましょう。
  • 動的なWebサイトについて: JavaScriptによって後から内容が読み込まれるような「動的なWebサイト」の場合、Requestsbs4だけではうまく情報を取得できないことがあります。そのような場合はSeleniumなどのツールが必要になりますが、これはまた別のお話です。

練習や学習目的であれば、まずは自分で作成したHTMLファイルや、スクレイピングを許可しているテスト用のサイトを利用するのが安全です。


まとめ:bs4でHTML解析の第一歩を踏み出そう!

今回は、Beautiful Soup 4 (bs4)を使ってHTMLから情報を抽出する基本的な方法を解説しました。

  • BeautifulSoupオブジェクトの作成
  • タグ名、属性、CSSセレクタを使った要素の検索と取得
  • タグ内のテキストや属性値の取得
  • Requestsとの連携例

bs4を使いこなせるようになると、Web上の膨大な情報の中から必要なデータを効率的に集めることができるようになります。最初は戸惑うかもしれませんが、色々なHTMLを解析してみることで、すぐに慣れてくるはずです。

ぜひ、Requestsbs4をあなたの強力な武器として、Webスクレイピングの世界を楽しんでください!

その他の投稿はこちら

コメント

このブログの人気の投稿

タイトルまとめ

これで迷わない!WindowsでPython環境構築する一番やさしい方法 #0

【Python標準ライブラリ完結!】11の冒険をありがとう!君のPython力が飛躍する「次の一歩」とは? 🚀