【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
のインストールから基本的な使い方まで、サンプルコードを交えながら分かりやすく解説していきます。Requests
とbs4
を組み合わせれば、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
がデフォルトで使われるので、通常は追加のインストールは不要です。
(より高速なlxml
やhtml5lib
といったパーサーもありますが、まずは標準の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))
解説:
from bs4 import BeautifulSoup
でライブラリからBeautifulSoup
クラスをインポートします。- ここではローカルのHTMLファイルを読み込んでいますが、
Requests
を使う場合はresponse = requests.get(url)
の後、html_content = response.text
となります。 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. Requests
と Beautiful 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サイト」の場合、
Requests
とbs4
だけではうまく情報を取得できないことがあります。そのような場合はSeleniumなどのツールが必要になりますが、これはまた別のお話です。
練習や学習目的であれば、まずは自分で作成したHTMLファイルや、スクレイピングを許可しているテスト用のサイトを利用するのが安全です。
まとめ:bs4でHTML解析の第一歩を踏み出そう!
今回は、Beautiful Soup 4 (bs4)
を使ってHTMLから情報を抽出する基本的な方法を解説しました。
BeautifulSoup
オブジェクトの作成- タグ名、属性、CSSセレクタを使った要素の検索と取得
- タグ内のテキストや属性値の取得
Requests
との連携例
bs4
を使いこなせるようになると、Web上の膨大な情報の中から必要なデータを効率的に集めることができるようになります。最初は戸惑うかもしれませんが、色々なHTMLを解析してみることで、すぐに慣れてくるはずです。
ぜひ、Requests
とbs4
をあなたの強力な武器として、Webスクレイピングの世界を楽しんでください!
コメント
コメントを投稿