系列:30 天用 Google AI 打造臺灣防災速報 App(Day 2/30)
做 AI 應用,資料永遠是第一步。今天先不碰模型,把「臺灣到底有哪些防災開放資料」一次整理清楚,並實際取得第一批資料。
國家災害防救科技中心(NCDR)彙整了跨部會的即時示警,以國際標準 CAP(Common Alerting Protocol)格式發布。最大的優點:免申請、免金鑰,一個網址直接取得:
https://alerts.ncdr.nat.gov.tw/JSONAtomFeed.ashx
它的格式是 Atom feed(一種網站用來持續發布最新內容的標準格式,訂閱新聞或部落格更新用的就是它)的 JSON 版本,每筆 entry 是一則示警的摘要,並附上完整 CAP 電文的連結。
opendata.cwa.gov.tw 提供地震報告、颱風警報、天氣特報、雨量觀測等 API。需要免費註冊取得授權碼(Authorization key),每個資料集有獨立的資料集編號,例如顯著有感地震報告是 E-A0015-001。明天之後我們會大量使用它。
用 Python 標準庫就夠,不需要任何第三方套件:
import json
import urllib.request
FEED_URL = "https://alerts.ncdr.nat.gov.tw/JSONAtomFeed.ashx"
def fetch_alerts():
req = urllib.request.Request(FEED_URL,
headers={"User-Agent": "disaster-assistant/0.1"})
with urllib.request.urlopen(req, timeout=30) as resp:
feed = json.load(resp)
entries = feed.get("entry", [])
if isinstance(entries, dict): # 只有一筆時會回物件而非陣列
entries = [entries]
alerts = []
for e in entries:
summary = e.get("summary", {})
link = e.get("link", {})
if isinstance(link, list): # 多個連結時回陣列,取第一個
link = link[0] if link else {}
alerts.append({
"id": e.get("id"), # Day 5 去除重複會用到,先原樣保留
"category": e.get("category", {}).get("@term", ""),
"title": e.get("title"),
"updated": e.get("updated"),
"sender": e.get("author", {}).get("name", ""),
"summary": summary.get("#text", "") if isinstance(summary, dict) else str(summary),
"cap_link": link.get("@href", "") if isinstance(link, dict) else "",
})
return alerts
注意 isinstance(entries, dict) 和 isinstance(link, list) 這兩個防呆:這份示警資料是 XML 轉 JSON 的服務,「單筆變物件、多筆變陣列」的形狀不固定是常見陷阱:entry 只有一筆時回物件,link 有多個時回陣列,先知道可避免。另外連續請求會被 429 限流,下載完一輪請間隔 20 秒以上再下載。
我在 9 月 15 日下午實際執行,共下載到 1,094 筆示警,來自 9 個發布單位、16 種分類(下載到的資料量每天都不同):
| 分類 | 筆數 | 主要發布單位 |
|---|---|---|
| 停水 | 570 | 台灣自來水公司 |
| 水庫放流 | 263 | 水利署 |
| 消防安全檢查重大不合格場所 | 126 | 內政部消防署 |
| 火災 | 29 | 內政部消防署 |
| 強風 | 26 | 中央氣象署 |
| 降雨/雷雨 | 33 | 中央氣象署 |
| 淹水 | 13 | 水利署 |
| 疏散避難 | 8 | 內政部消防署 |
| 高溫 | 7 | 中央氣象署 |
| 鐵路事故 | 6 | 臺鐵公司 |
| 地震 | 3 | 中央氣象署 |
| 其他(空氣品質、道路封閉、海洋污染、系統測試) | 10 | 環境部、公路局、海保署、NCDR |
幾個有意思的觀察:
ncdrSystemTest 的系統測試示警,正式系統要把它過濾掉,否則會推播給使用者。另外一個實戰教訓:連續連線這個資料來源會收到 HTTP 429 Too Many Requests。它是公共服務,請勿頻繁請求;之後上 Cloud Functions 排程時,我們會用 10–15 分鐘的間隔輪詢,並把結果快取設定到 Firestore。
明天 Day 3 整理工具箱:Google AI Studio、Gemini API、Stitch、Firebase、Antigravity 各自負責什麼,以及免費額度怎麼精打細算。