Spaces:
Sleeping
Sleeping
File size: 5,440 Bytes
c0f48f1 e9e401c 8b5bf5f c0f48f1 8b5bf5f 7b108b2 8b5bf5f 2cce2ac 8b5bf5f c0f48f1 a1fc907 c0f48f1 7b108b2 8b5bf5f 7b108b2 8b5bf5f 7b108b2 c0f48f1 8b5bf5f 7b108b2 c0f48f1 8b5bf5f c0f48f1 8b5bf5f 7b108b2 c0f48f1 7b108b2 c0f48f1 8b5bf5f 7b108b2 8b5bf5f c0f48f1 8b5bf5f c0f48f1 8b5bf5f e9e401c c0f48f1 8b5bf5f c0f48f1 8b5bf5f 7b108b2 8b5bf5f c0f48f1 8b5bf5f a1a9f32 8b5bf5f a1a9f32 8b5bf5f c0f48f1 8b5bf5f 2cce2ac 8b5bf5f |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 |
# app.py
from fastapi import FastAPI, HTTPException
from starlette.responses import JSONResponse
import requests
import re
import xml.etree.ElementTree as ET
from datetime import datetime, timedelta, timezone
import logging
import html
# --- 配置日誌 ---
logging.basicConfig(level=logging.INFO)
# --- 初始化 FastAPI 應用 ---
app = FastAPI(
title="台灣地震速報 API",
description="一個從台灣中央氣象署(CWA)公開預警XML Feed中,擷取最新地震速報的API。https://cwadayi-app-show-pws.hf.space/cwa-earthquakes",
version="1.0.0",
)
# --- Geocode 與縣市名稱的對照字典 ---
GEOCODE_MAP = {
"10002": "宜蘭縣", "10004": "新竹縣", "10005": "苗栗縣",
"10007": "彰化縣", "10008": "南投縣", "10009": "雲林縣",
"10010": "嘉義縣", "10013": "屏東縣", "10014": "臺東縣",
"10015": "花蓮縣", "10016": "澎湖縣", "10017": "基隆市",
"10018": "新竹市", "10020": "嘉義市", "63": "臺北市",
"64": "高雄市", "65": "新北市", "66": "臺中市",
"67": "臺南市", "68": "桃園市", "09007": "連江縣",
"09020": "金門縣"
}
# --- 核心功能函式 ---
def get_cwa_earthquakes():
"""
抓取並解析 CWA 地震速報 Feed,回傳結構化的 Python 列表。
"""
timestamp = int(datetime.now().timestamp())
feed_url = f"https://cbs.tw/files/rssatomfeed.xml?_={timestamp}"
keywords = ["中央氣象署", "氣象署"]
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
'Cache-Control': 'no-cache',
'Pragma': 'no-cache'
}
try:
response = requests.get(feed_url, headers=headers, timeout=15)
response.raise_for_status()
xml_content = response.content.decode('utf-8')
xml_content = re.sub(' xmlns="[^"]+"', '', xml_content, count=1)
root = ET.fromstring(xml_content)
earthquake_alerts = []
for entry in root.findall('entry'):
summary_text = ''
for tag_name in ['summary', 'description']:
content_tag = entry.find(tag_name)
if content_tag is not None and content_tag.text:
summary_text = content_tag.text
break
title_tag = entry.find('title')
title = title_tag.text if title_tag is not None else ""
is_earthquake_alert = "地震速報" in title
is_from_cwa = any(keyword in summary_text for keyword in keywords)
if is_earthquake_alert and is_from_cwa:
sent_tag = entry.find('sent')
published_time = sent_tag.text if sent_tag is not None else "N/A"
area_desc = ''
affected_counties = []
area_tag = entry.find('area')
if area_tag is not None:
area_desc_tag = area_tag.find('areadesc')
area_desc = area_desc_tag.text if area_desc_tag is not None else ''
for geocode_tag in area_tag.findall('geocode'):
value_tag = geocode_tag.find('value')
if value_tag is not None:
code = value_tag.text
location_name = GEOCODE_MAP.get(code, f"未知代碼({code})")
affected_counties.append(location_name)
alert = {
"title": html.unescape(title),
"publish_time": published_time,
"summary": html.unescape(summary_text),
"affected_area_desc": html.unescape(area_desc),
"affected_counties": affected_counties
}
earthquake_alerts.append(alert)
return earthquake_alerts
except requests.exceptions.RequestException as e:
logging.error(f"無法從 CWA 取得資料: {e}")
raise HTTPException(status_code=503, detail="無法連接到 CWA 資料來源")
except ET.ParseError as e:
logging.error(f"XML 資料解析失敗: {e}")
raise HTTPException(status_code=500, detail="解析 CWA 資料時發生錯誤")
except Exception as e:
logging.error(f"發生未預期的錯誤: {e}")
raise HTTPException(status_code=500, detail=f"發生內部錯誤: {e}")
# --- API 端點 ---
@app.get("/")
def root():
"""
根目錄端點,提供 API 簡介和範例連結。
"""
return {
"message": "歡迎使用台灣地震速報 API - https://cwadayi-app-show-pws.hf.space/cwa-earthquakes",
"documentation": "/docs",
"earthquake_feed_endpoint": "/cwa-earthquakes"
}
@app.get("/cwa-earthquakes")
async def get_earthquakes_endpoint():
"""
提供最新的地震速報。
https://cwadayi-app-show-pws.hf.space/cwa-earthquakes
此端點會從 CWA 的公開預警 Feed 中擷取資料,
篩選出來自「中央氣象署」的「地震速報」,
並以 JSON 格式回傳。
"""
alerts = get_cwa_earthquakes()
tw_tz = timezone(timedelta(hours=8))
last_updated = datetime.now(tw_tz).isoformat()
return JSONResponse(content={
"last_updated": last_updated,
"source": "台灣中央氣象署 (CWA)",
"alerts": alerts
}) |