渚ナギサコーポレーションSEO・LLMO・AEO・AIOのお悩み、全部お任せください。

全国対応打ち合わせから納品まで
メール・チャットで完結します

LINEで
相談する
サイトを
見てもらう
サイトを見てもらう(無料)LINEで相談
COLUMN 235 / 比較サイト・データベース型

CSVからページを作る:表の1行⁠を1ページ⁠にする手順

公開 2026.11.01文・ナギサコーポレーション

この記事の答え

  • 先に列を決める。URLに使う列、必須の列、出典と時点の列は必ず持つ
  • 文字コードを確かめて開く。BOM付きのUTF-8やShift_JISの違いで止まる
  • 必須の列が空の行と、数字が少ない行は、1ページにしない
目次

CSVからページを作るとは、表の1行⁠を1つ⁠のページにし、決めた型(テンプレート)⁠に列の値を流し込んで、行の数だけページを出すことです。会社の一覧なら1社⁠が1ページ⁠、製品の仕様表なら1型番が1ページ⁠になります。

道具の選び方は静的サイトジェネレーター⁠に書きました。ここでは、どの道具を使っても同じになる、表の側の準備と流し込みの手順を扱います。

作業は、どの順番で進める?

順番 やること
1 列を決める
2 文字コードを確かめて、UTF-8にそろえる
3 必須の列が空の行を、ページにしない行として外す
4 テンプレートに1行ずつ流し込む
5 数ページを開いて、元の表と見比べる

いちばん時間をかけるのは1です。あとから列を足したり名前を変えたりすると、テンプレートと、表を作る作業の両方を直すことになります。

列は、どう決める?

ページの中身を決める前に、次の4種類の列を必ず持たせます。

列の種類 例 決まり
URLに使う列 法人番号・型番 変わらない値。重複させない
必須の列 会社名・所在地 空ならページにしない
任意の列 従業員数・設立年 空なら理由を入れる
出典と時点の列 出典URL・確認日 行ごとに持つ

URLには、名前ではなく番号の列を使います。会社名は「株式会社」⁠の位置や表記が変わることがあり、そのたびにURLが変わります。会社なら13桁の法人番号が使えます。番号の使い方は法人番号とはに、URLの付け方はURL設計にまとめました。

出典と時点は、表全体で1つではなく、行ごとに持たせます。データを取り直したとき、一部の行だけ新しい日付になるからです。項目ごとに出典が違うなら、項目ごとに列を分けます。

文字コードは、UTF-8とShift_JISのどちら?

ページを作る側の表は、UTF-8にそろえます。受け取ったCSVがShift_JISで保存されていることがあるので、開く前にどちらかを確かめ、読み込むときに文字コードを指定して変換します。Pythonのcsvモジュールの説明では、ファイルはnewline=''を付けて開くよう書かれています。付けないと、項目の中の改行を正しく読めません。

Shift_JISは、cp932で読む

Pythonには、日本語の文字コードとしてshift_jisとcp932の2つ⁠があります(codecsの一覧)⁠。私たちが手元のPython 3.14⁠で試すと、shift_jisでは、丸数字の①、「髙」⁠、㈱が変換できずに止まりました。cp932では3つとも通りました。

全角のチルダ「~」⁠も違いが出ます。cp932で書いた「~」⁠をshift_jisで読むと、波ダッシュ「〜」⁠と⁠い⁠う別の文字になりました。見た目が似ているので、画面では気づきにくい違いです。Windowsで作られたShift_JISのファイルは、cp932で読みます。

BOMで、1列目が読めなくなる

UTF-8のCSVには、先頭にBOMという3バイトの印が付いていることがあります。私たちが試すと、BOM付きのファイルをutf-8で開いたとき、1列目の名前が「id」⁠で⁠は⁠な⁠く⁠、頭に印の残った別の文字列になりました。row["id"]で値を取り出そうとすると、列が無いと言われて止まります。

utf-8-sigを指定すると、先頭の印を読み飛ばします。BOMの無いファイルもそのまま読めるので、受け取ったCSVを読むときはutf-8-sigにしておくと、この失敗を避けられます。

テンプレートに、どう流し込む?

架空の会社の表で、1行⁠を1ページ⁠にする短い例です。

id,name,city,employees,source_url,checked
0001,サンプル工業,○○市,120,https://example.com/a,2026-10-01
0002,テスト精機,○○町,,https://example.com/b,2026-10-01
import csv
import html
from pathlib import Path

TEMPLATE = """<h1>{name}</h1>
<p>所在地:{city}</p>
<p>従業員数:{employees}</p>
<p>出典:<a href="{source_url}">{source_url}</a>({checked}時点)</p>
"""

with open("companies.csv", newline="", encoding="utf-8-sig") as f:
    for row in csv.DictReader(f):
        if not row["name"] or not row["source_url"]:
            continue  # 必須の列が空の行はページにしない
        row["employees"] = row["employees"] or "未確認"
        page = TEMPLATE.format(**{k: html.escape(v) for k, v in row.items()})
        out = Path("dist/company") / row["id"] / "index.html"
        out.parent.mkdir(parents=True, exist_ok=True)
        out.write_text(page, encoding="utf-8")

手元で動かすと、dist/company/0001/index.htmlとdist/company/0002/index.htmlの2ページ⁠ができました。2社目は従業員数の欄が空なので、「未確認」⁠と出ます。

