チェーン店の栄養データを集めて、世界一(応答が)速いカロリーデータベースを作った
外食やコンビニで「これ何kcalなんだろう」と思うことが多くて、チェーン店メニューの栄養情報を超高速でレスポンスするサイトを作りました。
公開しているのはこれです。
世界一速いカロリーデータベース
単なる一覧ではなく、たとえば
- 吉野家の牛丼は太る?
- スタバで100kcal以下の飲み物は?
- 高タンパクかつ低脂質で選びやすいものは?
みたいな検索意図に、そのまま答えられる構成を目指しています。
作ったもの
ざっくり言うと、チェーン店の公式栄養情報を集めて正規化し、静的ページとして大量生成する仕組みです。
最終的には次のようなページを出しています。
- トップページ
- チェーン別ページ
- 商品詳細ページ
- カテゴリ比較ページ
- 「太る?」「ダイエット向き?」のような質問ページ
- PFCバランスや高タンパク低脂質などのランキングページ
例:
技術的な考え方
今回あまりやりたかったのは「スクレイピングそのもの」より、ばらばらの公式データをどう扱いやすい形に揃えるかでした。
チェーン店の栄養情報は、実際にはかなり揺れます。
- HTML
- 表の構造が毎回違う
- 単位の持ち方が違う
- 商品名の表記揺れがある
- 塩分があるチェーンとないチェーンがある
なので、入口は複数あっても、最終的には同じ型に落とす方針にしています。
イメージとしてはこんな流れです。
- チェーンごとにデータを取得
- 共通スキーマに正規化
- 栄養指標を揃える
- 比較しやすい単位でエクスポート
- 静的ページをまとめて生成
構成
TypeScript で組んでいて、ざっくりこの3層です。
- 取得層: チェーンごとのデータ取得
- 正規化層: 共通フォーマットへの変換
- 出力層: JSON と静的 HTML の生成
特に意識したのは、チェーン追加のコストを下げることでした。
サイトを大きくするには、「1チェーン増えるたびに全体を触る」構成だとすぐ苦しくなるので、チェーンごとの差分をなるべく局所化しています。
静的サイトにした理由
この手のサイトは、検索流入を想定すると静的出力がかなり相性がいいです。
- 速い
- 配信が安定する
- 生成時に比較ロジックを持てる
- ページ単位で title / description / structured data を作りやすい
しかも今回は、ユーザーが見たいのは「データベースの全件表」ではなくて、比較結果や解釈です。
なのでページ生成時に
- 同チェーン平均との差
- カテゴリ平均との差
- 関連候補
- FAQ
- 質問クエリ向けの答え
- ランキング
まで先に埋め込むようにしました。
難しかったところ
1. データが同じようで全然同じじゃない
カロリーだけなら比較しやすそうに見えますが、実際は
- サービング単位が違う
- メニュー名にサイズ情報が混ざる
- 商品カテゴリが曖昧
- 一見同じ商品でも別IDがある
みたいな問題が地味に効きます。
2. 検索意図に寄せると、ページ設計が変わる
最初は「一覧ページをきれいに出せばいいかな」と思っていました。
でもそれだと、ユーザーが知りたいことに一歩届きません。
たとえば「吉野家 牛丼 太る」で来る人は、表そのものより
- 平均的に重いのか
- 軽めの選択肢はあるか
- 夜に食べるならどう見るか
を知りたいはずです。
そのため、一覧を見せるより、質問に答えるページを増やす方向に舵を切りました。
3. スクレイピング対策とSEOの両立
データをそのまま全部並べると便利ではあるのですが、そのぶん転載もしやすくなります。
そこで、全件一覧よりも「比較ページ」「ガイドページ」「質問ページ」に寄せる設計に変えました。
ユーザーにとっては見やすくなり、サイトとしての独自性も出しやすくなったので、この方向は正解だったと思っています。
いま気にしていること
今は機能開発より、次のあたりを詰めています。
- クロールされやすい構造
- 質問ページの固有性
- ランキングの納得感
- 更新頻度とデータ鮮度の扱い
検索向けのサイトは、作って終わりではなく、公開後の調整もかなり大事だと実感しています。
まとめ
作ってみて改めて思ったのは、こういうサイトは「データを集めること」よりも、データをどう解釈して届けるかのほうが重要だということでした。
もしよかったら触ってみてください。
世界一速いカロリーデータベース
感想や改善案も歓迎です。