个人微信机器人开发

2024 年 08 月 17 日

对喜欢折腾的人来说,微信机器人算是个有用的工具。主要是微信随处可得,如果可以接上机器人,就相当于多了一个可以接收命令和发送消息的通道。基于此通道,可以开发各种创意,比如有人接通了 ChatGPT。对于我自己来说,远程开关机,或者做服务器状态通知,都是不错的使用场景。

但是,腾讯对此可没什么好的官方支持。官方提供的所谓创建机器人功能,实际上是跟公众号或小程序绑定,做一些自动发消息和回复的功能。这完全不是开发者所需要的,更不用说动不动就每年 300 元的认证费用了。

不靠官方支持,那就只能自己动手了。还好有很多人已经做出了很多尝试,节约了我很多时间。在此整理一下动手过程中我所了解到的东西。

实现原理

用个人微信号做微信机器人,其问题本质就是,用程序模拟或控制微信客户端

参考微信官网,官方提供了如下正式的客户端:Android/iOS/Windows/macOS,实际上还有 web 客户端可用。

每一种客户端,实际上就是一种通信方式。实现微信机器人时,需要考虑每一种客户端的特点和能力。

根据客户端分别展开之前,有必要提一下 WeChaty。这个项目的想法非常有意思,它抽象出了 puppet 这个概念,每个 puppet 就是一种通信方式。因此它有多种 puppet 对应不同的客户端的通信方式。但如我前面说的,腾讯对此是没有好的官方支持的,因此我认为这个抽象反而是增加了一层麻烦。但由于 WeChaty 出现比较早,而且部分 puppet 也有商业化的运作,所以还是很有借鉴意义。

注意:如果违反了腾讯的规则,很可能会被封号。刑不可知,则威不可测。

Android 客户端

估计这应该是使用量最大的客户端了,但基于此做机器人的方案不多。大概思路一般都是用 Xposed 这种工具去拦截接口。但是这种方案对于技术要求比较高,既要考虑 Android 本身的问题,又要考虑微信版本升级的问题,关键是没有带来任何好处。所以我没有对这种方案做深入研究。

iOS 客户端

这个方案我只注意到 wechatty-puppet-padlocal 在做。使用 WeChaty 客户端,配合这个 puppet 就可以连接微信,开发起来不算困难。

但是要注意,这是一个商业化服务,使用其 API 是要付费的。当然,这不是人家的问题,而是我的问题。因此我没有过多研究。不过付费服务一定有人在维护。从这一点来看,我觉得他们对这个方案的稳定性应该是有信心的。

Windows 客户端

这种方案的原理就是通过 hook 方式跟原始 Windows 客户端通信,因此对 Windows 客户端版本有要求。

缺点主要有以下几个:

  • 必须要在 Windows x64 环境下运行,因此对硬件有要求。
  • Windows 客户端自动更新提示可能会限制程序自动启动。可能影响此功能作为服务实现。
  • 难以多开,不过我没这个需求。

这个方案已经有很多人实现了。我自己有用过 wechaty-puppet-xpwechatferry。个人认为后者实现较好,支持的客户端版本比较新,稳定性也不错。基于后者我还做了一个 rust 应用模板,稍稍扩展后,就是我现在的实现方案了。

macOS 客户端

能搜到几个旧实现,但似乎都没有更新。似乎是大家对这个方案需求都不强烈。我更是连 macOS 都没有,所以不关注了。

Web 客户端

客观讲,如果不是腾讯不做官方支持的原因。这个方案实际上是最佳方案。

这是因为,这个方案是从协议层面解耦的。因此可以用任意语言实现其协议,直接跟微信服务器通信。这样无需考虑硬件平台、操作系统、多进程等诸多限制。

但是,这个方案在现阶段主要存在以下几个问题:

  1. 协议不公开,因此随时可能被更改。
  2. Web 登录方式已经被禁用了,大部分账号是无法通过这种方式简单登录的。
  3. 只有少数项目实现了这个协议,且由于问题 1/2,开源实现未必能正常工作。

对于问题 2,有些项目实现了一些突破。我用我本来不能登录的账号试过,在这个项目上是可以登录的。

总结

基于目前的了解,我选择基于 wechatferry 实现了一个自用的简单机器人,能够连 chatgpt 帮我做一些简单查询。主要是因为开发起来比较省力,从开始到基本完成一共只用了 3 天时间。

但我认为,如果真的打算将此工作做到可以商业化的程度,只能是硬吃下 Web 协议,对要做完成的功能做抽象,然后放在独立服务器上运行。那么这项工作就不是几天就能够完成的了。

P.S. 我最终还是用 Web 协议重新实现了一个微信机器人服务,现在已经可以摆脱 Windows,直接在我的 arm 服务器上跑微信了。由于 openwechat 是 go 语言实现的。在使用 rust 重新实现和学习 go 语言这两个选择之间,我选择了后者。现在我的 go 语言也基本算是达到初级水平了。

Top