Day 52:Beautiful Soup ― HTMLを「読み解く」ためのやさしい道具
Day 52では、WebページのHTMLから欲しい情報だけを抜き出すための定番ライブラリ Beautiful Soup を使っていきます。
テーマは次の4つです。
- HTML取得
- 要素検索
- CSSセレクタ
- テキスト抽出
「ブラウザで見ているページの裏側(HTML)」を、 Pythonでそっとのぞき込んで、必要なところだけすくい取るイメージで進めていきます。
Beautiful Soupとは:HTMLを「扱いやすい形」にしてくれるライブラリ
役割のイメージ
Beautiful Soupは、ざっくり言うと、
「生のHTML文字列を、Pythonから扱いやすいオブジェクトに変換してくれる道具」
です。
- タグごとにアクセスできる
- 属性で絞り込みできる
- CSSセレクタで検索できる
- テキストだけ取り出せる
といった操作を、直感的なメソッドで書けるようになります。
インストールは一度だけ、次のように行います。
bash
pip install beautifulsoup4
HTML取得:まずはページの中身を「文字列」として手に入れる
requestsと組み合わせるのが定番
Beautiful Soupは「HTMLを解析する」ライブラリなので、 HTMLそのものは別の手段で取得する必要があります。
よく使われるのが requests との組み合わせです。
# day52_html_fetch.py
import requests # WebページのHTMLを取得するために使います。
from bs4 import BeautifulSoup # HTMLを解析するためのライブラリです。
def fetch_html(url: str) -> str | None:
"""指定したURLからHTMLを取得する関数です。"""
print(f"[GET] {url} にアクセスします。")
try:
response = requests.get(url, timeout=5)
except requests.exceptions.RequestException as e:
print("HTML取得中にエラーが発生しました:", e)
return None
if 200 <= response.status_code < 300:
# レスポンス本文(HTML)をそのまま返します。
return response.text
else:
print("HTMLの取得に失敗しました。ステータスコード:", response.status_code)
return None
def main():
url = "https://httpbin.org/html" # 練習用にHTMLを返してくれるURLです。
html = fetch_html(url)
if html is not None:
print("取得したHTMLの先頭100文字:")
print(html[:100])
if __name__ == "__main__":
main()
Pythonここではまだ「HTML文字列」を手に入れただけですが、 次のステップでこれをBeautiful Soupに渡して「解析可能な形」にしていきます。
要素検索:タグや属性で「欲しい場所」を探す
Beautiful SoupでHTMLを「スープ」にする
まずは、取得したHTMLをBeautiful Soupに渡して、 DOM構造として扱えるようにします。
# day52_bs_basic_find.py
import requests
from bs4 import BeautifulSoup
def parse_html_with_bs(url: str):
"""Beautiful SoupでHTMLを解析し、要素を検索する基本例です。"""
response = requests.get(url, timeout=5)
# レスポンス本文(HTML)を取り出します。
html = response.text
# BeautifulSoup に HTML文字列とパーサーの種類を渡します。
# "html.parser" は標準のHTMLパーサーです。
soup = BeautifulSoup(html, "html.parser")
# 例として、最初の <h1> 要素を探してみます。
h1_tag = soup.find("h1") # タグ名で検索します。
if h1_tag is not None:
print("<h1> タグが見つかりました。中身のテキスト:")
print(h1_tag.get_text())
else:
print("<h1> タグは見つかりませんでした。")
if __name__ == "__main__":
parse_html_with_bs("https://httpbin.org/html")
Pythonここでのポイントは:
BeautifulSoup(html, "html.parser")で「スープ」を作ることsoup.find("タグ名")で、最初に見つかった要素を取得できることget_text()で、その要素のテキストだけを取り出せること
です。
複数要素をまとめて取得する
複数の要素を一度に取りたいときは、find_all() を使います。
# day52_bs_find_all.py
import requests
from bs4 import BeautifulSoup
def find_all_paragraphs(url: str):
"""すべての <p> 要素を取得して一覧表示する例です。"""
response = requests.get(url, timeout=5)
soup = BeautifulSoup(response.text, "html.parser")
# すべての <p> タグをリストとして取得します。
p_tags = soup.find_all("p")
print(f"<p> タグの数: {len(p_tags)}")
for i, p in enumerate(p_tags, start=1):
print(f"[{i}] {p.get_text()}")
if __name__ == "__main__":
find_all_paragraphs("https://httpbin.org/html")
Pythonfind_all() は、
- タグ名
- 属性条件(後述)
などを指定して、複数の要素をまとめて取得するときに使います。
CSSセレクタ:ブラウザと同じ「指定の仕方」で要素を探す
CSSセレクタとは
CSSセレクタは、 ブラウザでスタイルを当てるときに使う「要素の指定方法」です。
例えば:
p.lead→class="lead"を持つ<p>タグ#content→id="content"の要素div.article > h2→div.articleの直下にある<h2>
などがあります。
Beautiful Soupは、このCSSセレクタを使って要素検索ができるので、 「ブラウザでの指定」と「Pythonでの指定」を揃えやすいのが便利なポイントです。
select() でCSSセレクタ検索をする例
# day52_bs_css_select.py
import requests
from bs4 import BeautifulSoup
def css_select_example(html: str):
"""CSSセレクタで要素を検索する例です。"""
soup = BeautifulSoup(html, "html.parser")
# 例として、class="lead" の <p> を探します。
lead_paragraphs = soup.select("p.lead") # CSSセレクタで指定します。
print(f"class='lead' の <p> タグの数: {len(lead_paragraphs)}")
for i, p in enumerate(lead_paragraphs, start=1):
print(f"[lead {i}] {p.get_text()}")
def main():
# Day 51で使ったようなサンプルHTMLをそのまま文字列として用意します。
html = """
<!DOCTYPE html>
<html>
<head>
<title>サンプルページ</title>
</head>
<body>
<h1>ページタイトル</h1>
<p class="lead">これはリード文です。</p>
<div id="content">
<p>本文の1行目です。</p>
<p>本文の2行目です。</p>
</div>
</body>
</html>
"""
css_select_example(html)
if __name__ == "__main__":
main()
Pythonポイント:
soup.select("CSSセレクタ")で、条件に合う要素をリストで取得できます。p.leadや#contentなど、ブラウザで見慣れた指定方法がそのまま使えます。
テキスト抽出:タグの中身だけを「きれいに」取り出す
get_text() でタグの中のテキストを取得
Beautiful Soupでは、 タグオブジェクトに対して get_text() を呼ぶことで、 その中に含まれるテキストだけを取り出すことができます。
# day52_bs_text_extract.py
import requests
from bs4 import BeautifulSoup
def extract_text_example(url: str):
"""特定の要素からテキストだけを抽出する例です。"""
response = requests.get(url, timeout=5)
soup = BeautifulSoup(response.text, "html.parser")
# 例として、最初の <h1> とすべての <p> からテキストを抽出します。
h1_tag = soup.find("h1")
if h1_tag is not None:
print("ページタイトル(<h1>):")
print(h1_tag.get_text())
p_tags = soup.find_all("p")
print("\n本文(<p>)一覧:")
for i, p in enumerate(p_tags, start=1):
# strip=True を付けると、前後の余計な空白を取り除いてくれます。
text = p.get_text(strip=True)
print(f"[{i}] {text}")
if __name__ == "__main__":
extract_text_example("https://httpbin.org/html")
Pythonポイント:
get_text()は、タグの中にあるテキストをまとめて取得します。strip=Trueを付けると、前後の改行や空白をきれいに整えてくれます。
Day 52ミニテンプレート:HTML取得〜要素検索〜テキスト抽出まで一気通し
最後に、Day 52の内容をひとつにまとめた 「シンプルなWebページ解析ツール」テンプレート を紹介します。
# day52_bs_web_scraper_template.py
import requests
from bs4 import BeautifulSoup
def fetch_html(url: str) -> str | None:
"""指定URLからHTMLを取得する関数です。"""
print(f"[GET] {url} にアクセスします。")
try:
response = requests.get(url, timeout=5)
except requests.exceptions.RequestException as e:
print("HTML取得中にエラーが発生しました:", e)
return None
if 200 <= response.status_code < 300:
return response.text
else:
print("HTMLの取得に失敗しました。ステータスコード:", response.status_code)
return None
def parse_and_extract(html: str):
"""HTMLを解析して、タイトルと本文を抽出する例です。"""
# Beautiful Soup でHTMLを解析します。
soup = BeautifulSoup(html, "html.parser")
# 1. ページタイトル(<h1>)を取得
h1_tag = soup.find("h1")
if h1_tag is not None:
print("ページタイトル:")
print(h1_tag.get_text(strip=True))
else:
print("<h1> タグが見つかりませんでした。")
# 2. リード文(p.lead)をCSSセレクタで取得
lead_paragraphs = soup.select("p.lead")
if lead_paragraphs:
print("\nリード文:")
for p in lead_paragraphs:
print(p.get_text(strip=True))
else:
print("\nリード文(p.lead)は見つかりませんでした。")
# 3. 本文(#content 内の <p>)をCSSセレクタで取得
content_paragraphs = soup.select("#content p")
if content_paragraphs:
print("\n本文:")
for i, p in enumerate(content_paragraphs, start=1):
print(f"[{i}] {p.get_text(strip=True))
else:
print("\n本文(#content 内の <p>)は見つかりませんでした。")
def main():
# サンプルHTMLをそのまま使う場合
sample_html = """
<!DOCTYPE html>
<html>
<head>
<title>サンプルページ</title>
</head>
<body>
<h1>ページタイトル</h1>
<p class="lead">これはリード文です。</p>
<div id="content">
<p>本文の1行目です。</p>
<p>本文の2行目です。</p>
</div>
</body>
</html>
"""
print("=== ローカルHTMLの解析 ===")
parse_and_extract(sample_html)
# 実際のWebページを解析する場合(練習用)
url = "https://httpbin.org/html"
html = fetch_html(url)
if html is not None:
print("\n=== 実際のWebページの解析 ===")
parse_and_extract(html)
if __name__ == "__main__":
main()
Pythonこのテンプレートは、
- HTML取得(requests)
- Beautiful Soupによる解析
- 要素検索(find / select)
- テキスト抽出(get_text)
をひと通り体験できる「ミニスクレイピングツール」になっています。
Day 52のまとめ
Day 52では、Beautiful Soupを使ったHTML解析として、
- Beautiful Soupは「HTMLを扱いやすいオブジェクトに変換する」ためのライブラリであること
- requestsと組み合わせて、まずHTML文字列を取得する流れが基本であること
find/find_allでタグ名や属性を指定して要素検索ができることselectでCSSセレクタを使った柔軟な検索ができることget_text()でタグの中身のテキストだけをきれいに取り出せること
を、コード例とともに整理しました。
この土台があると、
- ニュースサイトから記事タイトルだけを集める
- ECサイトから商品名と価格を一覧にする
- 社内のHTMLレポートから必要な数値だけ抜き出す
といった「WebデータをPythonで扱う」世界に、 ぐっと踏み込みやすくなっていきます。
