アプリを作ろう──妙高市雪情報グラフ第4回:動作確認とデバッグ
アプリを作ろう──妙高市雪情報グラフ
第4回:動作確認とデバッグ
こんにちは。
前回は、動作確認の準備としてgitコマンドを整理しました。
今回はいよいよ、AIエージェントが作ってくれたコードを実際に動かしてみます。
……が、当然のように動きません。そこからが本番です。
ちなみに、バイブコーディング(AIと対話しながらコードを書く手法)は、
別の記事「お誕生日お祝いアプリ」に続いて 2回目 です。
ただ、今回はHTMLから表データを取り出す テーブル処理 があるので、
前回より難しそうだな……と思いながらのスタートでした。
Cursor君、よろしくお願いします。
:::message
この連載は、Webアプリ開発初心者が、同じく初心者の方に向けて書いている記事です。
エラーや試行錯誤も隠さず共有しますので、一緒に「できた!」を目指しましょう。
:::
まずは動かしてみる
仮想環境を作って、依存パッケージをインストールしたら、さっそく実行です。
streamlit run main.py10秒ほど待つと、アプリが立ち上がりました。

左側に年月選択のサイドバー、右側に3つのグラフ表示エリア……
仕様通りの構成です。
でも、グラフが表示されていません。
画面には、こんなエラーメッセージが出ています。
❌ 2026年11月 / 新井消防署 のデータ取得に失敗しましたここからデバッグの旅が始まります。
問題① URLリストが正しくない
まず疑ったのは、URLリストが正しいかどうかです。
CSVファイルに書かれたURLをブラウザで開いてみると……
「お探しのページはありません」
URLが間違っていました。
第2回でAIが推測して作ったURLは、実際のページと異なっていたのです。
解決策:スクレイピングでURLを取得
妙高市のホームページを確認すると、年月ごとのURLは規則的ではなく、
`/docs/12345.html` のような 不規則なアドレス になっていました。
そこで、AIエージェントにお願いしてみました。
「積雪メニュー画面のURLを渡すから、そこからリンクを読み取ってURLリストを作って」
正直、無理なお願いかな……と思っていたのですが、
AIエージェントは、メニュー画面をスクレイピングしながらURLリストを作ってくれました。
これには驚きました。
まずは何でもお願いしてみるものですね。
URLリストの完成
AIが作ったリストには、いくつか抜けがありました。
そこで私が実際にページの存在を確認して、手動で補完しました。
最終的な直近5年分の完成度は以下の通りです。
| 年度 | 揃い具合 |
|------|----------|
| 令和3年度 | 11月、12月、1月、2月、3月、4月 → 6ヶ月完備 ✅ |
| 令和4年度 | ~~11月(欠損)~~、12月、1月、2月、3月、4月 → 5ヶ月 |
| 令和5年度 | 11月、12月、1月、2月、3月、4月 → 6ヶ月完備 ✅ |
| 令和6年度 | 11月、12月、1月、2月、3月、4月 → 6ヶ月完備 ✅ |
| 令和7年度 | 11月、12月、4月 → 3ヶ月(1月〜3月は今後公開予定) |令和4年度11月のデータだけは妙高市のサイトで見つかりませんでしたが、
それ以外はほぼ完璧。これで動作確認できる状態になりました。
問題② データが抽出できない
URLリストを修正して再実行。
今度こそ……と思いきや、また別のエラーが出ました。
WARNING:__main__:データが抽出できませんでした: https://www.city.myoko.niigata.jp/docs/75741.htmlURLは正しいのに、データが取れない。
HTMLの表(table)の構造が、コードの想定と違っているようです。
AIエージェントによる自動デバッグ
ここで、AIエージェント(Cursor Agent)の真価が発揮されました。
AIに「このエラーの原因を特定して修正して」とお願いすると、
自分でデバッグを始めました。
驚いたのは、AIが自分でコードを書いて、自分で実行して、自分で結果を確認していた ことです。
やってくれたこと:
HTMLページを取得してテーブル構造を解析する デバッグ用コードを自動作成
不足パッケージを自動インストール
デバッグコードを 自分で実行 して、実際のテーブル構造を確認
「ヘッダーが2行ある」「列の順序が想定と違う」などの問題点を特定
コードを修正
修正結果の動作確認用コードを作成 して、データテーブルを出力
出力結果を見て、正しくデータが取れているか 自分で検証
人間がやるデバッグの流れを、AIが全部やってくれたのです。
「確認用コード作って→実行→結果見て→直す」のサイクルを、自動で回していました。
もしAIエージェントがなかったら、
何度も何度も何度も print文を仕込んで確認していた ことでしょう。
それを全部やってくれるとは……。
話には聞いていましたが、実際に見ると感動すら覚えます。
問題③ 日付のパースエラー
修正後に再実行しても、またエラー。
AIに調べてもらうと、今度は 日付の解析(パース)に問題がある ことが判明。
妙高市のページでは、日付が「1日」「2日」のように
「日」という文字が含まれる形式 になっていました。
AIは「今度こそ確実に動くようにします」と宣言して、修正を実行。
数回のエラーを繰り返しながら、動作確認と修正を自動で繰り返してくれました。
ついに動いた!
そして、完成宣言が出ました。
streamlit run main.py
おおー!
グラフが描画されています!
降雪量は 赤い折れ線グラフ
積雪量は 水色の棒グラフ
要件定義で書いた通りの表示になっています。
AIエージェントからのメッセージ
お礼を言ったら、AIエージェントがこんな返事をくれました。
🎉 おめでとうございます!グラフが表示されたとのこと、本当に良かったです!
長い道のりでしたが、以下の問題を解決しました:
1. ✅ 新しいURL形式(/docs/xxxxx.html)への対応
2. ✅ ヘッダー行が2行ある構造への対応
3. ✅ 列の順序が交互になっている構造への対応
4. ✅ 日付に「日」という文字が含まれる問題への対応
5. ✅ --(ダブルハイフン)の欠損値処理
振り返ると、5つもの問題を解決していた んですね。
AIと一緒に歩んだデバッグの道のりでした。
感じたこと:バイブコーディングの威力
「バイブコーディング」(AIと対話しながらコードを書く手法)の威力は
色々なところで見聞きしていましたが、実際に自分で体験すると、
その能力を肌で実感できます。
ちょっと感動しました。(満員の新幹線の中でなかったら、「おーっ!」と叫んでいたはず)
正直、ちょっと怖かった
一方で、正直な気持ちも書いておきます。
要所要所でAIが「確認してください」と言ってくるのですが、
その合間に、勝手にテストコードを作って、パッケージをインストールして、ターミナルで実行して…… という動きを見ていると、
「こいつ、何やってるんだ……?」
という気持ちになりました。
問題が起きるんじゃないか、という不安。
これはすぐに慣れるのだろうけど、最初は少し怖かったです。
今後の改善メモ
動作確認中に気づいたことをメモしておきます。
改善案:データのキャッシュ保存
毎回5年分のデータを読み込むと時間がかかる。
前年度分までは保存しておいて、今年度分だけ読み込んで合体する仕組みにしたい。
これは、全ての動作確認を終えてから実装します。
次回予告
今回は、アプリを動かしてグラフが表示されるところまで確認しました。
次回は、左のサイドバーで年月や地点を切り替える動作 を確認していきます。
お楽しみに。
今回のまとめ
最初の実行ではエラーが出て当たり前(そこからがスタート)
URLリストはAIがスクレイピングで作ってくれた
テーブル構造の違いはAIが自動でデバッグしてくれた
5つの問題を解決して、ついにグラフが表示された
AIエージェントの自動デバッグは、感動と少しの怖さがある
学びポイント 💡
「動かないのは当然。そこからAIと一緒にデバッグする」
AIが書いたコードは、最初から完璧には動きません。
でも、エラーが出たら AIと一緒に原因を探って直していける のが、
バイブコーディングの強みです。
「エラー=失敗」ではなく、「エラー=学びのチャンス」。
そう思えると、開発がもっと楽しくなります。
補足:AIエージェントによる主な修正箇所
このセクションでは、AIエージェントが自動で行った具体的なコード修正を記録します。
修正① ヘッダー行のスキップ(70行目付近)
新しいURL形式ではヘッダーが2行存在することが判明。
# 修正前
for row in rows[1:]: # 最初の行はヘッダーと仮定
# 修正後
for row in rows[2:]: # ヘッダーは2行あるためスキップ理由: HTMLテーブルの1行目が観測所名、2行目が「降雪/積雪」の見出しになっていた。
修正② 日付パース(80行目)
日付列に「日」という文字が含まれていることが判明。
# 修正前
day = int(cols_text[0])
# 修正後
day = int(cols_text[0].replace("日", ""))理由: `"1日"`, `"2日"` のような文字列を `int()` に直接変換できないため、`"日"` を除去してから変換。
修正③ 列インデックスの計算(87-91行目)
列の順序が想定と異なることが判明。
# 修正前(想定していた列順)
# [日, 降雪1, 降雪2, 降雪3, 積雪1, 積雪2, 積雪3]
snowfall_idx = i + 1 # 降雪量(インデックス 1, 2, 3)
snowdepth_idx = i + 4 # 積雪量(インデックス 4, 5, 6)
# 修正後(実際の列順)
# [日, 降雪1, 積雪1, 降雪2, 積雪2, 降雪3, 積雪3]
snowfall_idx = i * 2 + 1 # 降雪量(インデックス 1, 3, 5)
snowdepth_idx = i * 2 + 2 # 積雪量(インデックス 2, 4, 6)理由: 実際のHTMLテーブルは、降雪と積雪が交互に配置されていた。
修正④ 欠損値パターンの追加(96-97行目)
`"--"` (ダブルハイフン) も欠損値として扱う必要があることが判明。
# 修正前
snowfall_cm = None if snowfall == "-" or snowfall == "" else float(snowfall)
snowdepth_cm = None if snowdepth == "-" or snowdepth == "" else float(snowdepth)
# 修正後
snowfall_cm = None if snowfall in ["-", "--", ""] else float(snowfall)
snowdepth_cm = None if snowdepth in ["-", "--", ""] else float(snowdepth)理由: 妙高市のサイトでは、欠損値を `"-"` だけでなく `"--"` でも表現していた。
デバッグの流れ
HTMLを直接確認 → テーブル構造を把握
デバッグスクリプト作成 → 実際のデータを確認
問題点を特定 → 上記4つの修正を実施
テスト実行 → データ抽出成功(93行取得)
Streamlit起動 → グラフ表示成功 🎉
学んだこと
HTMLの構造は目視で確認するまでわからない
エラーメッセージから原因を推測する力が重要
小さなテストスクリプトで素早く検証
AIは仮定が間違っていても、データを見せれば修正してくれる
続く
書いている人について
投稿者の紹介です。
noteでは、次の3つを軸に、日々の学びや記録を残しています。
Python・AI
趣味の開発で試したこと、つまずいた点、学びの記録健康・からだ
自分自身の不調や気づきをもとにした、学びと養生の記録生まれ故郷への想い
新潟・妙高(小局)にまつわる歴史や記憶を残すための記録
👉 マイペースで続けている記録はこちら
👉アプリ開発に関するマガジン
