PythonのPandasでWebページのHTMLテーブルを簡単スクレイピングする方法

WebページからHTMLのtableタグで構成された表データを取得したい場面は多くあります。PythonのPandasライブラリを使用すれば、わずか数行のコードでWebページの表データを簡単にスクレイピングできます。本記事では、Pandasを使った効率的なWebスクレイピング手法を詳しく解説します。

Pandasによる表スクレイピングの基本

必要なライブラリのインストール

まず、必要なライブラリをインストールします。

pip install pandas beautifulsoup4 lxml requests

基本的なスクレイピング方法

Pandasのread_html()関数を使用すると、WebページのHTMLテーブルを直接DataFrameとして取得できます。

import pandas as pd

# URLから直接テーブルを読み込み
url = "https://example.com/data.html"
tables = pd.read_html(url)

# 最初のテーブルを取得
df = tables[0]
print(df.head())

この方法では、指定したURLから全てのtableタグを自動的に検出し、それぞれをDataFrameのリストとして返します。

より詳細なスクレイピング手法

特定のテーブルを指定して取得

複数のテーブルが存在するページで、特定のテーブルのみを取得したい場合は以下のようにします。

import pandas as pd

# 特定の属性を持つテーブルを指定
url = "https://example.com/data.html"
tables = pd.read_html(url, attrs={'class': 'data-table'})

# またはテーブル内の特定文字列で絞り込み
tables = pd.read_html(url, match='売上データ')

df = tables[0]
print(df.info())

ヘッダー行の指定

テーブルのヘッダー行が複数行にわたる場合や、特定の行をヘッダーとして使用したい場合はheaderパラメータを使用します。

import pandas as pd

# 2行目をヘッダーとして使用
tables = pd.read_html(url, header=1)

# 複数行をヘッダーとして使用
tables = pd.read_html(url, header=[0, 1])

df = tables[0]
print(df.columns)

requestsとBeautifulSoupを組み合わせた高度な手法

セッション管理とカスタムヘッダー

ログインが必要なサイトや、特定のヘッダーが必要な場合はrequestsライブラリと組み合わせます。

import pandas as pd
import requests
from io import StringIO

# セッション作成
session = requests.Session()
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)'
}

# HTMLを取得
response = session.get(url, headers=headers)
html_content = response.text

# pandasでテーブルを解析
tables = pd.read_html(StringIO(html_content))
df = tables[0]

特定の要素内のテーブルを取得

BeautifulSoupを使って、特定のdivやセクション内のテーブルのみを取得することも可能です。

import pandas as pd
import requests
from bs4 import BeautifulSoup

# HTMLを取得
response = requests.get(url)
soup = BeautifulSoup(response.content, 'html.parser')

# 特定の親要素内のテーブルを取得
target_div = soup.find('div', {'class': 'content-area'})
tables = pd.read_html(str(target_div))

df = tables[0]

データクリーニングとエラーハンドリング

基本的なデータクリーニング

スクレイピングしたデータは、しばしばクリーニングが必要です。

import pandas as pd
import numpy as np

# テーブル取得
tables = pd.read_html(url)
df = tables[0]

# 欠損値の処理
df = df.dropna()  # 欠損値行を削除
# または
df = df.fillna(0)  # 欠損値を0で置換

# 数値列の型変換
df['売上'] = pd.to_numeric(df['売上'], errors='coerce')

# 不要な文字の除去
df['商品名'] = df['商品名'].str.replace('※', '')

エラーハンドリングの実装

ネットワークエラーや存在しないテーブルに対する適切な処理を行います。

import pandas as pd
import requests
from requests.exceptions import RequestException

def scrape_table(url, table_index=0):
    try:
        # タイムアウト設定
        tables = pd.read_html(url, timeout=10)
        
        if len(tables) <= table_index:
            print(f"テーブルが{table_index + 1}個未満です")
            return None
            
        return tables[table_index]
        
    except RequestException as e:
        print(f"ネットワークエラー: {e}")
        return None
    except ValueError as e:
        print(f"テーブルが見つかりません: {e}")
        return None

# 使用例
df = scrape_table(url)
if df is not None:
    print(df.head())

実践的な応用例

複数ページからのデータ統合

複数のページからテーブルデータを取得し、統合する例です。

import pandas as pd
import time

def scrape_multiple_pages(base_url, pages):
    all_data = []
    
    for page in range(1, pages + 1):
        url = f"{base_url}?page={page}"
        
        try:
            tables = pd.read_html(url)
            df = tables[0]
            df['ページ'] = page
            all_data.append(df)
            
            # サーバーへの負荷軽減
            time.sleep(1)
            
        except Exception as e:
            print(f"ページ{page}でエラー: {e}")
            continue
    
    # 全データを統合
    combined_df = pd.concat(all_data, ignore_index=True)
    return combined_df

# 使用例
df = scrape_multiple_pages("https://example.com/data", 5)

動的なテーブルの取得

JavaScriptで動的に生成されるテーブルの場合は、Seleniumとの組み合わせが必要です。

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
import pandas as pd
import time

# ヘッドレスモードでブラウザ起動
options = Options()
options.add_argument('--headless')
driver = webdriver.Chrome(options=options)

try:
    driver.get(url)
    
    # JavaScriptの実行完了を待機
    time.sleep(3)
    
    # ページソースを取得
    html = driver.page_source
    
    # pandasでテーブル解析
    tables = pd.read_html(html)
    df = tables[0]
    
finally:
    driver.quit()

パフォーマンスの最適化

効率的なスクレイピングのコツ

大量のデータを扱う際のパフォーマンス向上のテクニックです。

import pandas as pd
from concurrent.futures import ThreadPoolExecutor
import requests

def scrape_single_url(url):
    try:
        tables = pd.read_html(url)
        return tables[0]
    except:
        return None

# 並列処理でスクレイピング
urls = ["https://example.com/page1", "https://example.com/page2"]

with ThreadPoolExecutor(max_workers=3) as executor:
    results = list(executor.map(scrape_single_url, urls))

# 結果をフィルタリングして統合
valid_results = [df for df in results if df is not None]
combined_df = pd.concat(valid_results, ignore_index=True)

まとめ

PandasのWebスクレイピング機能を活用することで、HTMLテーブルから効率的にデータを取得できます。基本的なread_html()から始まり、requestsやBeautifulSoupとの組み合わせ、さらには動的コンテンツへの対応まで、様々な手法を使い分けることで、あらゆるWebページからデータを取得できるようになります。

スクレイピングを行う際は、対象サイトの利用規約やrobot.txtを確認し、適切な間隔でのアクセスを心がけることが重要です。また、エラーハンドリングとデータの品質管理を徹底することで、安定したデータ収集システムを構築できます。

らくらくPython塾 – 読むだけでマスター

■初心者歓迎「AI駆動開発/生成AIエンジニアコース」はじめました!

テックジム東京本校で先行開始。

■テックジム東京本校

格安のプログラミングスクールといえば「テックジム」。
講義動画なし、教科書なし。「進捗管理とコーチング」で効率学習。
対面型でより早くスキル獲得、月額2万円のプログラミングスクールです。

<短期講習>5日で5万円の「Pythonミニキャンプ」開催中。

<オンライン無料>ゼロから始めるPython爆速講座