Webサイトでデータを見つけた。それをデータベースに入れたい。
A地点からB地点への最速ルートは?
このガイドでは、HTMLテーブルをSQLite、PostgreSQL、MySQLなどのデータベースに取り込む実践的なワークフローを、最小限の手間で解説します。
基本ワークフロー
ブラウザからデータベースへのパイプラインは、すべて同じステップで構成されます:
- 抽出 — Webページからテーブルを取り出す
- クリーニング — フォーマット、型、構造を修正する
- ロード — データベースに挿入する
問題は、各ステップをどこで、どのツールで行うかです。
パス1:CSVを中間ファイルとして使う
最も一般的なアプローチ。どのデータベースでも使えます。
ステップ1:CSVにエクスポート
HTML Table Exporterなどのブラウザ拡張機能を使うか、スプレッドシートにコピー&ペーストしてCSVとして保存します。
重要なポイント: デリミタの選択。カンマはデータにカンマが含まれていない限り有効です。セミコロンやタブの方がデータが複雑な場合は安全です。
ステップ2:データベースにロード
SQLite:
sqlite3 mydb.db
.mode csv
.import data.csv tablename
ヘッダー付きの場合:
sqlite3 mydb.db <<EOF
.mode csv
.headers on
.import data.csv tablename
EOF
PostgreSQL:
COPY tablename FROM '/path/to/data.csv'
WITH (FORMAT csv, HEADER true);
またはpsqlで:
\copy tablename FROM 'data.csv' WITH (FORMAT csv, HEADER true);
MySQL:
LOAD DATA INFILE '/path/to/data.csv'
INTO TABLE tablename
FIELDS TERMINATED BY ','
ENCLOSED BY '"'
LINES TERMINATED BY '\n'
IGNORE 1 ROWS;
メリットとデメリット
- 汎用性が高い
- 中間ファイルを確認できる
- ロード前に手動で問題を修正できる
- 追加のステップが必要
- 型推論が基本的
パス2:SQL文に直接変換
テーブルを直接INSERT文としてエクスポートします。
SQLとしてエクスポート
一部のエクスポートツールはSQLを直接生成します。出力はこのようになります:
INSERT INTO table_name (col1, col2, col3) VALUES
('value1', 'value2', 123),
('value4', 'value5', 456);
ロード
SQLファイルを実行するだけです:
# SQLite
sqlite3 mydb.db < data.sql
# PostgreSQL
psql -d mydb -f data.sql
# MySQL
mysql mydb < data.sql
メリットとデメリット
- エクスポートからデータベースまでワンステップ
- SQLはデータベース間でほぼポータブル
- 大規模データセット=巨大なSQLファイル
- テーブルスキーマを事前に定義する必要がある
パス3:Python + Pandasパイプライン
最大の柔軟性。繰り返しインポートや複雑なクリーニングに最適。
完全なワークフロー
import pandas as pd
from sqlalchemy import create_engine
# ステップ1:CSVをロード(ブラウザからエクスポートしたもの)
df = pd.read_csv('data.csv')
# ステップ2:クリーニング
df.columns = df.columns.str.lower().str.replace(' ', '_') # 列名を正規化
df['date'] = pd.to_datetime(df['date']) # 日付をパース
df['amount'] = df['amount'].str.replace('[$,]', '', regex=True).astype(float) # 通貨をクリーニング
# ステップ3:データベースにロード
engine = create_engine('sqlite:///mydb.db')
# または: create_engine('postgresql://user:pass@localhost/mydb')
# または: create_engine('mysql+pymysql://user:pass@localhost/mydb')
df.to_sql('tablename', engine, if_exists='replace', index=False)
型マッピング
Pandasは型を推論しますが、明示的に指定することもできます:
df.to_sql('tablename', engine,
if_exists='replace',
index=False,
dtype={
'id': Integer(),
'name': String(100),
'created_at': DateTime(),
'amount': Float()
})
メリットとデメリット
- クリーニングと型の完全な制御
- 複雑な変換に対応
- 再現可能でスクリプト化できる
- Python環境が必要
- 一回限りのインポートにはやりすぎ
パス4:DuckDB(モダンなショートカット)
DuckDBはCSVを直接読み込み、ほとんどのクリーニングを自動で処理します。
直接クエリ
-- インポートせずにCSVをクエリ
SELECT * FROM 'data.csv';
-- 型推論付き
SELECT * FROM read_csv_auto('data.csv');
-- CSVからテーブルを作成
CREATE TABLE mytable AS SELECT * FROM 'data.csv';
ブラウザからクエリまで数秒で
# ブラウザからCSVとしてテーブルをエクスポート
# そのまますぐにクエリ:
duckdb -c "SELECT column1, SUM(column2) FROM 'data.csv' GROUP BY column1;"
スキーマ定義不要。インポートステップ不要。そのままクエリ。
メリットとデメリット
- アドホック分析に最速
- 優れた型推論
- SQLインターフェース
- 従来型のデータベースではない(永続化するには結果をエクスポート)
よくある問題の対処法
スペースを含む列名
Webテーブルのヘッダーには「Total Sales」や「Year to Date」のようなものが多い。
エクスポート時に修正: 一部のツールはヘッダーを自動的に正規化します。
インポート時に修正:
df.columns = df.columns.str.replace(' ', '_').str.lower()
またはインポート後にSQLで:
ALTER TABLE mytable RENAME COLUMN "Total Sales" TO total_sales;
異なる数値フォーマット
ヨーロッパ式(1.234,56)とUS式(1,234.56)のフォーマットがインポートを壊します。
インポート前に修正: クリーニングプリセット付きのツールを使うか:
# ヨーロッパ式を標準に変換
df['value'] = df['value'].str.replace('.', '').str.replace(',', '.').astype(float)
NULL表現
Webテーブルでは空白、「N/A」、「—」、「-」で欠損データを表します。
df = df.replace(['N/A', '—', '-', ''], pd.NA)
またはDuckDBで:
SELECT NULLIF(column, 'N/A') AS column FROM 'data.csv';
さまざまな日付フォーマット
df['date'] = pd.to_datetime(df['date'], format='mixed', dayfirst=True)
format='mixed' は同じ列内の不統一な日付フォーマットに対応します。
適切なパスの選び方
| シナリオ | 推奨パス |
|---|---|
| 一回限りのインポート、小さなテーブル | CSV + データベース直接インポート |
| 一回限りのインポート、クリーニングが必要 | Python + Pandas |
| 迅速な分析、永続化不要 | DuckDB |
| 同じソースからの定期インポート | Pythonスクリプト(自動化) |
| 共有/バージョン管理用にSQL形式が必要 | SQL直接エクスポート |
実例:完全なワークフロー
Webサイトに製品データのテーブルがあるとします。
ステップ1: HTML Table Exporterでエクスポート → 数値がクリーニングされたCSV
ステップ2: DuckDBで簡易検証:
SELECT COUNT(*), COUNT(DISTINCT product_id) FROM 'products.csv';
-- 重複チェック
ステップ3: PostgreSQLにロード:
import pandas as pd
from sqlalchemy import create_engine
df = pd.read_csv('products.csv')
engine = create_engine('postgresql://user:pass@localhost/inventory')
df.to_sql('products', engine, if_exists='replace', index=False)
合計時間:2分。
本質的な教訓
最短のパスが必ずしも最も直接的なルートとは限りません。
エクスポート時のクリーニングに30秒かけることで、インポートエラーのデバッグに10分を節約できます。適切な中間フォーマット(CSV vs SQL vs JSON)の選択は、ターゲットデータベースとデータの複雑さに依存します。
ほとんどのWebテーブル → データベースのワークフローでは:
- 数値/日付クリーニング付きでCSVにエクスポート
- データベースのネイティブCSVインポートでロード
- 複雑な変換が必要な場合のみPythonを使用
シンプルなパイプラインこそ保守しやすいパイプラインです。
Pythonワークフローの詳細については、WebテーブルをPython & Pandas用にJSONにエクスポートする方法のガイドをご覧ください。
データベースに直接取り込めるクリーンなエクスポートが必要ですか?gauchogrid.com/ja/html-table-exporterで詳細を確認するか、Chrome ウェブストアでHTML Table Exporterを無料でお試しください。
Top comments (0)