name: weather-forecast description: "Use when users ask about weather, weather forecast, temperature, today's weather, tomorrow's weather, this week's weather, or city weather conditions in China. Supports real-time weather, 7-day 3-hour interval forecasts, 15-day forecasts, and 40-day long-term forecasts. Trigger phrases include: 'weather', 'forecast', 'temperature', 'will it rain', 'hourly weather', 'next N days', 'next month'."
查詢中國城市的即時天氣和未來天氣預報。支援即時天氣、逐3小時預報、7天預報、15天預報和40天長期預報。
使用中國天氣網 (weather.com.cn) 的資料:
| 資料型別 | URL | 說明 |
|---|---|---|
| 即時天氣 | https://www.weather.com.cn/data/sk/{城市程式碼}.html |
當前溫度、風向、溼度 |
| 7天預報 | https://www.weather.com.cn/weather/{城市程式碼}.shtml |
含逐3小時預報 |
| 15天預報 | https://www.weather.com.cn/weather15d/{城市程式碼}.shtml |
較詳細的15天預報 |
| 40天預報 | https://d1.weather.com.cn/calendar_new/{年份}/{城市程式碼}_{年份月份}.html |
長期預報 |
| 城市程式碼 | https://j.i8tq.com/weather2020/search/city.js |
城市程式碼查詢 |
| 城市 | 程式碼 | 城市 | 程式碼 |
|---|---|---|---|
| 北京 | 101010100 | 武漢 | 101200101 |
| 上海 | 101020100 | 西安 | 101110101 |
| 廣州 | 101280101 | 杭州 | 101210101 |
| 深圳 | 101280601 | 南京 | 101190101 |
| 成都 | 101270101 | 重慶 | 101040100 |
優先使用已知城市程式碼(見上表)。如果城市不在列表中,從遠端獲取:
import urllib.request, json, re
headers = {'User-Agent': 'Mozilla/5.0'}
req = urllib.request.Request('https://j.i8tq.com/weather2020/search/city.js', headers=headers)
resp = urllib.request.urlopen(req)
text = resp.read().decode('utf-8')
# 解析 city_data
match = re.search(r'var city_data\s*=\s*(\{.*\});', text, re.DOTALL)
city_data = json.loads(match.group(1))
# 搜尋城市
def find_city(city_data, name):
for province, cities in city_data.items():
for city, districts in cities.items():
for district, info in districts.items():
if name in info.get('NAMECN', ''):
return info.get('AREAID')
return None
city_id = find_city(city_data, '北京') # 返回 '101010100'
根據查詢型別選擇合適的API:
import urllib.request, json
headers = {'User-Agent': 'Mozilla/5.0'}
url = 'https://www.weather.com.cn/data/sk/101010100.html'
req = urllib.request.Request(url, headers=headers)
resp = urllib.request.urlopen(req)
data = json.loads(resp.read().decode('utf-8'))
info = data['weatherinfo']
print(f"{info['city']}: {info['temp']}°C, {info['WD']} {info['WS']}, 溼度{info['SD']}")
import urllib.request, json, re, time
headers = {
'Referer': 'https://www.weather.com.cn/',
'User-Agent': 'Mozilla/5.0'
}
def get_40day_forecast(city_id, year_month):
"""獲取指定月份的40天預報資料"""
url = f'https://d1.weather.com.cn/calendar_new/{year_month[:4]}/{city_id}_{year_month}.html?_={int(time.time()*1000)}'
req = urllib.request.Request(url, headers=headers)
resp = urllib.request.urlopen(req)
text = resp.read().decode('utf-8')
# 去掉 JSONP 字首
text = re.sub(r'^var fc40\s*=\s*', '', text)
return json.loads(text)
# 示例:獲取2026年6月資料
data = get_40day_forecast('101010100', '202606')
# 過濾有效預報資料(排除歷史資料)
valid = [d for d in data if d.get('cla') not in ('history', 'obs')]
# 按日期去重(同一日期可能有多條資料,優先保留有w1的)
seen = {}
for d in valid:
date = d.get('date', '')
if date not in seen:
seen[date] = d
elif not seen[date].get('w1') and d.get('w1'):
seen[date] = d
# 查詢特定日期
target_date = '20260627'
if target_date in seen:
day = seen[target_date]
print(f"{day['date']} 周{day['wk']}: {day.get('w1','--')} {day.get('min','--')}~{day.get('max','--')}°C")
資料欄位說明:
| 欄位 | 說明 | 示例 |
|---|---|---|
| date | 日期 (YYYYMMDD) | "20260627" |
| wk | 星期 | "六" |
| w1 | 天氣現象(白天) | "多雲" |
| w2 | 天氣現象(夜間) | "晴" |
| c1 | 天氣圖示程式碼(白天) | "1" |
| c2 | 天氣圖示程式碼(夜間) | "0" |
| max/min | 最高/最低溫度 | "34"/"24" |
| hmax/hmin | 歷史均值溫度 | "32"/"22" |
| hgl | 降水機率 | "33%" |
| rain1 | 降水量(mm) | "0.0" |
| wd1/ws1 | 風向/風力 | "東南風"/"3級" |
| cla | 資料型別 | 見下方說明 |
cla欄位含義:
| cla值 | 說明 | 資料完整性 |
|---|---|---|
d15 pre |
15天預報(今天~3天內) | ✅ 完整(含w1/w2/c1/c2/wd1/ws1) |
d15 |
15天預報(當天) | ✅ 完整 |
d15 next |
15天預報(跨月前幾天) | ✅ 完整 |
d40 |
40天預報 | ⚠️ 無w1/w2,但有hgl/rain1 |
d40 next |
40天預報(跨月) | ⚠️ 無w1/w2,但有hgl/rain1 |
history |
歷史均值 | ❌ 過濾掉 |
obs |
已觀測資料 | ❌ 過濾掉 |
重要:
- 16天后(d40/d40 next)沒有天氣現象文字(w1為空),但有降水機率(hgl)和降水量(rain1)
- 網頁版根據 hgl 值顯示雨圖示:hgl > 50% 顯示大雨,30-50% 顯示中雨,< 30% 顯示小雨或無雨
- 展示時可根據 hgl 推斷降水可能性,如 hgl > 50% 提示"可能有雨"
import urllib.request, json, re
headers = {
'Referer': 'https://www.weather.com.cn/',
'User-Agent': 'Mozilla/5.0'
}
def get_hourly_forecast(city_id):
"""獲取7天逐3小時預報"""
url = f'https://www.weather.com.cn/weather/{city_id}.shtml'
req = urllib.request.Request(url, headers=headers)
resp = urllib.request.urlopen(req)
html = resp.read().decode('utf-8')
# 精確提取 hour3data JSON(通過括號匹配)
start = html.index('var hour3data')
brace_start = html.index('{', start)
depth = 0
end = brace_start
for i in range(brace_start, len(html)):
if html[i] == '{': depth += 1
elif html[i] == '}':
depth -= 1
if depth == 0:
end = i + 1
break
return json.loads(html[brace_start:end])
data = get_hourly_forecast('101010100')
# data['7d'] 是7天資料,每天8個時間點
# data['7d'][0] = 今天, data['7d'][1] = 明天, ...
# 解析單條資料
# 格式: "27日11時,d01,多雲,31℃,東南風,<3級,2"
# 日期時間,天氣程式碼,天氣現象,溫度,風向,風力,降水機率
for item in data['7d'][0]: # 今天
parts = item.split(',')
print(f"{parts[0]} {parts[2]} {parts[3]} {parts[4]} {parts[5]}")
📅 2026年6月27日 週六
🌤️ 多雲轉晴
🌡️ 溫度: 24°C ~ 34°C
💨 風向: 東南風
💧 降水機率: 33%
======================================================================
北京天氣預報 | 2026年6月27日 ~ 7月10日
======================================================================
日期 星期 天氣 溫度 降水機率
----------------------------------------------------------------------
6月27日 週六 多雲 24~34°C 33%
6月28日 週日 晴 24~35°C 50%
...
======================================================================
說明: 16天后為長期預報,僅有溫度範圍
======================================================================
杭州今天逐小時天氣:
08時 多雲 26°C 東南風 <3級
11時 多雲 29°C 東南風 <3級
14時 晴 32°C 南風 <3級
17時 晴 31°C 南風 <3級
20時 晴 28°C 南風 <3級
23時 晴 26°C 西南風 <3級
根據查詢型別選擇資料來源:
| 查詢型別 | 資料來源 | 說明 |
|---|---|---|
| 今天天氣 | 即時天氣 + 7天預報 | 優先使用即時天氣 |
| 明天/後天 | 7天逐3小時預報 | 包含詳細天氣現象 |
| 未來一週 | 7天預報 | 每天一條彙總 |
| 未來15天 | 40天預報(當月API) | 有完整天氣現象 |
| 未來30天 | 40天預報(當月+下月API合併,自動計算月份) | 前15天有天氣現象,16天后只有溫度 |
| 未來40天 | 40天預報(當月+下月+下下月API合併,自動計算月份) | 前15天有天氣現象,16天后只有溫度 |
| 逐小時天氣 | 7天逐3小時預報 | 每3小時一條 |
跨月查詢處理(完整方案):
from datetime import datetime, timedelta
def get_40day_forecast(city_id, year_month):
"""獲取指定月份的40天預報資料"""
import urllib.request, json, re, time
headers = {
'Referer': 'https://www.weather.com.cn/',
'User-Agent': 'Mozilla/5.0'
}
url = f'https://d1.weather.com.cn/calendar_new/{year_month[:4]}/{city_id}_{year_month}.html?_={int(time.time()*1000)}'
req = urllib.request.Request(url, headers=headers)
resp = urllib.request.urlopen(req)
text = resp.read().decode('utf-8')
text = re.sub(r'^var fc40\s*=\s*', '', text)
return json.loads(text)
def get_forecast_data(city_id, start_date, end_date):
"""
獲取指定日期範圍的預報資料。
關鍵邏輯:
- 計算需要請求的月份(可能跨2-3個月)
- 合併所有月份的資料
- 過濾歷史資料(cla=history/obs)
- 按日期去重:同一日期有多條時,優先保留有天氣現象(w1)的
- 篩選目標日期範圍
注意:40天預報API返回的資料範圍有限:
- 當月API:當月剩餘天數 + 下月初約4-5天(共約35天)
- 下月API:上月末3天 + 下月全部 + 再下月初約2天
- 最遠可覆蓋約40天,超出範圍的資料不存在
"""
# 計算需要的月份
months = set()
current = datetime.strptime(start_date, '%Y%m%d')
end = datetime.strptime(end_date, '%Y%m%d')
while current <= end:
months.add(current.strftime('%Y%m'))
# 移到下個月
if current.month == 12:
current = datetime(current.year + 1, 1, 1)
else:
current = datetime(current.year, current.month + 1, 1)
# 獲取所有月份資料併合並
all_data = []
for month in sorted(months):
data = get_40day_forecast(city_id, month)
all_data.extend(data)
# 過濾和去重
valid = [d for d in all_data if d.get('cla') not in ('history', 'obs')]
seen = {}
for d in valid:
date = d.get('date', '')
if date not in seen:
seen[date] = d
elif not seen[date].get('w1') and d.get('w1'):
seen[date] = d
# 篩選日期範圍
result = []
for date_str in sorted(seen.keys()):
if start_date <= date_str <= end_date:
result.append(seen[date_str])
return result
def get_forecast_months(start_date, days):
"""
計算指定天數範圍內需要獲取的月份。
例如:5月31日開始,40天后是7月10日,需要5月、6月、7月共3個月。
"""
start = datetime.strptime(start_date, '%Y%m%d')
end = start + timedelta(days=days)
months = set()
current = start
while current <= end:
months.add(current.strftime('%Y%m'))
if current.month == 12:
current = datetime(current.year + 1, 1, 1)
else:
current = datetime(current.year, current.month + 1, 1)
return sorted(months)
def get_30day_forecast(city_id):
"""
獲取從今天開始的30天預報。
自動計算需要請求的月份(當月+下月,可能需要3個月),合併資料。
返回去重後的日期->資料字典。
"""
today = datetime.now()
today_str = today.strftime('%Y%m%d')
# 計算需要的月份(30天可能跨2-3個月)
months_needed = get_forecast_months(today_str, 30)
all_data = []
for month in months_needed:
data = get_40day_forecast(city_id, month)
all_data.extend(data)
valid = [d for d in all_data if d.get('cla') not in ('history', 'obs')]
seen = {}
for d in valid:
date = d.get('date', '')
if date not in seen:
seen[date] = d
elif not seen[date].get('w1') and d.get('w1'):
seen[date] = d
return seen
def get_40day_forecast_complete(city_id):
"""
獲取從今天開始的40天完整預報。
自動計算需要請求的月份(當月+下月+下下月),合併資料。
返回去重後的日期->資料字典。
注意:API返回的資料範圍有限,最遠約40天。
16天后(d40型別)只有溫度範圍,沒有天氣現象(w1)。
"""
today = datetime.now()
today_str = today.strftime('%Y%m%d')
# 計算需要的月份(40天可能跨3個月)
months_needed = get_forecast_months(today_str, 40)
all_data = []
for month in months_needed:
data = get_40day_forecast(city_id, month)
all_data.extend(data)
valid = [d for d in all_data if d.get('cla') not in ('history', 'obs')]
seen = {}
for d in valid:
date = d.get('date', '')
if date not in seen:
seen[date] = d
elif not seen[date].get('w1') and d.get('w1'):
seen[date] = d
return seen
def infer_weather_from_hgl(hgl):
"""根據降水機率推斷天氣狀況(用於d40資料,沒有w1欄位時)"""
try:
val = int(hgl.replace('%', ''))
if val >= 70:
return '🌧️大雨'
elif val >= 50:
return '🌦️中雨'
elif val >= 30:
return '🌦️小雨'
elif val >= 10:
return '☁️陰'
else:
return '☀️晴'
except (ValueError, AttributeError):
return '—'
def display_forecast(city_name, city_id, days=30):
"""獲取並展示N天天氣預報(通用函式,支援30天或40天)"""
import sys, io
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
if days == 40:
seen = get_40day_forecast_complete(city_id)
else:
seen = get_30day_forecast(city_id)
dates = sorted(seen.keys())
# 只取前N天
display_dates = dates[:days]
print(f"{'=' * 72}")
print(f" {city_name}{days}天天氣預報")
print(f" {display_dates[0][:4]}年{int(display_dates[0][4:6])}月{int(display_dates[0][6:8])}日 ~ "
f"{display_dates[-1][:4]}年{int(display_dates[-1][4:6])}月{int(display_dates[-1][6:8])}日")
print(f"{'=' * 72}")
print(f"{'日期':<12} {'星期':<6} {'天氣':<14} {'溫度':<12} {'降水機率':<10}")
print(f"{'-' * 72}")
for date_str in display_dates:
d = seen[date_str]
month = date_str[4:6]
day = date_str[6:8]
wk = d.get('wk', '')
w1 = d.get('w1', '')
w2 = d.get('w2', '')
max_t = d.get('max', '--')
min_t = d.get('min', '--')
hgl = d.get('hgl', '--')
cla = d.get('cla', '')
# 有w1時使用文字描述,沒有時根據降水機率推斷
if w1:
weather = w1
if w2:
weather += f'轉{w2}'
else:
# d40資料沒有w1,根據hgl降水機率推斷天氣
weather = infer_weather_from_hgl(hgl)
print(f"{int(month)}月{int(day):02d}日 周{wk} {weather:<12} {min_t}~{max_t}°C {hgl}")
print(f"{'=' * 72}")
print(f" 說明:")
print(f" - 前15天有完整天氣現象描述")
print(f" - 16天后為長期預報,根據降水機率推斷天氣狀況")
print(f" - 資料來源:中國天氣網 (weather.com.cn)")
print(f"{'=' * 72}")
def display_30day_forecast(city_name, city_id):
"""獲取並展示30天天氣預報"""
display_forecast(city_name, city_id, days=30)
def display_40day_forecast(city_name, city_id):
"""獲取並展示40天天氣預報"""
display_forecast(city_name, city_id, days=40)
Referer 和 User-Agent 請求頭var fc40 = 字首history 型別資料(應過濾)小蔥技能站7w4.net,專業的AI技能分享平臺。
rain1 > 0 或 hgl > 50% 時,提醒使用者可能下雨°Cget_forecast_data() 函式按日期範圍查詢這個天氣預報 Skill 做得不錯,功能很全面,能查即時天氣、短中期預報和40天長期預報,資料來源可靠。文件寫得很詳細,程式碼可以直接用,常見問題也有說明。不足是缺少實際查詢示例,而且40天預報後半段只有溫度沒有天氣描述這點不夠顯眼,容易讓使用者困惑。總體質量良好,核心功能紮實,但還可以更完善一些。