基礎から学ぶPython入門 90日コース | Web・API - Day 52:Beautiful Soup

Python 90日で身につけるPython
スポンサーリンク
スポンサーリンク

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")
Python

find_all() は、

  • タグ名
  • 属性条件(後述)

などを指定して、複数の要素をまとめて取得するときに使います。

CSSセレクタ:ブラウザと同じ「指定の仕方」で要素を探す

CSSセレクタとは

CSSセレクタは、 ブラウザでスタイルを当てるときに使う「要素の指定方法」です。

例えば:

  • p.leadclass="lead" を持つ <p> タグ
  • #contentid="content" の要素
  • div.article > h2div.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で扱う」世界に、 ぐっと踏み込みやすくなっていきます。

タイトルとURLをコピーしました