feat: implement multi-source weather data collection functionality with OpenWeatherMap, Visual Crossing, and METAR APIs.

This commit is contained in:
2569718930@qq.com
2026-02-08 18:09:37 +08:00
parent ad97efcc4b
commit accdb5104b
2 changed files with 80 additions and 8 deletions
+30 -8
View File
@@ -276,6 +276,8 @@ def start_bot():
msg_lines.append(f"\n📊 <b>Open-Meteo 7天预测</b>")
nws = weather_data.get("nws", {})
nws_high = nws.get("today_high")
mgm = weather_data.get("mgm", {})
mgm_high = mgm.get("today_high")
for i, (d, t) in enumerate(zip(dates[:7], max_temps[:7])):
# 跳过无效数据
@@ -285,17 +287,37 @@ def start_bot():
day_label = "今天" if d == city_today_str else d[5:]
indicator = "👉 " if d == city_today_str else " "
# 如果是今天且有 NWS 数据,显示模型对比
if d == city_today_str and nws_high is not None:
diff = abs(t - nws_high)
if diff > 1:
msg_lines.append(f"{indicator}{day_label}: 最高 {t}{temp_symbol} ⚠️")
msg_lines.append(f" (NWS官方预报: {nws_high}{temp_symbol},差异 {diff:.1f}°)")
else:
msg_lines.append(f"{indicator}{day_label}: 最高 {t}{temp_symbol} (NWS: {nws_high}{temp_symbol})")
# 如果是今天且有 NWS 或 MGM 数据,显示模型对比
comp_lines = []
if d == city_today_str:
if nws_high is not None:
diff_nws = abs(t - nws_high)
warning = " ⚠️" if diff_nws > 1 else ""
comp_lines.append(f"{indicator}{day_label}: 最高 {t}{temp_symbol}{warning}")
comp_lines.append(f" (NWS官方预报: {nws_high}{temp_symbol},差异 {diff_nws:.1f}°)")
elif mgm_high is not None:
# 安卡拉 MGM 对比
diff_mgm = abs(t - mgm_high)
warning = " ⚠️" if diff_mgm > 1 else ""
comp_lines.append(f"{indicator}{day_label}: 最高 {t}{temp_symbol}{warning}")
comp_lines.append(f" (MGM官方预报: {mgm_high}{temp_symbol},差异 {diff_mgm:.1f}°)")
if comp_lines:
msg_lines.extend(comp_lines)
else:
msg_lines.append(f"{indicator}{day_label}: 最高 {t}{temp_symbol}")
# MGM 官方实测显示
if mgm:
mgm_curr = mgm.get("current", {})
mgm_temp = mgm_curr.get("temp")
if mgm_temp is not None:
msg_lines.append(f"\n🏛️ <b>MGM 官方实测 ({mgm_curr.get('station_name', 'Ankara')})</b>")
msg_lines.append(f" 🌡️ {mgm_temp}°C (湿度: {mgm_curr.get('nem', mgm_curr.get('humidity'))}%)")
msg_lines.append(f" 💨 风速: {mgm_curr.get('wind_speed_kt')}kt")
if mgm_curr.get("rain_24h"):
msg_lines.append(f" 🌧️ 24h降水: {mgm_curr.get('rain_24h')}mm")
if metar:
icao = metar.get("icao", "")
metar_temp = metar.get("current", {}).get("temp")
+50
View File
@@ -319,6 +319,50 @@ class WeatherDataCollector:
logger.error(f"METAR 数据解析失败 ({icao}): {e}")
return None
def fetch_from_mgm(self, istno: str) -> Optional[Dict]:
"""
从土耳其气象局 (MGM) 获取实时数据和预测 (由用户提供其内部 API)
"""
base_url = "https://servis.mgm.gov.tr/web"
# 必须带 Origin,否则会被反爬拦截
headers = {
"Origin": "https://www.mgm.gov.tr",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
}
results = {}
try:
# 1. 实时数据
obs_resp = self.session.get(f"{base_url}/sondurumlar?istno={istno}", headers=headers, timeout=self.timeout)
if obs_resp.status_code == 200:
data = obs_resp.json()
if data:
latest = data[0] if isinstance(data, list) else data
# MGM 数据字段映射
results["current"] = {
"temp": latest.get("sicaklik"),
"humidity": latest.get("nem"),
"wind_speed_kt": round(latest.get("ruzgarHiz", 0) * 1.94, 1) if latest.get("ruzgarHiz") is not None else None,
"wind_dir": latest.get("ruzgarYon"),
"rain_24h": latest.get("toplamYagis"),
"time": latest.get("veriZamani"),
"station_name": latest.get("istasyonAd")
}
# 2. 每日预报
daily_resp = self.session.get(f"{base_url}/tahminler/gunluk?istno={istno}", headers=headers, timeout=self.timeout)
if daily_resp.status_code == 200:
forecasts = daily_resp.json()
if forecasts and isinstance(forecasts, list):
today = forecasts[0]
results["today_high"] = today.get("enYuksekGun1")
results["today_low"] = today.get("enDusukGun1")
return results if "current" in results else None
except Exception as e:
logger.error(f"MGM API 请求失败 ({istno}): {e}")
return None
def fetch_nws(self, lat: float, lon: float) -> Optional[Dict]:
"""
从 NWS (美国国家气象局) 获取高精度预报
@@ -653,6 +697,12 @@ class WeatherDataCollector:
if metar_data:
results["metar"] = metar_data
# 对安卡拉,额外获取 MGM 官方数据
if city_lower == "ankara":
mgm_data = self.fetch_from_mgm("17128")
if mgm_data:
results["mgm"] = mgm_data
# 对美国城市,额外获取 NWS 高精预报
if use_fahrenheit:
nws_data = self.fetch_nws(lat, lon)