Pandas pd.read_html() 関数
read_html()pandasライブラリでHTMLテーブルを解析するための関数であり、WebページまたはHTMLファイルからテーブルデータを読み取り、DataFrameに変換できます。
Webページ内のテーブルデータは非常に重要なデータソースであり、多くの公開データ(株式情報や統計データなど)はHTMLテーブルの形式で提供されています。read_html()を利用してlxmlとBeautifulSoupライブラリでHTMLを解析し、ページ内のすべてのテーブルまたは指定したテーブルを自動的に抽出できます。
基本構文とパラメータ
構文形式
pandas.read_html(io, match='.+', flavor=None, header=None, index_col=None,
skiprows=None, attrs=None, parse_dates=False, thousands=',',
decimal='.', converters=None, ...)
パラメータの説明
| パラメータ | 型 | 説明 | デフォルト値 |
|---|---|---|---|
| io | str, path object, file-like object | HTMLファイルのパス、URL、または文字列 | 必須 |
| match | str, regex | 正規表現を使用してテーブルのテキスト内容をマッチングします | '.+' |
| flavor | str | パーサー:'lxml', 'html5lib', 'bs4' | None |
| header | int, list of int | 列名として使用する行番号 | None |
| index_col | int, str | 行インデックスとして使用する列 | None |
| skiprows | int, list, slice | 指定した行をスキップします | None |
| attrs | dict | テーブルをフィルタリングするためのHTMLタグ属性 | None |
| parse_dates | bool, list | 日付列を解析するかどうか | False |
戻り値
- 戻り値の型:
listof DataFrames - DataFrameのリストを返します。ページ上にあるテーブルの数だけDataFrameを返します。
- 一致するテーブルが見つからない場合は、空のリストを返します。
例
以下の例を通じて、詳細に理解しますread_html()の様々な使い方をマスターしましょう。
例1:ローカルHTMLファイル内のテーブルを読み取る
まずテーブルを含むHTMLファイルを作成し、次にread_html()読み取ります。
例
import pandas as pd
# テーブルを含むHTMLファイルを作成する
html_content = '''
<title>従業員情報テーブル</title>
<h1>Pandas pd-read-html() 関数</h1>
<table border="1" class="employee-table">
<tr>
<th>氏名</th>
<th>年齢</th>
<th>都市</th>
<th>給与</th>
</tr>
<tr>
<td>Tom</td>
<td>28</td>
<td>Beijing</td>
<td>8000</td>
</tr>
<tr>
<td>Jerry</td>
<td>35</td>
<td>Shanghai</td>
<td>12000</td>
</tr>
<tr>
<td>Mike</td>
<td>42</td>
<td>Guangzhou</td>
<td>15000</td>
</tr>
<tr>
<td>Lucy</td>
<td>26</td>
<td>Shenzhen</td>
<td>7000</td>
</tr>
</table>
<h2>部門リスト</h2>
<table border="1">
<tr>
<th>部門</th>
<th>人数</th>
</tr>
<tr>
<td>技術部</td>
<td>50</td>
</tr>
<tr>
<td>営業部</td>
<td>30</td>
</tr>
</table>
'''
# HTMLをファイルに書き込む
with open('tables.html', 'w', encoding='utf-8') as f:
f.write(html_content)
# read_html を使用してすべてのテーブルを読み取る
# io: HTMLファイルのパス(必須)
tables = pd.read_html('tables.html')
# 読み取り結果を確認する
print(f"合計 {len(tables)} 個のテーブルが見つかりました")
print()
# すべてのテーブルをループ処理する
for i, df in enumerate(tables):
print(f"--- テーブル {i+1} ---")
print(df)
print()
# テーブルを含むHTMLファイルを作成する
html_content = '''
<title>従業員情報テーブル</title>
<h1>Pandas pd-read-html() 関数</h1>
<table border="1" class="employee-table">
<tr>
<th>氏名</th>
<th>年齢</th>
<th>都市</th>
<th>給与</th>
</tr>
<tr>
<td>Tom</td>
<td>28</td>
<td>Beijing</td>
<td>8000</td>
</tr>
<tr>
<td>Jerry</td>
<td>35</td>
<td>Shanghai</td>
<td>12000</td>
</tr>
<tr>
<td>Mike</td>
<td>42</td>
<td>Guangzhou</td>
<td>15000</td>
</tr>
<tr>
<td>Lucy</td>
<td>26</td>
<td>Shenzhen</td>
<td>7000</td>
</tr>
</table>
<h2>部門リスト</h2>
<table border="1">
<tr>
<th>部門</th>
<th>人数</th>
</tr>
<tr>
<td>技術部</td>
<td>50</td>
</tr>
<tr>
<td>営業部</td>
<td>30</td>
</tr>
</table>
'''
# HTMLをファイルに書き込む
with open('tables.html', 'w', encoding='utf-8') as f:
f.write(html_content)
# read_html を使用してすべてのテーブルを読み取る
# io: HTMLファイルのパス(必須)
tables = pd.read_html('tables.html')
# 読み取り結果を確認する
print(f"合計 {len(tables)} 個のテーブルが見つかりました")
print()
# すべてのテーブルをループ処理する
for i, df in enumerate(tables):
print(f"--- テーブル {i+1} ---")
print(df)
print()
実行結果の想定:
共找到 2 个表格
--- 表格 1 ---
姓名 年龄 城市 薪资
0 Tom 28 Beijing 8000
1 Jerry 35 Shanghai 12000
2 Mike 42 Guangzhou 15000
3 Lucy 26 Shenzhen 7000
--- 表格 2 ---
部门 人数
0 技术部 50
1 销售部 30
コードの解説:
read_html()DataFrameのリストを返し、各テーブルが1つのDataFrameに対応します。- デフォルトでは、すべてのテーブルが読み取られます。
- 最初の行は自動的に列名として認識されます(
th<th>タグがあるため)。
例2:attrs と match を使用してテーブルをフィルタリングする
ページに複数のテーブルがある場合、属性またはテキストマッチングを使用して必要なテーブルをフィルタリングできます。
例
import pandas as pd
# 属性を持つHTMLファイルを作成する
html_with_attrs = '''
<table id="employees" class="data-table">
<tr><th>name</th><th>age</th></tr>
<tr><td>Tom</td><td>28</td></tr>
<tr><td>Jerry</td><td>35</td></tr>
</table>
<table id="products" class="data-table">
<tr><th>product</th><th>price</th></tr>
<tr><td>A</td><td>100</td></tr>
<tr><td>B</td><td>200</td></tr>
</table>
<table class="summary">
<tr><td>Total</td><td>2</td></tr>
</table>
'''
with open('tables_attrs.html', 'w', encoding='utf-8') as f:
f.write(html_with_attrs)
# 例2a: attrs を使用して id 属性でフィルタリングする
# id="employees" のテーブルを読み取る
tables_by_id = pd.read_html('tables_attrs.html', attrs={'id': 'employees'})
print("id でフィルタリング:")
print(tables_by_id[0])
print()
# 例2b: attrs を使用して class 属性でフィルタリングする
# class="data-table" のすべてのテーブルを読み取る
tables_by_class = pd.read_html('tables_attrs.html', attrs={'class': 'data-table'})
print("class でフィルタリング ({} 個のテーブルが見つかりました):".format(len(tables_by_class)))
for i, df in enumerate(tables_by_class):
print(f"テーブル {i+1}:")
print(df)
print()
# 例2c: match を使用して特定のテキストを含むテーブルをフィルタリングする
# match は正規表現を使用してテーブル内のテキストにマッチングする
tables_by_text = pd.read_html('tables_attrs.html', match='Tom')
print("'Tom' というテキストを含むテーブル:")
print(tables_by_text[0])
# 属性を持つHTMLファイルを作成する
html_with_attrs = '''
<table id="employees" class="data-table">
<tr><th>name</th><th>age</th></tr>
<tr><td>Tom</td><td>28</td></tr>
<tr><td>Jerry</td><td>35</td></tr>
</table>
<table id="products" class="data-table">
<tr><th>product</th><th>price</th></tr>
<tr><td>A</td><td>100</td></tr>
<tr><td>B</td><td>200</td></tr>
</table>
<table class="summary">
<tr><td>Total</td><td>2</td></tr>
</table>
'''
with open('tables_attrs.html', 'w', encoding='utf-8') as f:
f.write(html_with_attrs)
# 例2a: attrs を使用して id 属性でフィルタリングする
# id="employees" のテーブルを読み取る
tables_by_id = pd.read_html('tables_attrs.html', attrs={'id': 'employees'})
print("id でフィルタリング:")
print(tables_by_id[0])
print()
# 例2b: attrs を使用して class 属性でフィルタリングする
# class="data-table" のすべてのテーブルを読み取る
tables_by_class = pd.read_html('tables_attrs.html', attrs={'class': 'data-table'})
print("class でフィルタリング ({} 個のテーブルが見つかりました):".format(len(tables_by_class)))
for i, df in enumerate(tables_by_class):
print(f"テーブル {i+1}:")
print(df)
print()
# 例2c: match を使用して特定のテキストを含むテーブルをフィルタリングする
# match は正規表現を使用してテーブル内のテキストにマッチングする
tables_by_text = pd.read_html('tables_attrs.html', match='Tom')
print("'Tom' というテキストを含むテーブル:")
print(tables_by_text[0])
実行結果の想定:
使用 id 筛选: name age 0 Tom 28 1 Jerry 35 使用 class 筛选 (找到 2 个表格): 表格 1: name age 0 Tom 28 1 Jerry 35 表格 2: product price 0 A 100 1 B 200 包含 'Tom' 文本的表格: name age 0 Tom 28 1 Jerry 35
コードの解説:
attrsパラメータは、HTMLタグの属性(id、class、styleなど)を指定してテーブルをフィルタリングできます。matchパラメータは正規表現を使用してテーブル内のテキスト内容にマッチングし、一致するテキストを含むテーブルを返します。- テーブルが1つだけ返された場合は、
tables[0]最初のDataFrameを取得できます。
例3:ヘッダーとインデックスを処理する
HTMLテーブルの形式は複雑な場合があるため、ヘッダーとインデックスを柔軟に処理する必要があります。
h2 class="example">例
import pandas as pd
# 複雑な構造のHTMLを作成する
html_complex = '''
<!-- ヘッダーのないテーブル -->
<table id="no_header">
<tr><td>Tom</td><td>28</td></tr>
<tr><td>Jerry</td><td>35</td></tr>
</table>
<!-- 複数行のヘッダー -->
<table id="multi_header">
<tr><th>氏名</th><th colspan="2">連絡先</th></tr>
<tr><th></th><th>電話</th><th>メール</th></tr>
<tr><td>Tom</td><td>123456</td><td>[email protected]</td></tr>
<tr><td>Jerry</td><td>789012</td><td>[email protected]</td></tr>
</table>
<!-- 属性を持つテーブル -->
<table id="with_index" data-type="employee">
<tr><th>氏名</th><th>年齢</th><th>都市</th></tr>
<tr><th></th><th></th><th></th></tr>
<tr><td>Tom</td><td>28</td><td>Beijing</td></tr>
</table>
'''
with open('tables_complex.html', 'w', encoding='utf-8') as f:
f.write(html_complex)
# 例3a: ヘッダーがない場合
# header=None は最初の行を列名として使用しない
df_no_header = pd.read_html('tables_complex.html', attrs={'id': 'no_header'}, header=None)[0]
print("ヘッダーなし:")
print(df_no_header)
print()
# 例3b: 複数行のヘッダー
# 0行目と1行目をまとめてヘッダーとして使用する
df_multi_header = pd.read_html('tables_complex.html', attrs={'id': 'multi_header'})[0]
print("複数行のヘッダー:")
print(df_multi_header)
print()
# 例3c: インデックス列を設定する
# index_col は0列目をインデックスとして指定する
df_with_index = pd.read_html('tables_complex.html', attrs={'id': 'with_index'}, index_col=0)[0]
print("インデックスを設定:")
print(df_with_index)
# 複雑な構造のHTMLを作成する
html_complex = '''
<!-- ヘッダーのないテーブル -->
<table id="no_header">
<tr><td>Tom</td><td>28</td></tr>
<tr><td>Jerry</td><td>35</td></tr>
</table>
<!-- 複数行のヘッダー -->
<table id="multi_header">
<tr><th>氏名</th><th colspan="2">連絡先</th></tr>
<tr><th></th><th>電話</th><th>メール</th></tr>
<tr><td>Tom</td><td>123456</td><td>[email protected]</td></tr>
<tr><td>Jerry</td><td>789012</td><td>[email protected]</td></tr>
</table>
<!-- 属性を持つテーブル -->
<table id="with_index" data-type="employee">
<tr><th>氏名</th><th>年齢</th><th>都市</th></tr>
<tr><th></th><th></th><th></th></tr>
<tr><td>Tom</td><td>28</td><td>Beijing</td></tr>
</table>
'''
with open('tables_complex.html', 'w', encoding='utf-8') as f:
f.write(html_complex)
# 例3a: ヘッダーがない場合
# header=None は最初の行を列名として使用しない
df_no_header = pd.read_html('tables_complex.html', attrs={'id': 'no_header'}, header=None)[0]
print("ヘッダーなし:")
print(df_no_header)
print()
# 例3b: 複数行のヘッダー
# 0行目と1行目をまとめてヘッダーとして使用する
df_multi_header = pd.read_html('tables_complex.html', attrs={'id': 'multi_header'})[0]
print("複数行のヘッダー:")
print(df_multi_header)
print()
# 例3c: インデックス列を設定する
# index_col は0列目をインデックスとして指定する
df_with_index = pd.read_html('tables_complex.html', attrs={'id': 'with_index'}, index_col=0)[0]
print("インデックスを設定:")
print(df_with_index)
実行結果の想定:
没有表头:
0 1
0 Tom 28
1 Jerry 35
多行表头:
姓名 联系方式
NaN 电话 邮箱
0 Tom 123456 [email protected]
1 Jerry 789012 [email protected]
设置索引:
年龄 城市
姓名
Tom 28 Beijing
</空行>
空字符串 NaN NaN
Tom 28 Beijing
コードの解説:
header=None自動ヘッダー認識を無効にし、デフォルトの整数インデックスを列名として使用できます。- 複数行のヘッダーは多層インデックス(MultiIndex)として処理されます。
index_colパラメータは、特定の列を行インデックスとして指定できます。
注意事項
- を使用するには
read_html()のインストールが必要ですlxmlライブラリ:pip install lxml。 - 返されるのはDataFrameのリストであり、インデックスに基づいて特定のテーブルを選択する必要があります。
- ページに複数のテーブルがある場合は、
attrs或matchパラメータを使用してフィルタリングします。 read_html()すべてのテーブルの解析を試みるため、遅くなる可能性があります。大きなページでは、matchパラメータを使用して範囲を絞り込むことができます。- ネットワークページを読み取るにはネットワークサポートが必要であり、アクセス制限やスクレイピング防止メカニズムが存在する可能性があります。
まとめ
read_html()pandasでHTMLテーブルデータを読み取るための強力なツールです。Webページ内のテーブルを自動的に解析し、構造化されたDataFrame形式に変換できます。
実際の業務でWebページからデータを取得する必要がある場合、read_html()非常に実用的な選択肢です。attrs と match パラメータの使用方法を理解すれば、複雑なページから必要なデータを効率的に抽出できます。Webページのテーブルを取得する必要がある場合は、この関数を優先的に検討することをお勧めします。
Pandas よく使われる関数