用PHP实现每日自动推送微信天气:模板消息与定时任务实战

发布时间:2026/10/15 16:23:00

用PHP实现每日自动推送微信天气:模板消息与定时任务实战 简介围绕微信公众号每日定时推送场景这份资源整理了完整的制作教程与可运行代码面向想给伴侣或亲友推送天气、纪念日提醒、且具备少量编程基础的读者。压缩包内共5个文件以 Python 主程序为核心配合文本配置文件、Markdown 说明文档和 GitHub Actions 工作流文件覆盖了 API 接入、消息模板、定时触发与依赖管理各环节可帮助理解从天气/星座数据获取、消息模板拼接到云端定时自动运行的全链路实现。资源包仅5KB体积虽小但方案完整、可操作性强除最新完整版外还附带简化版、星座版、星座天气版及PHP版等多个变体方便按不同需求直接选用。已有7692人学习下载可见这类实用通知场景需求不小直接参考成品代码与消息模板即可快速搭建属于自己的每日推送服务省去从零调试的时间。1. 这个教程在解决什么每天一封天气早安送进微信里早上睁开眼第一件事不是看微信而是打开天气App看一眼今天要不要带伞——这个动作你一定不陌生。如果你还想顺便给在意的人问声好那每天重复这套动作其实挺繁琐的先查天气再想几句话再复制粘贴发出去。时间一长这事大概率就坚持不下来了。这个项目做的事情就是把整个流程自动化通过 PHP 脚本定时去天气接口拉取当日天气数据再调用微信公众号的消息推送接口在每天早晨把「早安 今日天气 出行提醒」打包成一条模板消息直接推到对方的微信里。你只需要做一次配置之后每天固定时间自动发送甚至你本人睡过头了问候也不会缺席。说白了这是一个「接口对接 定时任务」的典型实战项目。它不复杂但把微信公众号开发中最常用的三个环节——获取访问凭证、调用模板消息接口、外部数据源接入——完整走了一遍。适合的人群也很明确有一点 PHP 基础、想把微信开发真正落地一次的人以及那些很想表达关心但总是坚持不下来的朋友。接下来我就把从零到跑通的全过程拆开讲清楚你可以照着做也可以把它改造成自己的版本。2. 核心链路微信推送是怎么打通天气数据的2.1 整体架构两个外部接口 一个定时任务整个系统包含三个参与者你的服务器跑脚本的地方、天气数据源、微信公众平台。三者之间没有任何页面交互全部通过 HTTP 请求完成数据交换。你的服务器 (每天9点执行 PHP 脚本) ├── 请求天气接口获取城市当日天气温度、天气现象、风力 ├── 请求微信接口获取 access_token凭证 └── 组装模板消息 → 请求微信发送接口 └── 微信服务器 → 推送到目标用户微信这里有一个常见误区微信的模板消息不是「你的服务器直接发给用户微信」而是你的服务器先告诉微信服务器「我要发一条这样的消息」再由微信服务器推送给用户。所以你的服务器必须能访问公网或者至少能访问微信接口域名否则整个链路根本走不通。2.2 两个关键接口的选择逻辑天气数据源我选了支持城市模糊搜索、返回 JSON 格式、免费额度够个人使用的接口这类接口在实名认证后每天有足够的免费调用次数。一次推送只调一次天气接口完全没有成本压力。微信侧需要两个接口配合获取 access_token 的接口和模板消息发送接口。前者需要你在公众号后台配置 IP 白名单后者需要提前在后台开通「模板消息」功能并选用一个模板。这两个接口是微信开发的老面孔文档里参数写得清楚但实际调用时容易在参数名上翻车后面避坑那章我会细说。2.3 PHP 脚本在整条链路里的位置PHP 在这里不承担任何 UI 职责它就是一个纯 CLI 脚本按顺序调接口、拼字符串、发请求。我选择 PHP 的原因是教程面向的读者大多是做网站开发出身的PHP 的环境几乎不用额外装一个curl扩展就能跑起来。你要换成 Python 写逻辑完全一样只是语法层面的翻译。脚本的核心流程固定为五步读取配置城市、用户 openid、模板 ID、密钥请求天气接口拿到 JSON解析 JSON提取天气现象、温度区间、风力组装模板消息的数据结构调用微信发送接口看返回码判断是否成功这五步里最容易出问题的是第 4 步——模板消息对参数结构要求极严格多一层嵌套或少一个字段都会报错而且报错信息比较晦涩。我在第 3 章会把这部分的完整代码贴出来逐段讲。3. 代码逐段拆解从天气数据到微信消息的完整实现3.1 配置与初始化把该变的东西全部拎出来我先定义了一个配置区把账号、城市、模板这些每次都可能调整的东西集中管理不让散落在代码各处。?php // push_daily_weather.php // 用法php push_daily_weather.php // 配置区按需修改 $config [ app_id 你的AppID, // 公众号后台基本配置里获取 app_secret 你的AppSecret, // 公众号后台基本配置里获取 template_id 你的模板ID, // 模板消息功能中选用模板后可见 user_openid 接收人的openid, // 用户关注公众号后在聊天记录里可获取 city 杭州, // 城市名称天气接口支持模糊匹配 region 浙江-杭州, // 用于模板消息中的展示文本 tip 今天也要元气满满哦, // 自定义问候语每天可改 ]; // 1. 获取微信公众号 access_token function getAccessToken($appId, $appSecret) { $url https://api.weixin.qq.com/cgi-bin/token?grant_typeclient_credentialappid . $appId . secret . $appSecret; $result json_decode(fileGet($url), true); // 如果返回结果里有 access_token 字段说明获取成功 if (isset($result[access_token])) { return $result[access_token]; } // 失败时把错误信息打到日志里便于排查 file_put_contents(./error.log, date(Y-m-d H:i:s) . token获取失败: . json_encode($result) . PHP_EOL, FILE_APPEND); return null; }这段代码里做了两件重要的事一是把配置单独拎出来二是封装了一个带日志记录的 token 获取函数。grant_typeclient_credential是微信固定的参数不需要改动app_id和app_secret必须从公众号后台「基本配置」里复制注意不是小程序的那对密钥很多人在这一步复制错了导致一直报 40001 错误。fileGet是一个统一封装 HTTP GET 请求的函数稍后和第 4 步的发送函数放在一起避免代码里到处重复 curl。3.2 获取天气数据解析 JSON 并转换成友好文本天气接口返回的是标准 JSON里面字段很多但我真正需要的只有三个天气现象、最高/最低温度、风力等级。解析时要注意健壮性接口偶尔会返回没有「result」字段的错误 JSON这时要给用户提示而不是让脚本直接报错。// 2. 获取指定城市的今日天气 function getWeather($city) { // 这里以某天气接口为例具体 URL 以实际申请的接口文档为准 $url https://api.weather.example.com/v3/weather/now?city . urlencode($city) . key你的天气接口密钥; $result json_decode(fileGet($url), true); // 接口正常时返回码是 200结构一般是 result.realtime if (isset($result[result][realtime])) { $weather $result[result][realtime]; // 部分接口会返回温度区间没有就用当前温度加℃ $temp isset($weather[temperature]) ? $weather[temperature] . ℃ : 未知; $info $weather[info]; // 天气现象描述晴、多云、小雨等 $direct $weather[direct]; // 风向 $power $weather[power]; // 风力如 3级 // 拼成一句适合直接放进模板消息的话 return 今日天气{$info}气温 {$temp}{$direct} {$power}。; } file_put_contents(./error.log, date(Y-m-d H:i:s) . 天气接口返回异常: . json_encode($result) . PHP_EOL, FILE_APPEND); return 今日天气暂无数据出门前记得看一眼窗外。; }这段的逻辑很直接调接口、判空、取字段、拼字符串。需要注意的是urlencode($city)城市名是中文不转义的话某些接口会拒绝请求。返回值设计成了一段可以直接嵌进模板消息的自然语言文本而不是把 JSON 原样塞进去——因为最终这条消息是要推送到人微信里的人读的是句子不是数据结构。3.3 组装模板消息并发送微信接口的参数结构是重点模板消息的请求体结构是微信定的不能乱改。你需要先建一个「模板消息数据」数组第一层是touser、template_id、datadata里的每个字段名必须与你选用的模板关键词一一对应字段值是{ value, color }的结构。// 3. 组装并发送模板消息 function sendTemplateMessage($accessToken, $openid, $templateId, $weatherText, $tip) { // 这里模板关键词是 tutorial 模板自带的天气情况、温馨提示 // 实际字段名要去公众号后台-模板消息-你的模板里查看 $data [ touser $openid, template_id $templateId, url , // 点击消息跳转的链接留空则不跳转 data [ weather [ value $weatherText, color #173177 ], tip [ value $tip, color #000000 ] ] ]; $url https://api.weixin.qq.com/cgi-bin/message/template/send?access_token . $accessToken; $result json_decode(fileGet($url, json_encode($data, JSON_UNESCAPED_UNICODE)), true); // 微信返回码 0 表示发送成功非 0 表示失败 if (isset($result[errcode]) $result[errcode] 0) { return true; } file_put_contents(./error.log, date(Y-m-d H:i:s) . 模板消息发送失败: . json_encode($result) . PHP_EOL, FILE_APPEND); return false; }这里有两个必须强调的细节。第一data里的字段名上面代码里的weather和tip不是随便写的必须和你后台选用的模板「关键词」名称完全对应。比如模板里第一个关键词叫「天气情况」那字段名就要写成weather或其他你在模板里自定义的标识填错了会报 47003 模板参数错误。第二json_encode第二个参数传了JSON_UNESCAPED_UNICODE这是为了让中文在请求体里保持可读状态避免\u6e29这种转义序列引发某些接口解析异常。3.4 统一入口把三个函数串起来最后写一个入口逻辑判断 access_token 获取成功后才继续执行天气获取和发送任何一个环节失败都终止脚本并留下日志。// 4. 主流程 $accessToken getAccessToken($config[app_id], $config[app_secret]); if (!$accessToken) { exit(脚本终止access_token 获取失败请检查日志 . PHP_EOL); } $weatherText getWeather($config[city]); $result sendTemplateMessage( $accessToken, $config[user_openid], $config[template_id], $weatherText, $config[tip] ); echo $result ? 发送成功 . PHP_EOL : 发送失败详见 error.log . PHP_EOL;整个项目就是一个 PHP 文件不到 80 行不依赖任何框架不连数据库没有页面。它的全部职责就是「每天跑一次发出一条消息」。你在命令行执行php push_daily_weather.php能看到输出结果第一次跑通之后剩下的就是让它每天自动执行。4. 部署与定时触发让脚本在每天早晨自动执行4.1 部署位置的选择你的服务器需要能访问外网这个脚本的部署位置没有太多限制只要能执行 PHP 且能访问外网就行。常见的做法是扔在一台便宜的云服务器上或者你自己的一台常开的电脑上。需要注意的一点是微信公众号接口要求调用方 IP 在白名单内而白名单是在公众号后台配置的——如果你家里宽带的公网 IP 不固定那每次 IP 变了都要去后台改一次白名单会比较折腾。所以我在实际部署时更倾向于选择云服务器IP 稳定白名单配一次就行。4.2 配置 crontab定时任务的核心操作定时调度我用的是 Linux 自带的 crontab配置简单没有任何额外依赖。在命令行输入crontab -e在文件末尾加一行保存退出定时任务就生效了。# 每天早上8点30分执行一次天气推送 30 8 * * * /usr/bin/php /www/wwwroot/weather-push/push_daily_weather.php /www/wwwroot/weather-push/run.log 21这行配置的含义是分钟字段填 30小时字段填 8三个星号分别表示「每天、每月、每周」都执行。 run.log 21的意思是把脚本的输出和错误信息都追加到日志文件里这样脚本有没有跑、跑成功了还是失败了都有据可查。我建议每个用 crontab 的人都要养成看日志的习惯定时任务最大的特点是它的失败是「安静失败」——没有弹窗没有报错只是一条本该出现的消息没出现所以日志就成了唯一的排查入口。4.3 另一种方案无服务器定时触发如果你没有云服务器或者不想维护一台常开的机器微信云开发控制台里也有定时触发的能力本质上是把同样的 PHP 脚本包一层云函数入口用云开发的定时触发器来调用。这种方案的好处是不用管服务器坏处是调试起来比本地麻烦。我个人更推荐第一次跑通时先在本地用命令行执行确认整个链路没问题了再上定时或不定期机制否则你会在「脚本本身报错」和「定时配置错误」之间反复横跳很难定位问题。4.4 上线前的自检清单我在部署完脚本后会按下面这个顺序做一遍自检确认万无一失再让它自动跑命令行手动执行三次每次都收到消息才算通过检查 error.log 里有没有 token 获取失败的记录修改系统时间或手动执行一次确认消息内容里没有乱码或缺失字段观察两天确认推送时间正确、内容无异常这套流程走完基本可以放心把脚本交给定时任务。如果中途哪一步出了问题大概率是下面这些原因之一。5. 避坑与常见问题接口报错和消息发不出去的排查记录5.1 排查流程先分清楚是哪一环断了整个链路只有三个环节获取 token、获取天气、发送消息。任何一个环节出错现象都表现为「微信上没有收到消息」。我第一次做的时候犯了个错——上来就检查发送接口折腾半天结果发现是 token 没拿到后续步骤全部白搭。后来我总结出一个固定的排查顺序检查 error.log → 看是 token 失败还是发送失败 ├── token 失败 → 查 appid/secret 是否正确、IP 白名单是否有当前服务器 IP └── 发送失败 → 查返回错误码 ├── 40003 → openid 不正确 ├── 47003 → 模板参数不匹配 └── 45047 → 发送频率超限这个顺序比直接去看微信错误码文档要高效得多因为前三步里每一步失败都会留下日志日志是判断问题方向的第一手材料。5.2 常见问题记录现象、原因与解决问题一返回码 40001「invalid credential」却找不到原因。这个报错说的是 access_token 无效或已过期。现象很迷惑手动测试时明明发送成功了定时任务却报 40001。原因是微信公众号官方要求 access_token 有效期两小时但同一时刻只能有一个有效的 token。如果你在测试时频繁调用获取 token 的接口后一次获取会让前一个 token 失效。解决方法是给脚本加一层 token 缓存把 token 存到文件里过期了再去拿新的而不是每次执行都重新获取。问题二模板消息发送返回 47003 参数不匹配。这几乎是我见过最多的报错现象是返回码 47003 且带一句「argument invalid」。原因分两种要么字段名和模板关键词对不上要么字段值格式不符合模板设置的类型。解决方法是先去公众号后台的模板消息页面把你选的模板点开看它每个关键词的类型要求比如「日期」类型要求值格式是2019年10月1日再回头比对代码里的data结构。不要靠猜后台页面写得明明白白。问题三定时任务执行了但消息没收到。这个坑是 crontab 环境变量导致的。现象是命令行手动执行成功crontab 里却静默失败。原因是 crontab 执行时使用的 PATH 很精简php命令可能不在默认路径里。解决方法是像我第 4 章里写的那样在 crontab 里写全路径/usr/bin/php或者更稳妥地在脚本开头加一段#!/usr/bin/php并用完整路径执行。问题四天气接口免费额度迅速耗尽。如果你是按我 3.2 节的写法每次执行都直接调实时天气接口那一个用户一天只调一次完全够用。但如果你在调试阶段每测一次就调一次免费额度消耗得也很快。解决方法是调试阶段把天气接口返回的 JSON 保存成文件先用本地缓存的 JSON 做开发等逻辑跑通了再换回真实接口。这四条是我在实际部署里真实踩过的坑每条都至少浪费过半小时以上。如果你按本教程复现建议把这一章截图存下来等你在部署时遇到第一个困难你会回来感谢这段记录的。6. 二次开发思路从天气问候变成你的专属小工具跑通之后你手里其实已经握着一个「能定时往微信发消息」的完整通道。通道比天气本身更有价值因为你可以把任何数据源塞进这条通道。6.1 改造一加入节假日与纪念日提醒这是最自然的延伸。在天气接口旁边再调一个节假日接口或者干脆自己在配置文件里写死几个重要日期在sendTemplateMessage之前做一个日期判断当天命中纪念日就在 template 里多塞一个special字段文本写「今天是相识第 1000 天」之类的。// 在 getWeather 之后追加一段 $special ; $days floor((time() - strtotime(2020-06-01)) / 86400); if ($days 0 $days % 100 0) { $special 今天是纪念日 {$days} 天; }这种改造的工作量极小但对收消息的人来说感觉完全不同。6.2 改造二把被动推送改成按需查询模板消息是单向推送你没法让用户发一条「天气」就收到回复。如果你想做成这种交互需要换一种接口思路接入公众号的自动回复能力用户发关键词公众号回复当天天气。核心是把天气逻辑抽出来放到一个独立函数里然后对接消息接收接口。这一步会把项目从「发送」升级到「交互」复杂度会明显上升但这也是公众号开发里更接近生产环境的方向。6.3 改造三多城市支持如果你周围有几个朋友都需要天气推送Configuration 里的city可以改成一个数组循环调用getWeather再循环发送。唯一要注意的是模板消息对同一用户每分钟发送频率有限制多个用户轮流发不会有问题但单个用户高频推送会被限流。把循环体保持在一个用户发一条的水平上就不会触到红线。我从这个项目里学到的最大一条习惯是凡是交给定时任务之前的东西先手动跑三遍凡是涉及外部接口的脚本日志必须留够信息。这两个习惯救过我不少次希望你也能用上。希望帮到你。本文还有配套的精品资源点击获取
延伸阅读

