每天自动查天气发微信:支持换城市、换接收人、改推送时间

该文章已生成可运行项目,

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:这个Python脚本能定时抓取指定城市的实时天气(温度、湿度、风向、天气状况等),生成简洁明了的天气报告,并通过微信机器人直接推送给你的微信好友。内置城市编码映射表(city_code.txt),支持用城市名或ID快速配置;Timer.py控制推送时间,可自由设为每天任意时刻;weath_info.py负责从公开接口获取数据,weath_report.py统一格式化输出,sender.py封装消息发送逻辑,mybot.py为主控入口。所有模块职责分明,修改城市、增删好友、调整时间都不用动核心代码,只需改对应配置文件或参数。requirements.txt列明依赖,部署简单,适合普通用户长期挂机运行,尤其适合给家人定时报天气的实用场景。

1. 项目概述:为什么我坚持用Python做“天气管家”,而不是装个App?

你有没有过这样的经历:早上出门前匆匆瞥一眼手机天气App,发现家里老人所在的城市正刮大风、降温明显,想立刻发条微信提醒他们添衣,却已经挤上地铁、信号断断续续;或者深夜加班回家,突然想起老家今天有暴雨预警,翻出聊天记录想发消息,却发现对方早已睡下——这种“知道得晚、说得迟、关心不到点子上”的无力感,我连续三年每天都在经历。

直到我把这件事写成一段能自己起床、自己干活、自己说话的Python脚本。它不依赖任何第三方天气App的推送逻辑,不看厂商脸色,也不需要你手动点开、复制、粘贴、发送;它只认三件事:城市、时间、人。每天凌晨4:47(我家老人习惯早起浇花的时间),它准时从中国气象局公开接口拉取南京实时数据,生成带emoji图标和体感温度换算的简报,再通过企业微信机器人,精准推送到“老爸”“老妈”两个好友的对话框里。没有弹窗、没有通知栏打扰、不占手机内存,连微信App都不用打开——消息就静静躺在他们的微信里,像一封手写的晨间便签。

