China Weather

👤 Bingo 📦 v1.0.3 ⭐ 4.3 ⬇️ 798 下載
🏠 生活服務 免費

📖 技能介紹

China Weather

中國天氣查詢工具,支援即時天氣、天氣預報、空氣質量、生活指數,提供豐富的資料和精美的排版輸出。

Features

  • 🌤️ 即時天氣: 當前天氣狀況、溫度、溼度、風向
  • 📅 天氣預報: 7天/15天天氣預報
  • 🌫️ 空氣質量: AQI指數、PM2.5、PM10
  • 🧥 生活指數: 穿衣、紫外線、運動、洗車指數
  • 🔄 API降級: 多個免費API自動切換
  • 🎨 精美排版: 專業格式輸出
  • 🌍 多語言: 中英文支援

Trigger Conditions

  • "查天氣" / "Check weather"
  • "明天天氣怎麼樣" / "What's the weather tomorrow"
  • "北京天氣" / "Beijing weather"
  • "空氣質量" / "Air quality"
  • "天氣預報" / "Weather forecast"
  • "china-weather"

API Strategy (介面策略)

認證方式說明

推薦訪問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

Step 1: Install Dependencies

pip install requests

Step 2: Weather Query Script

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

API Configuration (介面配置)

和風天氣 (推薦)

# 註冊: https://dev.qweather.com
# 免費額度: 1000次/天
export QWEATHER_API_KEY="your_key_here"

OpenWeatherMap

# 註冊: https://openweathermap.org/api
# 免費額度: 1000次/天
export OPENWEATHER_API_KEY="your_key_here"

心知天氣

# 註冊: https://www.seniverse.com
# 免費額度: 無限制(基礎資料)
export SENIVERSE_API_KEY="your_key_here"

wttr.in (無需API Key)

# 直接使用,無需註冊
curl "wttr.in/Beijing?format=j1"

Data Fields (資料欄位)

Current Weather (即時天氣)

欄位 說明 單位
temp 溫度 °C
feels_like 體感溫度 °C
weather 天氣狀況 文字
humidity 溼度 %
wind_dir 風向 方位
wind_speed 風速 km/h
visibility 能見度 km
pressure 氣壓 hPa

Air Quality (空氣質量)

欄位 說明 單位
aqi 空氣質量指數 0-500
pm25 PM2.5濃度 μg/m³
pm10 PM10濃度 μg/m³
so2 二氧化硫 μg/m³
no2 二氧化氮 μg/m³
co 一氧化碳 mg/m³
o3 臭氧 μg/m³

Life Index (生活指數)

指數 說明 等級
穿衣指數 建議穿著 寒冷/涼爽/舒適/炎熱
紫外線指數 UV強度 弱/中等/強/很強
運動指數 適合運動程度 適宜/較適宜/不宜
洗車指數 適合洗車程度 適宜/較適宜/不宜
感冒指數 感冒風險 低/中/高

Security Notes

  • ✅ No data uploaded to external servers (except API calls)
  • ✅ Open source dependencies
  • ✅ Multiple API fallback
  • ⚠️ API keys should be kept secure

Notes

  • wttr.in 免費無需API Key,功能較簡單
  • 和風天氣資料最豐富,需要註冊
  • 多API降級策略確保服務可用性
  • 支援中英文天氣描述

🤖 AI 評測

這是一款功能豐富的中文天氣查詢工具,支援即時天氣、預報、空氣質量和生活指數查詢。最大優點是操作簡單,無需配置即可查詢天氣,如果主服務不可用還會自動切換備用介面。介面排版清晰美觀,中英文都能用。但部分高階功能(如空氣質量、生活指數)需要註冊第三方賬號才能完全使用,整體文件和實際程式碼存在一些小不一致,對普通使用者來說可能造成困惑。總的來說基礎功能實用可靠,適合日常天氣查詢使用。

📊 多維度評分

適應性4.3
規範性4.1
有效性4.3
可靠性4.2
可信度5

📁 包含檔案 (3 個)

📄 LICENSE.txt 901 B
📄 SKILL.md 14.8 KB
📄 _meta.json 136 B