更多相关文章

2026/10/15 16:23:00

让Continuwuity支持语音通话:LiveKit与TURN服务器搭建全攻略

【免费下载链接】continuwuity A community-driven Matrix homeserver 项目地址: https://gitcode.com/gh_mirrors/co/continuwuity 点击查看 免费下载 Continuwuity 是一款社区驱动的开源 Matrix homeserver,但默认开箱并不带语音/视频通话能力。这篇完…

2026/10/15 17:18:27

MFC 嵌入网页实战:CHtmlView 加载与 C++/JS 双向互调

简介:本资源面向使用MFC框架开发桌面应用的C开发者,聚焦CHtmlView类在对话框与HTML、JavaScript交互场景中的实战应用。包内共57个文件,以cpp与h源码、js脚本、html页面、css样式及png/jpg界面素材为主,另含sln解决方案、vcxproj工…

2026/10/15 17:18:27

你的数据在“说谎”吗?趣博思AI的“质检逻辑”值得聊聊

有个学生曾经拿着一份漂亮的回归结果来找我,R接近0.8,p值小于0.01,表格做得工工整整。我问他:“你有没有画过残差图?”他愣住了。 后来我们花了一个下午,发现他的数据里藏着三个极端值,把整条回…

2026/10/15 17:18:27

MATLAB常用信号处理函数清单:从FFT到滤波器实战指南

