表形式データの抽出と Pandas への変換 ― Beautiful Soup 応用ガイド

1. 全体像

  1. HTML テーブルの特定
    CSS セレクタや属性検索で <table> 要素を取得します。ページに複数テーブルがある場合は、idclass でフィルタリングすると意図した表だけを対象にできます。

  2. ヘッダー解析
    <th> タグから列名を取得します。rowspancolspan がある場合はツリー構造をたどって論理的ヘッダーを構築します。

  3. ボディ行の走査
    <tr><td> の順に値を抽出し、ネストしたタグ(<a> など)があれば .get_text(strip=True) でテキストだけを取り出します。

  4. Python リスト/辞書に整形
    1 行=1 レコードのリストや辞書リストを作成し、欠損セルには None を挿入。

  5. Pandas DataFrame へ変換
    pd.DataFrame(records, columns=headers) で即座に表形式データを扱えるようになります。

  6. 後処理
    型変換・欠損値補完・重複除去・列名正規化などを行い、CSV や DB に保存します。


2. 具体的なコード例

python
from bs4 import BeautifulSoup import pandas as pd import requests url = "https://example.com/report.html" html = requests.get(url, timeout=10).text soup = BeautifulSoup(html, "lxml") # 1) 対象テーブル取得(例: class='sales') table = soup.find("table", class_="sales") # 2) ヘッダー抽出 headers = [th.get_text(strip=True) for th in table.find_all("tr")[0].find_all("th")] # 3) 行データ抽出 records = [] for row in table.find_all("tr")[1:]: # ヘッダー以降 cells = [td.get_text(strip=True) for td in row.find_all("td")] if not cells: # 空行を除外 continue # colspan/欠損調整 while len(cells) < len(headers): cells.append(None) records.append(cells) # 4) DataFrame 化 df = pd.DataFrame(records, columns=headers) # 5) 型変換例 numeric_cols = ["売上", "利益"] df[numeric_cols] = df[numeric_cols].apply(pd.to_numeric, errors="coerce") print(df.head())

ポイント補足

課題 解決策
<th> が複数行にまたがる複合ヘッダー pandas.read_html()header=[0,1] とするか、Beautiful Soup で各 <th>rowspancolspan を再帰的に展開してフラット化
セルに改行・空白が多い get_text(" ", strip=True) の第1引数に区切り文字を指定し、改行をスペース1つへ統一
画像・アイコンが埋め込まれている <img>alt 属性を取得するか、['src'] をダウンロード URL として扱う
数値にカンマが含まれる str.replace(",", "")pd.to_numeric()
日付文字列の統一 pd.to_datetime(df["日付列"], format="%Y/%m/%d") などで ISO 形式へ正規化

3. pandas.read_html() と組み合わせる場合

  • 単純な表: df_list = pd.read_html(url, flavor="bs4", match="売上表") で Beautiful Soup パーサを内部利用しつつ自動 DataFrame 化。

  • 複雑な表: 先に Beautiful Soup で DOM を操作して不要列や広告行を削除後、pd.read_html(str(clean_table)) に渡すと手間を減らせます。


4. ベストプラクティス

実践的アドバイス 説明
テーブル検出ロジックは疎結合に soup.select("table.sales") のようにセレクタに依存しすぎない書き方にして、HTML 構造が変わっても影響範囲を限定。
構造変化テストを自動化 pytest + Beautiful Soup で「ヘッダー数が変わらないか」などをチェックし、サイト改修時の事故を減らす。
正規表現で数値抽出 re.sub("[^0-9.-]", "", cell) で通貨記号や単位を除去してから数値変換。
文字エンコーディング対策 response.encoding を確認し、response.apparent_encoding で推定結果も検証。Beautiful Soup の from_encoding 引数で強制指定可能。
パフォーマンス改善 テーブルが大きい場合、records.append ではなくリスト内包表記+pd.DataFrame.from_records を使うと高速。

5. まとめ

  • Beautiful Soup で テーブル構造を柔軟に解析 → 行列データを Python のリスト/辞書にマッピング → Pandas で高機能なデータ処理を実施、という分業が最も保守性と拡張性を両立します。

  • pandas.read_html() は便利ですが、複雑なヘッダー動的に生成されるセル を扱う際には Beautiful Soup との併用が必須です。

  • 型変換・欠損処理・エンコーディング管理・テスト自動化を早期に組み込み、将来の HTML 変更やデータ品質問題に強いスクレイピング基盤を構築しましょう。

ChatGPT4o 生成日:2025/06/19