Home About Contact
Python

BeautifulSoup を使って HTML のテーブルデータをCSVへ変換する

ネット上のドキュメントで一覧表をHTMLのテーブルデータとして 掲載されているが、表計算(エクセル)用のデータまたはCSVデータは 提供されていない、という場合の対処方法です。(覚え書き)

GPT-4 Vision API など使えば、そのHTMLまたはそれをPDFにしたデータを アップロードした上で「CSVデータに変換して」といえば済むのかと思ったのですが、 どうやらまだ(今のところは)そこまで簡単にはいかない模様。

ChatGPT Plus であればすでにその手のことができるようになっているかもしれません。試していません。

数年もたてば ブラウザに搭載された AI に「今見ているページをエクセルに変換して」といえば済む世界が来そう。

ただ・・・この手の処理で GPT のような LLM を使う場合の不安は、 一部が間違って変換されても気づかない、という問題です。 人間が手作業でやった場合、間違いが混入することはある(ヒューマンエラー)ので、 その作業を GPT 的なもので代用した場合には、 人間とGPT(的なもの)とどっちが間違い多いか?みたいな問いになるとは思う。

たとえば、データ内に価格情報があった場合に間違った値として変換されると場合によっては悲惨なことになる。

しかし、HTMLのテーブルデータがあるのであれば、 Python + BeautifulSoup を使うことで、CSVへの変換が可能。 この古典的なやり方ならば、 変換用のコードに書いたルール通りにHTMLデータができている限りは 変換後のデータに間違いないと確信できる、 という点において GPT的方式より優れている。

環境

 $ python3 --version
Python 3.10.12

以下の説明では、 venv が使える状態であることを前提とします。

対象とするデータ(サンプル)

ポケモンの一覧がテーブルデータになっています。

index.html

<html>
<body>
<h1>ポケモン一覧</h1>
<table border=1>
<tr><th>No.</th><th>Name</th><th>Type</th></tr>
<tr><td>1</td><td>Bulbasaur</td><td>Grass</td></tr>
<tr><td>2</td><td>Ivysaur</td><td>Grass</td></tr>
<tr><td>3</td><td>Venusaur</td><td>Grass</td></tr>
<tr><td>4</td><td>Charmander</td><td>Fire</td></tr>
<tr><td>5</td><td>Charmeleon</td><td>Fire</td></tr>
<tr><td>6</td><td>Charizard</td><td>Fire</td></tr>
</table>
</body>
</html>

HTMLをブラウザでレンダリングして見ると次のようなデータになります。

ポケモン一覧

┌───┬───────────┬─────┐
│No.│   Name    │Type │
├───┼───────────┼─────┤
│1  │Bulbasaur  │Grass│
├───┼───────────┼─────┤
│2  │Ivysaur    │Grass│
├───┼───────────┼─────┤
│3  │Venusaur   │Grass│
├───┼───────────┼─────┤
│4  │Charmander │Fire │
├───┼───────────┼─────┤
│5  │Charmeleon │Fire │
├───┼───────────┼─────┤
│6  │Charizard  │Fire │
└───┴───────────┴─────┘

サンプルなので簡単なデータですが、BeautifulSoup はもっと複雑なものでも対処できます。

venv 環境の準備

venv 環境をカレントディレクトリに作成し、そこに BeautifulSoup4 をインストール。

$ python3 -m venv ./venv
$ source  ./venv/bin/activate
(venv) $ pip install beautifulsoup4

コード

main.py

import csv
from bs4 import BeautifulSoup

input_html_file = "index.html"
output_csv_file = "index.csv"

## 1) read index.html file
with open(input_html_file, 'r') as f:
    data = f.read()

soup = BeautifulSoup(data, "html.parser")
tables = soup.find_all('table')

cell_values_list = []

## 2) parse first table
rows = tables[0].find_all("tr")
for row in rows:
    cell_values = []
    for cell in row.findAll(["th","td"]):
        text = cell.get_text()
        cell_values.append(text)
    
    cell_values_list.append( cell_values )

## 3)export CSV to index.csv file
with open(output_csv_file, "w", encoding="utf-8") as file:
    writer = csv.writer(file)
    for cell_values in cell_values_list:
        writer.writerow(cell_values)

簡単なコードなので一度にまとめて掲載しました。

処理内容は次の通り:

  1. index.html を読む
  2. それを BeautifulSoup4 で読み取り先頭のテーブルデータを読み取る
  3. 結果を index.csv にCSV形式で保存

それでは実行してみます。

(venv) $ python main.py

生成された index.csv:

No.,Name,Type
1,Bulbasaur,Grass
2,Ivysaur,Grass
3,Venusaur,Grass
4,Charmander,Fire
5,Charmeleon,Fire
6,Charizard,Fire

以上です。

こんなに簡単にできるのだから、 データ配布元が処理して、(HTMLデータだけでなく)表計算データもいっしょに配布してほしいものです。