1. 项目概述:为什么要单独整理一份信号处理函数清单做信号处理这几年,我最大的感受就是:MATLAB的功能强大到让人眼花缭乱,但真正高频使用的函数翻来覆去就那么几十个。很多初学者最容易犯的毛病,是一上来就抱着几百页的…

2026/10/15 17:18:27

拓扑优化入门:99行与88行程序对比及OC与MMA算法解析

简介:这份资源面向拓扑优化初学者与结构优化方向的学生、研究人员,提供一套可直接运行的MATLAB入门程序,涵盖优化准则法(OC)与移动渐近线法(MMA)两种主流求解思路,帮助读者理解如何在…

2026/10/15 17:18:27

Agent Skills 标准实战:用 SKILL.md 让 AI Agent 真正学会干活

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 17:13:26

STM32F4 移植 uCOS-II 实战:从裸机到 RTOS 的完整工程指南

简介:这份资源是面向嵌入式开发者的STM32F4移植UCOS_II完整工程,基于STM32F407ZGT6与Keil μVision环境,解决实时操作系统在Cortex-M4平台上的落地问题。内容涵盖UCOS_II任务调度、信号量、消息队列与内存管理机制,并涉及时钟初始…

2026/10/14 11:31:03

Python调用Gemini Structured Outputs实现工单路由门禁

