微信课表推送:用公众号给自己发上课提醒
微信课表推送:用公众号给自己发上课提醒
大三开始,课表变得有些支离破碎。
作为软件工程专业的学生,前两年的基础课像是一整块密不透风的砖,每天按部就班地坐在固定的教室里就行。但到了大三,专业选修课变多,上课的时间和地点开始变得随机。有时候是周一早上的第一节,有时候是周四下午的最后一节,教室也常常在不同的教学楼之间横跳。
我们学校的教务系统并不好用。每次想看课表,都需要打开那个加载缓慢的校园App,忍受几秒钟的开屏广告,再点进层层叠叠的菜单。早八的早晨本来就兵荒马乱,这种繁琐的交互让人感到一种莫名的焦躁。
我需要一个东西,一个极其简单、没有任何冗余动作的东西。它只需要在每天早上我醒来的时候,安静地躺在手机屏幕上,告诉我今天有什么课,几点上,在哪个教室。
微信应该是最合适的载体。它是所有应用里存活率最高的,不需要额外打开,也不需要刻意去查。
最初的设想是写一个微信机器人。我查阅了 wechaty 的文档,发现现在的微信对个人微信号的自动化管控非常严格,新建的微信号几乎无法通过网页版协议登录,强行使用很容易面临封号的风险。对于一个每天都要用的核心通讯工具来说,这个代价太大了。
后来我把目光转向了微信公众号。
但常规的公众号也走不通。个人订阅号很早以前就被收回了主动推送模板消息的权限,只能用户发一句,它回一句,这不符合我“定时提醒”的需求。而企业号的注册流程又过于繁琐。
在翻阅微信公众平台开发文档的角落时,我找到了一个看似是给开发者临时用的后门——“微信公众平台接口测试帐号”。
这个测试号本来是让开发者在正式申请公众号之前调试接口用的。它不需要营业执照,不需要认证费用,只要用个人微信扫个码就能立刻生成一个 appID 和 appsecret。最关键的是,它拥有几乎所有的接口权限,包括无限制的模板消息推送。
它的唯一缺点是,关注这个测试号的用户上限只有 100 人,且推送的消息会被折叠在“订阅号消息”里。但对于我,或者我的几个室友来说,100 人的额度就像一片广阔的海,完全足够了。
解决了通道的问题,接下来是数据来源。
很多做校园课表应用的人,第一反应都是写个爬虫去抓取学校教务系统的数据。我也试过。但我发现这并不是一个工程学上的好主意。教务系统通常只能在校园局域网内访问,如果要在外网服务器上跑爬虫,就需要处理复杂的 VPN 登录、验证码识别,甚至还要应对学校网络中心不定期的系统升级和接口变动。
我只是想每天早上知道去哪上课,不想给自己找一个需要长期维护的麻烦。
最后我选择了最原始也最可靠的方案:手动录入。我定义了一个 JSON 格式的数据结构,按星期一到星期日把课表存好。包含课名、时间、地点、老师,以及这门课是单周上还是双周上。
每个学期初,花十分钟时间对着教务系统把 JSON 文件填好,接下来的四个月里,它就永远不会出错。这种看似笨拙的静态配置,在个人项目里往往是最优雅的解决方案。
代码是用 Python 写的。逻辑很简单:读取当天的星期数,判断单双周,从 JSON 里提取当天的课程,组装成微信模板消息所需的 payload,然后调用微信的 API 发送。
为了让它看起来更像一个完整的私人助理,我又加了一些零碎的功能。
早上 7:30 发送当天的全天课表。但在实际使用中我发现,如果下午有课,早上 7:30 的提醒到了下午往往已经被遗忘了。于是我加了一个时间判断逻辑,在每节课上课前 30 分钟,再单独推一条这节课的具体信息。
既然每天早上都要推送,不如顺便把天气也带上。我接入了 OpenWeather 的 API。这里踩过一个坑,OpenWeather 对国内部分区县的定位不是很准确,有时传广州市的拼音,返回的却是另一个区域的天气。后来我改成了直接传经纬度,才算稳定下来。
最后,在每天晚上 22:00,我让它推送一句随机的晚安心语。其实没什么实际作用,只是觉得在满是验证码、工作通知和推销信息的微信列表里,能有一个毫无目的的、单纯祝你晚安的机器,是一件挺温情的事。
我不打算为这个脚本买一台云服务器。作为广州商学院的一名普通学生,我习惯了用最少的资源去做事。GitHub Actions 是一个完美的免费计算平台。
我写了一个 YAML 配置文件,利用 GitHub Actions 的 cron 定时任务来触发 Python 脚本。这里有一个时区的问题,GitHub 的服务器默认使用 UTC 时间,和北京时间差了 8 个小时。所以如果要让它在早上 7:30 运行,cron 表达式必须写成前一天的 23:30。
第一天早上,当我在洗漱时,听到手机在洗手台上震动了一下。点亮屏幕,锁屏界面上整整齐齐地列着当天的软件测试课和数据库课的时间地点。那一刻,有一种微小的掌控感。
我把这个仓库整理了一下,写了详细的 README,发给了寝室里的室友。他们只需要扫码关注我的测试号,把生成的 openid 发给我,我填进环境变量里,他们就能享受到同样的推送。
没过几天,三个室友都用上了。每天早上 7:30,寝室里会接连响起几声短促的微信提示音。大家不用再互相问“今天早八在哪个楼”,看一眼手机就各自出门。
后来发生了一件让我意外的事。
有一天,我的 GitHub 邮箱收到了一封邮件,有人给这个名为 WeChatPush 的仓库提了一个 Issue。对方说,天气预报的功能报错了,似乎是广州的 API key 配置在异地调用时出现了权限问题。
我愣了一下,才意识到除了我和室友,已经有我不认识的外地同学在跟着 README 部署这个项目了。
我花了一个晚上的时间,把代码里硬编码的城市信息抽离出来,改成了可以通过环境变量自定义配置的参数,然后回复了他的 Issue。对方很快回了一句谢谢。
在这个只有 7 个 Star 的小仓库里,我看着那个 closed 的 Issue,安静地坐了一会。
在民办三本读软件工程,其实是一件很容易让人产生无力感的事情。不论我的 GPA 保持在 4.02,还是拿了两次国家奖学金,在面对外界的评价体系时,学历的标签总是第一位的。我习惯了靠不断地折腾各种技术、参加各种竞赛来证明自己,试图在简历上多增加一点筹码。
但写这个课表推送脚本的时候,我没有想过任何证明自己的事。它仅仅源于我自己的一个真实的不便,然后我用我学过的知识,把它缝补好了。
它没有用到什么高深的设计模式,也没有复杂的算法,只是一些基础的 API 调用和简单的逻辑判断。但它确实在每天早上 7:30 准时运行着,解决了我自己的问题,并且顺便,也跨越了物理距离,解决了一个我不认识的人的问题。
这大概就是写代码最简单的快乐。不是为了绩点,不是为了奖项,只是因为一行行敲下去的字符,最终变成了一个能在现实世界里运转的齿轮。