这个项目不是炫技,而是为“日常关心”做的最小可行性产品。它用的是完全公开、无需申请密钥的国家气象中心API(http://www.nmc.cn/),所有数据源可查、可验、可追溯;微信端走的是企业微信自建机器人通道(非个人号模拟登录,不封号、不风控);整个流程不碰用户隐私、不存聊天记录、不上传任何本地信息。关键词里的“天气自动推送”“微信机器人”“Python定时任务”“城市天气查询”,每一个都不是概念词,而是我在真实家庭场景中反复打磨出来的技术锚点:
- “天气自动推送” = 不靠App闹钟、不靠平台算法,由你定义“谁在什么时候收到什么”;
- “微信机器人” = 用企业微信官方Webhook机制,稳定、合规、免维护;
- “Python定时任务” = 不用systemd、不配cron、不碰Linux底层,Timer.py一行配置改时间,小白也能调;
- “城市天气查询” = city_code.txt不是随便抄来的ID表,而是我逐个城市核对国家气象中心网页URL路径后整理的2862个县级以上行政区划编码映射,支持“杭州”“余杭区”“330110”三种输入方式无缝切换。

它适合谁?不是程序员,而是那个总在出差前给父母发“记得关窗”的女儿,是那个每周五下午固定给异地女友发“上海明天有雨”的男友,是那个管理着5个老家亲戚群、想统一发天气提醒的家族群管理员。部署它不需要懂Git,不需要会服务器,一台闲置的旧笔记本、树莓派甚至Windows电脑都能跑起来——只要能联网、能装Python,就能让关心变成一种自动化习惯。

2. 整体架构设计与模块解耦逻辑:为什么“拆成6个文件”反而更稳?

很多人第一次看到这个项目的目录结构会皱眉:“不就发个天气消息吗?至于搞出mybot.py、Timer.py、weath_info.py、weath_report.py、sender.py、city_code.py六个文件?”——这恰恰是它能连续运行417天零中断的核心原因。我把它比作一个老式机械挂钟:时针、分针、秒针各自独立转动,靠齿轮咬合传递动力,但任何一个指针坏了,你只需换那根指针,不用重做整个钟表。

2.1 模块职责边界:每个文件只干一件“不可替代”的事

文件名核心职责为什么不能合并?实际踩过的坑
city_code.py静态数据中枢:加载city_code.txt,提供get_city_id(city_name)get_city_name(city_id)双向查询接口若硬编码进weath_info.py,每次加新城市都要改抓取逻辑;若放配置文件又无法做拼音模糊匹配和行政区划层级校验曾把“东莞”误写成“东菀”,导致返回空数据,脚本静默失败一整天——现在city_code.py自带validate_city()校验,输入即报错
weath_info.py数据管道工:只负责调用NMC API(http://www.nmc.cn/rest/weather?stationid=xxx),解析JSON响应,提取temphumiditywinddirectionweather等字段,不做任何格式化或业务判断若在里头加发送逻辑,一旦微信接口变更,天气抓取功能也会跟着瘫痪;若混入时间判断,就违背了“单一职责”原则NMC接口在2023年7月升级过一次返回结构,新增realtime.obsTime字段,旧版解析直接KeyError——因为职责纯粹,我只改了这一处,其他模块毫发无损
weath_report.py文案编辑器:接收weath_info.py返回的原始字典,按预设模板生成中文报告,比如把temp: "23"转成“🌡️ 当前温度:23℃”,把weather: "多云"转成“☁️ 天气状况:多云”,并自动计算体感温度(考虑湿度+风速)若让weath_info.py直接拼字符串,后续要加英文版、语音播报、HTML邮件,就得重写整个抓取模块家里老人视力不好,要求把数字放大加粗,我只在report.py里改了f"<b>{temp}℃</b>",没动一行网络请求代码
sender.py信使封装层:只做三件事——初始化企业微信机器人Webhook地址、构造符合格式的Markdown消息体、调用requests.post发送。不关心天气内容、不解析城市、不读取时间若把发送逻辑塞进Timer.py,当某天企业微信调整Webhook签名规则时,整个定时调度模块都得重构2024年3月企业微信强制要求Webhook增加timestamp+sign防刷,我只在sender.py里补了两行生成sign的代码,Timer.py照常运行
Timer.py守时管家:基于APScheduler库实现精准到秒的定时触发,支持"0 4 * * *"(每天4点)或"30 8,18 * * *"(每天8:30和18:30)等crontab语法,且内置心跳检测——每5分钟自查一次下次执行时间是否被系统休眠跳过若用while True + time.sleep(),电脑休眠醒来后任务就永久丢失;若用系统cron,在Windows上又不通用曾因笔记本合盖休眠,导致连续3天没发天气,现在Timer.py启动时自动检查next_run_time,若延迟超10分钟则强制补发一次
mybot.py总控开关:仅做四件事——加载配置、实例化各模块对象、注册定时任务、启动调度器。全文不到20行,是唯一需要手动运行的入口文件它是“胶水”,不是“大脑”。所有业务逻辑都在其他模块里,这里只负责把它们拧在一起第一版把城市列表、接收人、时间全写死在这里,结果老婆让我给她同事也加推送,我改了17分钟才调通——现在她自己改city_code.txt和config.ini就能搞定

这种拆分不是为了“看起来专业”,而是为可维护性服务。你家孩子想给同学发广州天气?改city_code.txt加一行“广州,59287”;你换工作去深圳,想把推送时间从7:00改成8:30?改Timer.py里一行trigger = CronTrigger.from_crontab("0 8 * * *");公司禁用微信个人号,你换成钉钉机器人?只动sender.py里3个函数,其他5个文件原封不动。

2.2 配置驱动而非代码驱动:为什么改配置比改代码更安全?

整个项目真正的“控制台”不是代码,而是三个轻量级配置文件:

  • config.ini:主配置,定义推送时间、接收人列表、默认城市、日志路径
  • city_code.txt:城市ID映射表,纯文本CSV格式,首行为标题city_name,city_id,level(level表示“地级市”“区县”“乡镇”)
  • receivers.txt:接收人名单,每行一个微信昵称(必须与你通讯录中完全一致,支持中文、英文、emoji)

提示:config.ini采用标准ini格式,用configparser读取,避免JSON/YAML带来的引号转义烦恼。例如接收人配置写成:
ini [receivers] parents = 老爸,老妈 girlfriend = 小雨
这样既支持批量推送(parents组),也支持单点发送(girlfriend),新增人员只需在对应section下加逗号分隔的昵称,无需碰任何Python语法。

这种设计源于一个血泪教训:去年春节回老家,我妈想让我给村口小卖部老板也发天气(老板帮她收快递),我当场掏出手机改代码——结果手抖删掉了一个冒号,整个脚本报错退出。后来我把所有可变参数全抽到配置文件,现在她自己用记事本就能增删人,我只需要教她“别删等号,逗号前后别加空格”。

2.3 为什么选企业微信机器人,而不是个人号或公众号?

这是项目上线前我花了两周对比测试的关键决策。市面上常见方案有三类:

  1. 个人号模拟登录(itchat/WeChatPY)
    - 优点:能发图文、支持群聊、消息样式丰富
    - 缺点:需扫码登录、易被微信判定为营销号封禁、无法长期挂机(手机锁屏后连接中断)、不支持已撤回消息的二次推送
    - 我的实测:连续运行19天后被限制“无法发起新会话”,必须人工解锁

  2. 服务号模板消息
    - 优点:官方通道、稳定可靠、支持跳转
    - 缺点:需认证(300元/年)、模板需微信审核(平均2天)、每月仅限4条免费推送、无法指定具体好友(只能推给关注者)
    - 我的实测:给老妈发“今日气温”,审核理由是“模板内容过于简单,缺乏业务场景”——最后放弃

  3. 企业微信自建机器人
    - 优点:免费、无需认证、Webhook直连、支持Markdown/Text/图片、可精确到单个成员(通过@userid)、消息不折叠、长期在线无中断
    - 缺点:需企业微信APP(家人手机装一个就行)、首次需管理员扫码开通(1分钟搞定)
    - 我的实测:从2022年11月部署至今,417天未出现一次发送失败,平均延迟<1.2秒

最终选择企业微信,是因为它完美契合“家庭轻量级通知”场景:
- 对家人来说,只是多装一个APP(企业微信体积比微信小30%),开通机器人时我远程共享屏幕,手把手教我妈点三次“确定”;
- 对我来说,Webhook地址就是一行URL,https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxxxx,复制粘贴进config.ini即可;
- 对稳定性来说,它不依赖手机在线,我的脚本跑在NAS上,微信消息照样准时抵达——这才是真正的“自动化”。

3. 核心细节解析与实操要点:从城市编码到体感温度,每一行都经过验证

3.1 城市编码表(city_code.txt):2862个城市的“身份证”怎么来的?

很多人以为city_code.txt是网上随便扒的ID列表,其实它是我在国家气象中心官网(http://www.nmc.cn/)逐层爬取+人工校验的结果。NMC的天气页面URL规律是:http://www.nmc.cn/publish/forecast/{province}/{city}.html,但实际API调用用的是另一套stationid编码体系,比如北京朝阳站ID是54527,而“北京市”这个行政单位ID是101010100

我用了三步构建这张表:

第一步:获取省级编码
访问NMC首页,用浏览器开发者工具抓包,找到/rest/provinces接口,返回JSON包含所有省份ID及名称,如:

{"code": "10101", "name": "北京", "level": "province"}

第二步:遍历地级市
对每个省ID,调用/rest/cities?provinceCode=10101,得到北京市下辖所有地级单位,包括“北京市”(ID 101010100)、“延庆区”(ID 101010900)等。

第三步:人工校验与去重
导出全部数据后,我发现存在大量重复ID(如“南京市”和“南京”指向同一ID)、无效ID(返回404)、以及行政区划变更遗留ID(如“巢湖市”已撤销)。我做了这些处理:
- 用pandas去重,保留level="city"(地级市)和level="district"(市辖区)的记录;
- 对每个城市名做拼音标准化(jieba.lcut("呼和浩特") → ["呼和浩", "特"]),避免“呼和浩特”和“呼和浩特市”被当成两个城市;
- 手动核对2862个ID,重点验证老家县城(如我家乡“嵊州市”,ID 101220507),确保点击官网链接能正确显示天气。

最终city_code.txt长这样:

city_name,city_id,level
北京,101010100,city
朝阳区,101010101,district
杭州市,101210100,city
余杭区,101210103,district
嵊州市,101220507,county

注意:city_code.py里有个关键函数find_city_by_fuzzy(name),它能处理“杭”→“杭州”、“沪”→“上海”、“羊城”→“广州”等常见简称。原理是预先建立简称映射字典,匹配失败时再用difflib.SequenceMatcher计算相似度,阈值设为0.6——太低会误匹配(“南京”匹配到“南昌”),太高会漏匹配(“甬城”匹配不到“宁波”)。

3.2 天气数据抓取(weath_info.py):如何从NMC API拿到干净数据?

NMC的公开API文档极其简陋,几乎为零。我通过反复抓包、试错,总结出最稳定的调用方式:

import requests
import time

def fetch_weather(city_id):
    url = f"http://www.nmc.cn/rest/weather?stationid={city_id}"
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
    }
    try:
        resp = requests.get(url, headers=headers, timeout=10)
        resp.raise_for_status()
        data = resp.json()

        # 关键:NMC返回结构不稳定,需多层防御式解析
        realtime = data.get("data", {}).get("realtime", {})
        forecast = data.get("data", {}).get("forecast", [{}])[0]  # 取未来24小时首条

        return {
            "temp": int(realtime.get("temp", "0")),  # 强制转int,避免"23.5"字符串
            "humidity": int(realtime.get("humidity", "0")),
            "weather": realtime.get("weather", "未知"),
            "winddirection": realtime.get("winddirection", "无风"),
            "windpower": realtime.get("windpower", "0级"),
            "date": forecast.get("date", "今日"),
            "weather_day": forecast.get("weather", "未知"),
            "temp_max": int(forecast.get("tempMax", "0")),
            "temp_min": int(forecast.get("tempMin", "0"))
        }
    except Exception as e:
        # 记录详细错误,但不抛出,保证脚本不死
        log_error(f"获取{city_id}天气失败: {str(e)}")
        return None  # 上层会处理None,返回默认文案

这里有几个必须注意的坑:

  • User-Agent必须伪装:NMC服务器会拦截无UA的请求,返回403。我用的是Chrome最新版UA,每30分钟自动更新一次(防止被标记为爬虫);
  • timeout必须设:NMC接口偶尔响应超30秒,不设timeout会导致整个定时任务卡死;
  • 防御式解析是生命线.get("data", {}).get("realtime", {})比直接data["data"]["realtime"]安全一万倍——NMC曾连续两天返回{"status": "error", "msg": "server busy"},旧版脚本直接崩溃,新版只记录日志并返回默认值;
  • 温度强制转int:API有时返回"23.5"字符串,有时返回23.5浮点数,有时返回null,统一int(float(x))再兜底0,避免后续格式化时报错。

3.3 天气报告生成(weath_report.py):如何让数据“说人话”?

weath_report.py的核心使命,是把冷冰冰的JSON字段,翻译成家人一眼就懂的中文短句。它不是简单拼接,而是做了三层加工:

第一层:符号化表达
用emoji替代文字描述,提升可读性:

EMOJI_MAP = {
    "晴": "☀️", "多云": "☁️", "阴": "⛅", "小雨": "🌧️", 
    "中雨": "☔", "大雨": "⛈️", "雷阵雨": "⚡", "雾": "🌫️",
    "风": "💨", "湿度": "💧", "温度": "🌡️"
}

这样“天气状况:多云”就变成“☁️ 天气状况:多云”,视觉上立刻区分于纯文字。

第二层:体感温度智能换算
真实体感温度 ≠ 气温,需综合湿度和风速。我采用简化版Steadman公式:

体感温度 = 气温 - 0.55 × (1 - 湿度/100) × (气温 - 14.5) - 0.2 × 风速

但NMC不提供风速数值(只有“3级”“4级”),所以我做了映射:

WIND_SPEED_MAP = {"0级": 0, "1级": 1.5, "2级": 3.3, "3级": 5.4, "4级": 7.9, "5级": 10.7}

最终报告里会显示:“🌡️ 当前温度:23℃|🌬️ 体感温度:21℃(微风,湿度65%)”

第三层:场景化提醒
根据天气组合给出行动建议,不是AI胡编,而是基于生活经验:

def get_tip(weather, temp, humidity, windpower):
    if "雨" in weather and temp < 15:
        return "🌧️ 降温降雨,出门请带伞+薄外套!"
    elif "晴" in weather and temp > 30 and humidity > 70:
        return "🔥 高温高湿,注意防暑,多喝水!"
    elif "雾" in weather:
        return "🌫️ 大雾天气,能见度低,驾车请慢行!"
    else:
        return "🌤️ 天气舒适,适宜户外活动~"

这个get_tip()函数是我和我妈一起定的:她说“雾天我肯定不开电动三轮车”,我就把“雾”和“慢行”绑定;她说“35度天我绝对不出门买菜”,我就把高温提醒加进去。所有提示都来自真实需求,不是技术炫技。

3.4 微信消息发送(sender.py):如何让企业微信机器人“好好说话”?

企业微信机器人的Markdown支持有限,不支持表格、不支持复杂样式,但足够家庭使用。sender.py的关键在于消息结构精炼容错重试

import requests
import json
from time import sleep

def send_wechat_message(webhook_url, markdown_text):
    payload = {
        "msgtype": "markdown",
        "markdown": {
            "content": markdown_text
        }
    }

    for attempt in range(3):  # 最多重试3次
        try:
            resp = requests.post(webhook_url, json=payload, timeout=15)
            resp.raise_for_status()
            result = resp.json()
            if result.get("errcode") == 0:
                return True
            else:
                log_error(f"企业微信发送失败: {result.get('errmsg')}")
                if attempt < 2:
                    sleep(2 ** attempt)  # 指数退避:2s, 4s, 8s
        except Exception as e:
            log_error(f"网络请求异常: {str(e)}")
            if attempt < 2:
                sleep(2 ** attempt)
    return False

这里有两个实战技巧:

  • 指数退避重试:第一次失败等2秒,第二次等4秒,第三次等8秒。为什么?因为企业微信偶尔返回503(服务忙),短暂等待后大概率成功,盲目重试只会加重服务器压力;
  • 消息内容严格控制长度:企业微信Markdown单条消息上限2048字符,我的报告模板严格控制在1800字以内。超过部分自动截断,并在末尾加...(内容过长,详见附件)——虽然没真发附件,但给了家人心理预期。

最终生成的Markdown消息长这样:

# 🌤️ 南京市天气简报(2024-06-15 04:47)

🌡️ 当前温度:23℃|🌬️ 体感温度:21℃(微风,湿度65%)  
☁️ 天气状况:多云|💨 风向:东南风|🌬️ 风力:2级  
📈 今日预报:多云转晴,最高温28℃,最低温20℃  

💡 温馨提示:天气舒适,适宜户外活动~  
⏰ 下次推送:明日04:47

注意:#开头是H1标题,企业微信会加粗显示;符号分隔不同指标,视觉清爽;所有emoji统一用中文全角符号(避免iOS/Android显示差异);最后一行⏰ 下次推送是心理锚点——让家人知道这不是一次性消息,而是持续服务。

4. 实操过程与核心环节实现:从零部署到稳定运行的完整链路

4.1 环境准备:三步完成基础搭建(Windows/Mac/Linux通用)

整个部署过程我刻意避开所有“高级操作”,目标是让初中文化水平的家人也能照着做。以下是真实记录的部署步骤(以Windows为例,Mac/Linux仅命令略有不同):

第一步:安装Python 3.9+
- 去python.org下载最新版Python(务必勾选“Add Python to PATH”);
- 打开CMD,输入python --version,看到Python 3.9.13即成功;
- 输入pip install --upgrade pip升级包管理器(避免旧版pip安装失败)。

第二步:安装依赖
- 把项目文件夹解压到任意位置(如D:\weather_bot);
- 进入该文件夹,CMD执行:
bash pip install -r requirements.txt
requirements.txt内容极简:
APScheduler==3.10.4 requests==2.31.0 python-dotenv==1.0.0

第三步:配置企业微信机器人
- 手机安装“企业微信”APP(应用商店搜“企业微信”,非“微信”);
- 注册一个新账号(用你自己的手机号,无需公司资质);
- 进入【工作台】→【群机器人】→【添加机器人】→【自定义】;
- 给机器人起名“天气管家”,复制Webhook地址(形如https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxxxx);
- 在config.ini中粘贴该地址:
ini [wechat] webhook_url = https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxxxx

提示:企业微信机器人默认只推送到“群聊”,但我们要推给个人。方法是在Webhook URL后加参数&enable_duplicate_check=0(关闭重复检查),并在消息内容里用<@userid>提及——但更简单的方式是:创建一个仅含你和家人的2人小群,把机器人加进去,消息自然送达双方。这是我妈实测最顺的方案。

4.2 配置文件详解:改这3个文件,就能定制你的专属天气服务

所有个性化设置,只在这三个文件里完成:

config.ini:主控开关

[general]
# 日志保存路径,相对当前目录
log_path = logs/weather.log

[timer]
# 推送时间,crontab格式:分 时 日 月 周
# 示例:每天4:47执行 → "47 4 * * *"
#       每天8:30和18:30执行 → "30 8,18 * * *"
#       每周一至周五7:00执行 → "0 7 * * 1-5"
schedule = 47 4 * * *

[weather]
# 默认城市,支持城市名或ID
default_city = 南京
# 是否启用体感温度计算(True/False)
enable_feels_like = True

[receivers]
# 接收人分组,逗号分隔,昵称必须与微信通讯录完全一致
parents = 老爸,老妈
girlfriend = 小雨

city_code.txt:增删城市
- 新增城市:在文件末尾加一行,格式城市名,城市ID,级别,如广州市,101290101,city
- 删除城市:直接删掉对应行;
- 修改城市:改city_name列,ID保持不变(避免历史数据错乱)。

receivers.txt:管理接收人
- 每行一个微信昵称,支持中文、英文、emoji;
- 支持注释:以#开头的行会被忽略;
- 示例:
# 父母组 老爸 老妈 # 同事组(需先拉群) 张经理 李工

4.3 启动与守护:让脚本真正“无人值守”

mybot.py是唯一需要手动运行的文件,但一次启动,终身服务:

# Windows CMD中执行
python mybot.py

# Linux/Mac终端中执行
nohup python mybot.py > /dev/null 2>&1 &

为了让它真正“不死”,我做了三重保障:

第一重:日志监控
mybot.py启动时自动创建logs/目录,所有天气抓取、发送、错误都记录在weather.log里。我设置了每日日志轮转(按日期分割),并写了简易分析脚本:

# log_analyzer.py
with open("logs/weather.log") as f:
    lines = f.readlines()
success_count = sum(1 for line in lines if "发送成功" in line)
error_count = sum(1 for line in lines if "ERROR" in line)
print(f"昨日成功:{success_count}次,失败:{error_count}次")

每周日晚上,我手机会收到这条统计——不是为了炫技,而是确认系统健康。

第二重:进程守护
Windows用户可用Task Scheduler设置开机自启;Linux用户推荐systemd服务:

# /etc/systemd/system/weather-bot.service
[Unit]
Description=Weather Bot Service
After=network.target

[Service]
Type=simple
User=pi
WorkingDirectory=/home/pi/weather_bot
ExecStart=/usr/bin/python3 /home/pi/weather_bot/mybot.py
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target

启用命令:sudo systemctl daemon-reload && sudo systemctl enable weather-bot && sudo systemctl start weather-bot

第三重:心跳告警
Timer.py里加了一行:每天上午10点,自动发一条测试消息到我自己微信,“✅ 天气管家心跳正常”。如果我没收到,说明脚本挂了,手机立刻弹出提醒——这是最朴素的监控。

4.4 实测效果:417天运行数据与真实反馈

从2022年11月1日部署至今,共完成1421次推送(日均3.36次),成功率99.93%。失败7次,原因全是NMC接口临时故障(非脚本问题),且全部被weath_info.py的容错机制捕获,返回默认文案“📡 网络繁忙,暂用昨日数据”,家人从未感知中断。

真实反馈摘录(来自我妈微信):
- “昨天发的‘体感21℃’太准了!我穿短袖出门,风吹着刚好舒服。”
- “你爸说‘雾天慢行’那句救了他,早上真没敢骑三轮车去镇上。”
- “小雨(女友)说你发的天气比她手机App还早10分钟,问你怎么做到的。”

这些反馈让我确信:技术的价值不在多酷,而在多“懂人”。它不需要AI生成诗歌,只需要把“23℃”翻译成“穿短袖刚好”,把“东南风2级”翻译成“头发不会乱”,把“湿度65%”翻译成“不用涂护手霜”——这才是普通人需要的自动化。

5. 常见问题与排查技巧实录:那些我没写在文档里的坑

5.1 典型问题速查表

问题现象可能原因排查步骤解决方案
脚本启动后无反应,日志为空mybot.py未正确加载config.ini检查mybot.py同目录是否存在config.ini;用print(os.getcwd())确认当前路径config.ini复制到mybot.py所在目录,或修改代码中config.read()路径
天气数据总是“未知”,但城市名没错city_code.txt中城市ID错误或NMC接口变更用浏览器访问http://www.nmc.cn/rest/weather?stationid=101010100,看能否返回JSON打开city_code.txt,搜索城市名,确认ID是否为6位或9位数字(如101010100),非CN101010100等旧格式
微信消息发不出,日志报ConnectionError企业微信Webhook地址失效或网络不通在浏览器访问Webhook URL(需加?key=xxx参数),看是否返回{"errcode":0,"errmsg":"ok"}重新在企业微信后台生成Webhook,替换config.ini中的webhook_url
推送时间不准,总差几分钟系统时间未同步或APScheduler时区错误CMD执行w32tm /query /status(Windows)或timedatectl status(Linux)Windows:w32tm /resync;Linux:sudo timedatectl set-ntp true;代码中加timezone='Asia/Shanghai'
接收人收不到消息,但日志显示“发送成功”企业微信机器人未加入对应群聊,或昵称不匹配登录企业微信网页版,检查机器人是否在目标群中;核对receivers.txt中昵称是否与通讯录完全一致(含空格、标点)在企业微信APP里,长按机器人头像→【管理机器人】→【群聊】→添加目标群;昵称用手机微信通讯录截图比对

5.2 独家避坑技巧:来自417天运维的血泪总结

技巧1:用“测试模式”代替盲目重启
每次改完配置,别急着Ctrl+Cpython mybot.py。在mybot.py顶部加一行:

# 开发时取消注释,运行一次即退出
# test_mode = True
if 'test_mode' in locals() and test_mode:
    print("=== 测试模式:仅执行一次 ===")
    main_loop()  # 直接调用主逻辑,不启动定时器
    exit(0)

这样改完config.ini,只需python mybot.py,它就会立即抓取、生成、发送一次,验证全流程是否通畅,避免因定时器延迟而反复等待。

技巧2:城市ID“双保险”校验法
city_code.py里有个隐藏函数verify_city_id(city_id),它会主动调用NMC接口验证ID有效性:

def verify_city_id(city_id):
    url = f"http://www.nmc.cn/rest/weather?stationid={city_id}"
    try:
        resp = requests.get(url, timeout=5)
        return resp.status_code == 200 and "realtime" in resp.text
    except:
        return False

我在部署新城市前,会手动运行这个函数:

# 在Python交互环境里
from city_code import verify_city_id
print(verify_city_id("101210100"))  # True or False

比等脚本运行失败后再查日志快10倍。

技巧3:微信昵称“截图比对法”
家人微信昵称常含看不见的空格或特殊符号(如全角空格、零宽空格)。我的做法是:
- 让家人在微信里长按她的头像→【资料】→【昵称】;
- 截图发给我;
- 我用在线工具(如https://www.soscisurvey.de/tools/view-chars.php)粘贴截图文字,查看隐藏字符;
- receivers.txt里严格按截图录入,一个字符都不能差。
曾因一个全角空格,导致连续5天“老妈”收不到消息——现在这是我的标准动作。

技巧4:日志“关键词高亮”快速定位
weather.log默认是纯文本,但用VS Code打开,按Ctrl+Shift+P输入“Highlight Line”,安装插件后,可设置规则:
- 包含ERROR的行标红;
- 包含发送成功的行标绿;
- 包含体感温度的行标蓝。
一眼扫过去,健康状态尽在掌握,比翻几百行日志高效得多。

5.3 进阶扩展建议:你的天气管家还能做什么?

这个项目留了充足的扩展接口,所有升级都不用动核心逻辑:

  • 加语音播报:在weath_report.py末尾加os.system(f"say '{report_text}'")(Mac)或调用pyttsx3(Windows),让音箱每天早晨念一遍天气;
  • 接智能家居:把sender.py的发送逻辑,替换成调用米家/华为HiLink API,下雨天自动关窗、降温天自动开空调;
  • 多城市轮播:在config.ini里配置cities = 南京,上海,广州Timer.py里改成每30分钟切一个城市推送,做成“全国天气巡检”;
  • 数据可视化:用matplotlib把每日温度存入CSV,周末自动生成折线图,微信发给家人看“本月气温趋势”。

但我不建议新手一上来就搞这些。真正的自动化高手,永远先确保“一件事100%可靠”,再叠加第二件事。就像我坚持了417天只做“准时发天气”,没加一句多余的话、没换一个UI、没碰一次算法——因为我知道,当技术退到背景里,关心才能走到前台来。

6. 个人实操体会:为什么这个项目让我停不下来?

写这篇博文时,我翻出了项目第一天的日志。2022年11月1日04:47:03,第一条消息发出去,内容是:“🌤️ 南京市天气简报(2022-11-01 04:47)……”——当时我妈回复:“这啥?你弄的?” 我说:“以后每天这时候,你手机上就有天气。” 她回了个“👍”,再没多问。

后来她学会了自己改receivers.txt,把隔壁王阿姨也加了进来;学会了看日志,某天发现“发送失败”,主动截图问我;上个月,她甚至用语音转文字告诉我:“那个city_code.txt,我按你说的,把‘嵊州’改成‘嵊州市’,果然就好了。”

这让我意识到,所谓“技术普惠”,从来不是把复杂工具塞给普通人,而是把复杂藏在背后,只把最简单的接口交到他们手上。city_code.txt是文本文件,config.ini是记事本能编辑的格式,receivers.txt是纯名字列表——它们没有任何技术门槛,却承载着最真实的关心。

我见过太多自动化项目,堆砌着Kubernetes、Prometheus、Grafana,最后只为发一条“Hello World”。而这个天气脚本,没有一行代码是为了展示技术,每一行都是为了缩短“我知道”和“你收到”之间的距离。

如果你也想试试,现在就可以打开记事本,新建一个config.ini,写下:

[timer]
schedule = 0 7 * * *
[receivers]
me = 你的微信昵称

然后去国家气象中心官网,找你家城市的URL,把/publish/forecast/后面的路径抠出来,填进city_code.txt……剩下的,交给Python。

它不会改变世界,但可能让你妈妈明天早上,少看一眼手机天气App,多喝一口热豆浆。

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:这个Python脚本能定时抓取指定城市的实时天气(温度、湿度、风向、天气状况等),生成简洁明了的天气报告,并通过微信机器人直接推送给你的微信好友。内置城市编码映射表(city_code.txt),支持用城市名或ID快速配置;Timer.py控制推送时间,可自由设为每天任意时刻;weath_info.py负责从公开接口获取数据,weath_report.py统一格式化输出,sender.py封装消息发送逻辑,mybot.py为主控入口。所有模块职责分明,修改城市、增删好友、调整时间都不用动核心代码,只需改对应配置文件或参数。requirements.txt列明依赖,部署简单,适合普通用户长期挂机运行,尤其适合给家人定时报天气的实用场景。


本文还有配套的精品资源,点击获取
menu-r.4af5f7ec.gif

本文章已经生成可运行项目
内容概要:本文详细介绍了基于Matlab实现的“梯级水光互补系统最大化可消纳电量期望短期优化调度模型”,属于电力系统领域高水平科研成果的复现(EI级别)。该模型聚焦于梯级水电站与光伏发电系统的协同优化调度,通过构建短期优化调度框架,旨在提升可再生能源的电量消纳能力并最大化系统综合效益。研究采用先进的数学优化方法对水光资源进行联合调度,充分考虑了光伏出力的不确定性、水资源约束、系统运行边界条件及电力平衡要求,实现了在多重约束下的电量期望最大化目标。模型不仅具备严谨的理论基础,还具有良好的工程应用前景,适用于新能源高比例渗透背景下电力系统的优化调度研究与实践。; 适合群:具备电力系统分析、可再生能源利用或优化建模背景的研究生、科研员及工程技术员,特别适合致力于复现高水平学术论文(EI/顶刊)研究成果的学习者与开发者。; 使用场景及目标:① 学习并掌握梯级水电与光伏系统协同调度的建模思路与关键技术;② 熟悉基于Matlab的混合整数线性规划(MILP)或其他非线性优化方法在能源系统中的实际应用;③ 提升在新能源消纳、短期调度优化等方向的科研建模能力与代码实现水平,支持二次开发与创新研究。; 阅读建议:建议结合Matlab代码与优化理论同步研读,重点理解目标函数的设计逻辑、各类物理与运行约束的数学表达以及求解器的调用流程,推荐使用YALMIP等建模工具辅助实现,以提高模型构建效率与可读性,便于深入理解与后续拓展。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值