中國天氣查詢工具,支援即時天氣、天氣預報、空氣質量、生活指數,提供豐富的資料和精美的排版輸出。
推薦訪問7w4.net獲取更多AI技能。
| API | 認證方式 | 免費額度 | 配置要求 |
|---|---|---|---|
| wttr.in | 無需認證 | 無限制 | ❌ 無需任何配置 |
| 和風天氣 | API Host + Key | 1000次/天 | ✅ 需要API_HOST + API_KEY |
| OpenWeatherMap | API Key | 1000次/天 | ✅ 需要API_KEY + 繫結信用卡 |
| 心知天氣 | API Key | 無限制 | ✅ 需要API_KEY |
推薦:優先使用wttr.in(無需任何配置,免費無限制)
# 優先順序:無需配置 → 需要配置
API_CHAIN = [
{"name": "wttr", "requires_key": False}, # 無需任何配置
{"name": "qweather", "requires_key": True}, # 需要API Host + Key
{"name": "openweathermap", "requires_key": True} # 需要Key + 信用卡
]
和風天氣從2026年起不再支援公共API地址,必須使用專屬API Host:
# 環境變數配置
export QWEATHER_API_HOST="你的API_HOST" # 如:abc1234xyz.def.qweatherapi.com
export QWEATHER_API_KEY="你的API_KEY"
# 正確的API呼叫
curl "https://${QWEATHER_API_HOST}/v7/weather/now?location=101010100&key=${QWEATHER_API_KEY}"
注意:響應使用gzip壓縮,需要新增--compressed引數或在程式碼中處理
API_CHAIN = [
{"name": "qweather", "priority": 1, "fallback": True},
{"name": "seniverse", "priority": 2, "fallback": True},
{"name": "openweathermap", "priority": 3, "fallback": True},
{"name": "wttr", "priority": 4, "fallback": False}
]
def get_weather_with_fallback(city):
"""Try APIs in priority order, fallback on failure"""
for api in API_CHAIN:
try:
result = call_api(api["name"], city)
if result:
return result
except Exception as e:
if api["fallback"]:
continue
else:
raise
return None
pip install requests
python3 << 'PYEOF'
import os
import requests
import json
from datetime import datetime
class WeatherService:
def __init__(self):
self.apis = {
'qweather': QWeatherAPI(),
'seniverse': SeniverseAPI(),
'openweathermap': OpenWeatherMapAPI(),
'wttr': WttrAPI()
}
def get_weather(self, city, days=7):
"""Get weather with fallback strategy"""
for name, api in self.apis.items():
try:
result = api.get_weather(city, days)
if result:
result['source'] = name
return result
except Exception as e:
print(f"⚠️ {name} failed: {e}")
continue
return None
def format_weather(self, data, lang='zh'):
"""Format weather data beautifully"""
if lang == 'zh':
return self._format_chinese(data)
else:
return self._format_english(data)
def _format_chinese(self, data):
"""Chinese format output"""
output = []
output.append(f"┌{'─'*50}┐")
output.append(f"│ 🌤️ {data['city']}天氣預報")
output.append(f"└{'─'*50}┘")
output.append("")
# 當前天氣
output.append(f"📍 當前天氣")
output.append(f"├─ 🌡️ 溫度: {data['current']['temp']}°C (體感 {data['current']['feels_like']}°C)")
output.append(f"├─ 🌤️ 天氣: {data['current']['weather']}")
output.append(f"├─ 💧 溼度: {data['current']['humidity']}%")
output.append(f"├─ 🌬️ 風向: {data['current']['wind_dir']} {data['current']['wind_speed']}km/h")
output.append(f"└─ 👁️ 能見度: {data['current']['visibility']}km")
output.append("")
# 空氣質量
if 'aqi' in data:
output.append(f"🌫️ 空氣質量")
aqi = data['aqi']
aqi_level = self._get_aqi_level(aqi['value'])
output.append(f"├─ AQI: {aqi['value']} ({aqi_level})")
output.append(f"├─ PM2.5: {aqi.get('pm25', 'N/A')}μg/m³")
output.append(f"├─ PM10: {aqi.get('pm10', 'N/A')}μg/m³")
output.append(f"└─ 首要汙染物: {aqi.get('primary', 'N/A')}")
output.append("")
# 未來預報
output.append(f"📅 未來預報")
for day in data.get('forecast', [])[:7]:
output.append(f"├─ {day['date']}: {day['weather']} {day['temp_min']}~{day['temp_max']}°C")
output.append("")
# 生活指數
if 'indices' in data:
output.append(f"🧥 生活指數")
for idx in data['indices'][:4]:
output.append(f"├─ {idx['name']}: {idx['level']}")
return '\n'.join(output)
def _format_english(self, data):
"""English format output"""
output = []
output.append(f"┌{'─'*50}┐")
output.append(f"│ 🌤️ {data['city']} Weather Forecast")
output.append(f"└{'─'*50}┘")
output.append("")
# Current weather
output.append(f"📍 Current Weather")
output.append(f"├─ 🌡️ Temperature: {data['current']['temp']}°C (Feels like {data['current']['feels_like']}°C)")
output.append(f"├─ 🌤️ Weather: {data['current']['weather']}")
output.append(f"├─ 💧 Humidity: {data['current']['humidity']}%")
output.append(f"├─ 🌬️ Wind: {data['current']['wind_dir']} {data['current']['wind_speed']}km/h")
output.append(f"└─ 👁️ Visibility: {data['current']['visibility']}km")
output.append("")
# Air quality
if 'aqi' in data:
output.append(f"🌫️ Air Quality")
aqi = data['aqi']
aqi_level = self._get_aqi_level(aqi['value'])
output.append(f"├─ AQI: {aqi['value']} ({aqi_level})")
output.append(f"├─ PM2.5: {aqi.get('pm25', 'N/A')}μg/m³")
output.append(f"├─ PM10: {aqi.get('pm10', 'N/A')}μg/m³")
output.append(f"└─ Primary: {aqi.get('primary', 'N/A')}")
output.append("")
# Forecast
output.append(f"📅 Forecast")
for day in data.get('forecast', [])[:7]:
output.append(f"├─ {day['date']}: {day['weather']} {day['temp_min']}~{day['temp_max']}°C")
output.append("")
return '\n'.join(output)
def _get_aqi_level(self, aqi):
"""Get AQI level description"""
if aqi <= 50:
return "優 🟢"
elif aqi <= 100:
return "良 🟡"
elif aqi <= 150:
return "輕度汙染 🟠"
elif aqi <= 200:
return "中度汙染 🔴"
elif aqi <= 300:
return "重度汙染 🟣"
else:
return "嚴重汙染 🟤"
class WttrAPI:
"""wttr.in - Free, no API key required"""
def get_weather(self, city, days=7):
url = f"https://wttr.in/{city}?format=j1"
response = requests.get(url, timeout=10)
data = response.json()
current = data['current_condition'][0]
result = {
'city': city,
'current': {
'temp': current['temp_C'],
'feels_like': current['FeelsLikeC'],
'weather': current['lang_zh'][0]['value'] if 'lang_zh' in current else current['weatherDesc'][0]['value'],
'humidity': current['humidity'],
'wind_dir': current['winddir16Point'],
'wind_speed': current['windspeedKmph'],
'visibility': current['visibility']
},
'forecast': []
}
for day in data['weather'][:days]:
result['forecast'].append({
'date': day['date'],
'weather': day['hourly'][4]['weatherDesc'][0]['value'],
'temp_min': day['mintempC'],
'temp_max': day['maxtempC']
})
return result
class QWeatherAPI:
"""和風天氣 - 需要API Host + Key"""
def __init__(self):
self.api_key = os.environ.get('QWEATHER_API_KEY', '')
self.api_host = os.environ.get('QWEATHER_API_HOST', '')
# 預設使用GeoAPI端點
self.geo_url = f"https://{self.api_host}/geo/v2" if self.api_host else ''
self.weather_url = f"https://{self.api_host}/v7" if self.api_host else ''
def get_weather(self, city, days=7):
if not self.api_key or not self.api_host:
return None
# Get city ID
city_id = self._get_city_id(city)
if not city_id:
return None
# Get current weather (with gzip support)
url = f"{self.weather_url}/weather/now?location={city_id}&key={self.api_key}"
response = requests.get(url, timeout=10, headers={'Accept-Encoding': 'gzip'})
response.encoding = 'utf-8'
try:
current_data = response.json()
except:
return None
if current_data.get('code') != '200':
return None
now = current_data['now']
result = {
'city': city,
'current': {
'temp': now['temp'],
'feels_like': now['feelsLike'],
'weather': now['text'],
'humidity': now['humidity'],
'wind_dir': now['windDir'],
'wind_speed': now['windSpeed'],
'visibility': now['vis']
},
'forecast': self._get_forecast(city_id, days)
}
# Get AQI
aqi = self._get_aqi(city_id)
if aqi:
result['aqi'] = aqi
return result
def _get_city_id(self, city):
"""Get city ID from city name"""
url = f"{self.geo_url}/city/lookup?location={city}&key={self.api_key}"
response = requests.get(url, timeout=10, headers={'Accept-Encoding': 'gzip'})
try:
data = response.json()
if data.get('code') == '200' and data.get('location'):
return data['location'][0]['id']
except:
pass
return None
def _get_forecast(self, city_id, days):
"""Get weather forecast"""
url = f"{self.base_url}/weather/7d?location={city_id}&key={self.api_key}"
response = requests.get(url, timeout=10)
data = response.json()
forecast = []
for day in data.get('daily', [])[:days]:
forecast.append({
'date': day['fxDate'],
'weather': day['textDay'],
'temp_min': day['tempMin'],
'temp_max': day['tempMax']
})
return forecast
def _get_aqi(self, city_id):
"""Get air quality index"""
url = f"{self.base_url}/air/now?location={city_id}&key={self.api_key}"
response = requests.get(url, timeout=10)
data = response.json()
if data.get('code') == '200':
air = data['now']
return {
'value': int(air['aqi']),
'pm25': air.get('pm2p5'),
'pm10': air.get('pm10'),
'primary': air.get('primary')
}
return None
# Example usage
service = WeatherService()
# Query weather
data = service.get_weather('Beijing')
if data:
# Format output
output = service.format_weather(data, lang='zh')
print(output)
else:
print("❌ 無法獲取天氣資料")
PYEOF
# 註冊: https://dev.qweather.com
# 免費額度: 1000次/天
export QWEATHER_API_KEY="your_key_here"
# 註冊: https://openweathermap.org/api
# 免費額度: 1000次/天
export OPENWEATHER_API_KEY="your_key_here"
# 註冊: https://www.seniverse.com
# 免費額度: 無限制(基礎資料)
export SENIVERSE_API_KEY="your_key_here"
# 直接使用,無需註冊
curl "wttr.in/Beijing?format=j1"
| 欄位 | 說明 | 單位 |
|---|---|---|
| temp | 溫度 | °C |
| feels_like | 體感溫度 | °C |
| weather | 天氣狀況 | 文字 |
| humidity | 溼度 | % |
| wind_dir | 風向 | 方位 |
| wind_speed | 風速 | km/h |
| visibility | 能見度 | km |
| pressure | 氣壓 | hPa |
| 欄位 | 說明 | 單位 |
|---|---|---|
| aqi | 空氣質量指數 | 0-500 |
| pm25 | PM2.5濃度 | μg/m³ |
| pm10 | PM10濃度 | μg/m³ |
| so2 | 二氧化硫 | μg/m³ |
| no2 | 二氧化氮 | μg/m³ |
| co | 一氧化碳 | mg/m³ |
| o3 | 臭氧 | μg/m³ |
| 指數 | 說明 | 等級 |
|---|---|---|
| 穿衣指數 | 建議穿著 | 寒冷/涼爽/舒適/炎熱 |
| 紫外線指數 | UV強度 | 弱/中等/強/很強 |
| 運動指數 | 適合運動程度 | 適宜/較適宜/不宜 |
| 洗車指數 | 適合洗車程度 | 適宜/較適宜/不宜 |
| 感冒指數 | 感冒風險 | 低/中/高 |
這是一款功能豐富的中文天氣查詢工具,支援即時天氣、預報、空氣質量和生活指數查詢。最大優點是操作簡單,無需配置即可查詢天氣,如果主服務不可用還會自動切換備用介面。介面排版清晰美觀,中英文都能用。但部分高階功能(如空氣質量、生活指數)需要註冊第三方賬號才能完全使用,整體文件和實際程式碼存在一些小不一致,對普通使用者來說可能造成困惑。總的來說基礎功能實用可靠,適合日常天氣查詢使用。