#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ 和风天气(QWeather)客户端 —— 实时天气 + 今日温区。 和风要求使用「用户专属 API Host」(控制台-设置查看 https://console.qweather.com/setting), 用 API Key 鉴权(请求头 X-QW-Api-Key);响应体 Gzip 压缩需手动解压,且返回 code 为字符串。 免费订阅额度足够墨水屏每日推送。HOST/KEY 通过环境变量配置,未配置时调用方回退占位。 接口(参考 https://dev.qweather.com/docs/api/): - GET /v7/weather/now?location=经度,纬度 实时天气(now.text 中文天气 / now.temp 温度) - GET /v7/weather/3d?location=经度,纬度 逐日预报,取 daily[0] 的今日 tempMin/tempMax """ import gzip import json import urllib.request import urllib.error import config def _get(path): if not config.QWEATHER_HOST or not config.QWEATHER_KEY: raise RuntimeError("未配置 QWEATHER_HOST / QWEATHER_KEY") host = config.QWEATHER_HOST.rstrip("/") if not host.startswith("http"): host = "https://" + host headers = {"X-QW-Api-Key": config.QWEATHER_KEY, "Accept-Encoding": "gzip"} req = urllib.request.Request(host + path, headers=headers, method="GET") try: with urllib.request.urlopen(req, timeout=30) as resp: raw = resp.read() except urllib.error.HTTPError as e: raise RuntimeError(f"HTTP {e.code}: {e.read().decode('utf-8', 'ignore')[:200]}") from e if raw[:2] == b"\x1f\x8b": # gzip magic number,和风默认压缩 raw = gzip.decompress(raw) data = json.loads(raw.decode("utf-8")) if str(data.get("code")) != "200": # 和风 code 为字符串 raise RuntimeError(f"{path} 返回 code={data.get('code')}") return data def get_now() -> dict: """实时天气:now.text(中文天气)/ now.temp(摄氏温度)。""" return _get(f"/v7/weather/now?location={config.WEATHER_LOCATION}")["now"] def get_today() -> dict: """今日逐日预报:daily[0] 含 tempMin / tempMax。""" return _get(f"/v7/weather/3d?location={config.WEATHER_LOCATION}")["daily"][0] if __name__ == "__main__": print("now: ", json.dumps(get_now(), ensure_ascii=False)[:300]) print("today:", json.dumps(get_today(), ensure_ascii=False)[:300])