客服工单最怕的不是模型“答错一句话”,而是它给出一段看起来合理的说明,程序却从中猜错优先级。通俗做法是:要求模型只交 JSON(JavaScript Object Notation,轻量数据格式),再让代码验证它。Gem…

2026/10/14 17:41:07

Spring Boot超市进销存系统毕设实战:从需求拆解到答辩通关

最近带的一个学生项目组里,有A同学跑来问我:选什么毕设题目最稳妥,既能让评审老师觉得工作量够,又不会在答辩时被问到语无伦次。我第一反应就是推荐基于Spring Boot的超市仓库管理系统——也就是超市进销存系统。这个题目乍一看平…

2026/10/15 13:42:16

Flutter StatefulWidget 生命周期核心解析

很多刚开始接触 Flutter 的朋友,在看完一堆“Hello World”和基础组件之后,大概率都会撞上同一堵墙:StatefulWidget 里那堆 initState、build、dispose 方法,到底什么时候被调用?为什么顺序是那样?在里面到…

2026/10/15 0:02:22

防关联浏览器哪个好?三款产品实测差异解析

新手做多店铺,最纠结的就是防关联浏览器选哪个。飞跨、网易、站斧这三款被问得最多,先给结论:要一体化省心、长期便宜,选站斧;要网易招牌和稳,选网易;预算紧做东南亚 Lazada,选飞跨。…

2026/10/15 0:02:22

影刀RPA深度实战:大模型Fine-tuning定制RPA专用Prompt与指令生成

影刀RPA深度实战:大模型Fine-tuning定制RPA专用Prompt与指令生成 一、技术背景 大模型(LLM)在通用场景下表现强大,但当我们将 GPT-4 或 Qwen 直接用于生成影刀RPA操作指令和 XPath 定位时,准确率通常只有 40%-60%。原因…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