値を流し込む前にhtml.escapeを通しているのは、会社名に「&」⁠や「<」⁠が入っていてもページが崩れないようにするためです。実際のサイトでは、見出し、表、リンク、構造化データも同じ型に入れます。型に何を置くかはプログラマティックSEO⁠で扱いました。

空欄は、どう扱う?

この例では空欄を全部「未確認」にしましたが、実際のデータでは、公表されていない、当てはまらない、まだ調べていない、0の4つ⁠が混ざります。表の側で、値の列とは別に理由の列を持たせ、ページにはその理由を出します。0と空欄を同じにすると、並べ替えや平均にも入ってしまいます。分け方はデータの空欄の見せ方⁠に書きました。

ページにしない行は、どう決める?

必須の列が空の行は、コードの中で外します。もう1つ⁠、値は入っているけれど、1ページ⁠にするほどの中身が無い行があります。会社名と所在地しか分からない会社のページは、読む人が知りたいことに答えられません。

私たちの採用の数字のデータベース(カイシャのホント)⁠で⁠は⁠、数字が5項目以上ある会社だけを検索に出しました。その後、数字が少ない会社は1社1ページ⁠をやめ、市町村の一覧の中の1行⁠にまとめています。線の引き方は薄いページの基準⁠にまとめました。

判定は、テンプレートの中に散らさず、流し込む前の1か所に書きます。データが増えたり取り直したりしたとき、判定を1回回せば、ページにする行が決まります。

流し込んだ後に、何を確かめる?

全部のページを人が開くことはできないので、選んで見ます。

  • 表の最初の行と最後の行
  • 空欄の多い行、文字数のいちばん長い行
  • 名前に&や括弧、全角の英数字を含む行
  • ページにしないはずの行が、出ていないか

ページの数が、表の行数から外した行を引いた数と合っているかも数えます。合わなければ、URLに使う列に重複があるか、判定の条件が思ったとおりに働いていません。データで作るサイトの全体はデータベース型サイトから読めます。

仕様・出典の確認日:2026年10月26日⁠。

よくある質問

CSVのどの列をURLに使えばいいですか?

変わらない番号の列です。会社なら法人番号、製品なら型番や自社で振った番号を使います。会社名や製品名は表記が変わることがあり、そのたびにURLが変わってしまいます。

CSVはUTF-8とShift_JISのどちらで保存すればいいですか?

ページを作る側ではUTF-8にそろえます。受け取ったCSVがShift_JISなら、読み込むときに文字コードを指定して変換します。Pythonでは、丸数字や「髙」⁠を含むファイルは、shift_jisではなくcp932を指定しないと読み書きで止まります。

Excelで作ったCSVを読むと、1列目の名前がおかしくなるのはなぜですか?

ファイルの先頭にBOMという印が付いていることがあります。PythonでUTF-8として開くと、1列目の名前の頭にその印が残り、列名で値を取り出せません。utf-8-sigを指定すると、先頭の印を読み飛ばします。

空欄のある行は、ページにしていいですか?

必須の列が空の行はページにしません。任意の列の空欄は、空白のままにせず、未確認や非公開など理由ごとに決めた言葉を入れます。数字が少ない行は、1ページ⁠にせず一覧の1行⁠にまとめる方法もあります。

あわせて読みたい

SSGとは:静的サイト生成とCMSの使い分け

静的サイトジェネレーター(SSG)⁠は⁠、データとテンプレートから公開前にHTMLを組み立てておく道具です。WordPressなどのCMSとの違い、会社やデータの行数が多いサイトでSSGを選ぶ場面と選ばない場面、Hugo・Astro・Eleventyでデータからページを作る仕組み、ファイル数の上限を整理します。

解説を読む
データの空欄の見せ方:非公開・該当なし・未確認を分ける

データの表の空欄は、公表されていない・該当しない・まだ調べていない・0の4つを、別々の記号や言葉で分けて見せます。凡例を表の近くに置き、0と空欄を混ぜません。国の統計の「-」「…」「X」⁠の意味を総務省統計局の注意書きで確かめ、空欄の多いページを検索に出すかの判断までを整理します。

解説を読む
薄いページとは:検索に出すかを決める基準

薄いページとは、読む人が判断に使える中身が少なく、他のページやデータの元を見れば足りてしまうページです。データベース型のサイトでは、項目の数で基準を決め、足す・検索から外す・一覧にまとめるの3つ⁠に機械で振り分けます。基準の決め方と、Googleの公式の説明を整理します。

解説を読む
URL設計:あとで変えなくて済むURLの付け方

URL設計は、ページの中身が変わっても変えなくて済むものだけをURLに入れる作業です。Googleが求めるURLの要件とおすすめ、W3Cの「変わらないURL」⁠の考え方、データベース型サイトで分類と項目をどうURLにするか、表記ゆれをそろえる方法を説明します。

解説を読む

いきなり契約する必要はありません。

御社のサイトを見て、「検索とAIから問い合わせを増やすなら、まず何をするべきか⁠」⁠をお伝えします。営業電話はしません。相談だけでも構いません。

自社サイトを見てもらう LINEならURLを送るだけ 打ち合わせから納品まで、メールとチャットで完結します
サイトを見てもらうLINEで相談