きっかけ
GW明け、ジムがやたら混んでいて器具が全然使えず、正直むかついた。
でも、冷静になってみると疑問が湧いてきた。「普段こんなに混んでないのに、なんでこんなに人が多いんだ?」
しばらく考えてみると、仮説が浮かんだ。GW中に時間ができて「そうだ、体を動かそう」と思い立つ人が多いのかも。あるいは、新生活に慣れてきた人たちが一念発起してジムに来はじめるタイミングなのかも。
そこから疑問がどんどん広がった。季節によってフィットネスブームみたいなものはあるのか?祝日を挟んだ週は混み方が変わるのか?連休明けはどうなのか?自分が「空いてる」と思っていた時間帯は、本当に空いているのか?
なんとなくの感覚を、データで確かめたくなった。
ふと気づいたのが、スマホアプリに利用人数がリアルタイムで表示されているということ。 「これ、API として用意されてるんじゃないか?取得できないか?」とピンときた。
だったら自動で取って分析すればいいじゃないか。
やったこと
まず mitmproxy を使ってスマホアプリの通信をキャプチャし、API エンドポイントと認証トークンを特定した。 アプリの中身を直接掘り下げてAPIを見つけるこのアプローチが、地味に一番楽しかった部分かもしれない。
特定した API を使って15分ごとに混雑人数・混雑状態を自動取得して Google Sheets に蓄積した。
# 取得した人数データを Google Sheets に書き込む
sheet.append_row([jst_now, count, weekday, condition])
蓄積データが溜まってきたところで、Flask で可視化ダッシュボードを作成。 時間帯別・曜日別の平均混雑グラフ、今日の実績 vs 予測グラフを Chart.js で描画した。
Claude API でインサイトを生成
数字を見るだけでは「で、いつ行けばいいの?」がわかりにくい。 そこで Claude API(claude-sonnet-4-5)に過去データのサマリーを渡し、 おすすめの来店時間帯をインサイトとして自動生成させた。
response = client.messages.create(
model="claude-sonnet-4-5",
messages=[{"role": "user", "content": prompt}],
)
生成されたインサイトは Google Sheets の別シートに保存し、 ダッシュボードから読み出して表示している。
わかったこと
データを溜めて分析してみると、いくつか意外な発見があった。
まず「土日の昼は混んでいる」という自分の思い込みが完全に外れていた。実際はむしろ空いていて、意外と穴場だった。逆に一番混んでいるのは平日、特に月曜と火曜の20時前後。仕事終わりにジムへ直行する人が集中するタイミングだと思われる。
「なんとなくそうだろう」と思っていたことが、データで見るとぜんぜん違う。それが一番面白かった。
課題を解決するためにツールを作る、という体験が純粋に楽しかった。
今後の展望
現状、混雑予測には時間帯・曜日ごとの平均値をそのまま使っている。シンプルだけど、意外と実用的には機能している。
ただ、データが溜まってきたら機械学習モデルを使った予測にも挑戦したいと思っている。 今は収集期間がまだ短くデータ量が少ないため、モデルを組んでも過学習になってしまう。データが十分に積み上がったタイミングで取り組む予定。
データが十分に溜まったら、シーズンごとの分析にも踏み込みたい。夏前に急に混み始めるのか、年明けは新年の誓いで一瞬増えるのか、GW明けのような特定イベント前後でどう変化するか——きっかけで感じた疑問を、ちゃんとデータで答え合わせしたい。
データが育っていくにつれて、できることも広がっていくのが楽しみなプロジェクト。まだまだやりたいことは山積みで、これからも少しずつ育てていくつもり。
技術スタック
- Python / Flask
- Google Sheets API(gspread)
- Anthropic Claude API
- Chart.js
- Railway(デプロイ)