作者: @iyjian, 半路出家伪程序员

我是个半路出家的程序员,有一个爱玩信用卡的老婆,老婆总逼着我我参加银行的积分活动,为了节省时间,我用wechaty做了一个积分红包机器人。

产品的模样

以下是流水账格式,先介绍了我有一个什么需求,然后介绍了我怎么找到wechaty的,最后说了一些我用wechaty的心得和遇到的坑。

我用wechaty很巧合。某银行信用卡有个活动,消费会得到一个红包,红包打开有积分,但是分享给朋友后,朋友也可以得到积分。当然也意味着你可以从朋友那里领取他红包里的积分,每天可以从不同的15个朋友那里各领一个红包!

这个活动虽小,可玩的人特别多。虽然银行的本意是希望大家用这种分享红包的方式让更多没有卡的人眼馋这个积分,然后对这个信用卡产生兴趣而来办卡,但是信用卡迷们互相之间交换一下红包也没什么问题啊。奈何大家身边不可能恰巧有这么多有这个信用卡的朋友可以互相交换红包,这些善于折腾的人就发明了微信群,16个人一个群,大家互相在里面发红包交换。产品做出来后我通过腾讯分析搜集到一些用户信息,我不知道腾讯怎么知道这些人的学历的,但这数据要是真的,那你别说这群人挺无聊,可他们学历还挺高,本科的不少呢。

学历分布图--腾讯分析 我老婆呢也是个信用卡迷,没事总喜欢折腾折腾信用卡,她也正好在一个微信群里和微信好友们这样每天不厌其烦的交换着红包,而她也要求我着这样做。可我是个懒人,倒腾这点积分浪费我那么多时间我实在是有点心疼!所以三天两头就会忘记这件事情,弄的群里的人对我都有意见,后来有次和朋友吃饭我就抱怨起这个事情,一个朋友和我推荐说有个微信红包机器人可以简化这件事情,只要把红包发送给机器人,机器人会自动返还给你其他人的红包,我立刻关注去看了下,还真的如他所说,是一个微信个人号在提供这个功能,非常神奇。 我脑子转了转,觉得这个功能并不算太复杂,其实就是个库存系统,然后通过一定的算法来合理的分配,虽然要解决些信用的问题(因为可以作弊)需要费点时间,但是如何实现微信个人号的自动化是个关键问题,我准备着手研究一下。

我自诩是一个数据工程师,但是算算也有5年多没有怎么碰过数据了,我的前同事们很多都在各大公司的大数据部门干活,奈何我折腾不出名堂,才开始对自己并不擅长,怎么学也学不好的编程产生了极大的兴趣,用了五年时间也算入了门,至少可以写出能运行的代码。

说干就干,我首先去github上搜索了微信,wechat等关键字,发现微信个人号的自动化很早就有人做了,从框架的语言上有perl、python、 js、 C#等,从实现原理上最多的是直接用网页版的接口,也有用Android的客户端做钩子的,用iOS客户端做钩子的开源项目倒是没找到,估计都做黑产挣大钱去了吧。

虽然我是个二流的程序员,但是我什么语言都能用,在我眼里无非是if/then/else/for,反正我也没有什么面相对象的思想 ;)。于是我就挑选了一个我还算熟悉的用perl语言做的框架来试验,我写了第一个hello word应用 — 收到一条消息后拼接“你个头!”然后自动回复,于是朋友和我打招呼说“hey”,就会回复 “hey 你个头!”,问我“在吗”就会回复“在吗你个头!”。做完后,我部署到自己的个人号,把朋友们可逗乐好一阵子。至此我认为我已经具备了做一个红包机器人的能力。 如果我决定花时间来做这件事情,我希望这件事情可以长久一点,我把我能找到的框架比较了一下后发现还是wechaty不错,文档清晰,commit很多,star也很多,而且是用比较新颖的typescript写的,说明作者紧跟时代。我看完文档还发现这个作者很用心,他用程序自动获取微信网页版的代码,自动比较代码的diff,如果有改动会弄个什么issue出来,我觉得这样很先进,毕竟这种框架还是很依赖微信,最担心的就是微信整出什么幺蛾子。有这种运营开源项目精神一定值得信赖。

我又找了一个朋友一起玩这个东西,他负责产品设计,我来负责写代码,这样我们都可以专注一点。我们从开始做这件事情到暂时停止使用个人号大概2个多月的时间,最多的时候三台手机同时使用wechaty(因为一个个人号最多5000人就满了),期间发生了太多太多的事情无法一一流水账的记录,但我准备把遇到的一些和wechaty有关以及微信个人号运营可能会碰到的问题写出来和大家分享一下,如有不对的地方,还请大家斧正(刚学的词)。

主动加人

我们刚开始做完整套系统后,没有地方宣传,也没有用户,我们很苦恼,于是跑到信用卡论坛上去找一些人留的二维码来加他们(他们为了找互相分享红包的好友也会留自己的微信在论坛上),我们一个人一个人的推广,结果第一天加了20个人就加不上了,后来查了些资料才发现微信对主动加人有限制,并且对附近的人,摇一摇,扫码等都有各种频率限制,但你的好友基数比较大,或者微信号年龄较大可以拥有多一点的限额。果然,我们坚持了两天后每天可以加到五六十个人,原来这玩意得养啊,后来我们发现很多东西都得养。

被动加人

后来我们做的有点口碑了,已有玩家里也有些有影响力的人开始帮我们宣传,第一次宣传就很厉害,第一天就给我们带来了300多个新用户,这些人加着加着,自动通过好友的功能就不好使了,但是我们可以在手机上点击好友通过,后来因为每天都会有很多人来加我们,所以我们准确的计算出这个功能会崩掉,也就是微信网页版的接口限制为24小时内100人,只要超过100个人,妥妥的不能自动通过好友,那就得傻傻的在手机上一个个点通过。两个月后有一天一个微信号上来了800多个人,这时我们发现点到500个人,手机上也不能点击通过了,而这个封锁的时间达到48小时。这个玩意是不能养的,我们后期没办法,人太多了,不能自动通过的就丢在那里,他愿意再加一遍就再加一遍,不愿意就只能拉倒。

改备注

因为微信网页版里没有太好的办法拿到用户的唯一编号,wechaty上也是建议把用户通过Contact.alias()方法改个备注名来管理,我刚开始也就是简单的用个随机数生成个md5来作为用户的备注名,这样在通讯录列表里虽然看起来有点怪,但是是唯一的。 这样做其实也有个坑,因为这个改名的接口也会崩掉,改太多了就会崩,自动通过好友后如果立刻进行改名会更容易崩,这个接口的频率我们一直到最后也没整明白,因为他总是比自动通过好友的接口要先挂掉,到底什么时候挂也不知道。但是如果自动改名坏掉了,照样可以按照改备注后的名字继续提供服务,因为wechaty内部存储了用户的临时的唯一编号,改名的时候其实是现在wechaty内部的Contact对象里修改,然后同步到网页版上,wechaty和网页版通讯的时候还是通过这个临时唯一编号通讯的,所以只要wechaty不重启,即使改名失败了,仍然不会出问题。但是一旦重启就全乱了。 一旦出现这个问题后,我们就不敢重启了,我们就开始在手机上一个个改名(还是那个问题,网页版接口频率限制了客户端还是可以),一定要改成当初分配给他的那个md5串,这个串在数据库有一份记录。这个是很痛苦的,我们用苹果的电脑和手机之间的云粘贴功能从数据库表里复制到手机上才能快一点,但是每天也要改上一个多小时,眼睛都要看瞎了。

回消息

回消息当然也是有频率限制的,如果你回复的过快,轻则禁言,重则和你的好友互相解除好友关系,我们那次一天来了800多个人的时候就是提示消息回复过快而自动删除了很多好友。但是这个频率也是可以提高的,我们最开始做的1号机器人高峰时每个小时有1万条消息也照样可以处理,我们一个用户一次给微信号发了50条消息,我分别回复了他50条也并没有提示禁言,这算是养出来了。而2号机器人也就是碰到那天来800多个人的时候就一下子顶不住垮掉了。

重启

wechaty在启动的时候会初始化Contact对象,如果联系人比较少,这个过程就很快,根本感觉不出来,如果超过3000个人就可能会出问题。首先这服务器得比较好,开始我就弄了个1核1G普通硬盘的的云服务器,到1000多人的时候Contact就初始化不动了,经常初始化失败,后来我意识到自己可能会有很多号,也会加很多人,就直接用了12核12G固态硬盘的服务器,这样子撑到一台服务器三个微信号,单个号3000人没有出现过问题,但是到了3000多人如果在处理消息高峰时期,也就是一个小时有一万条消息的时候重启,那也是歇菜了,别指望可以初始化成功,我们碰到过好多次,在忙乱之中去翻了一下wechaty的源码,也是没有调试出原因。 关于重启有一些小经验,首先我们有数据统计,知道什么时候不是高峰,那么找非高峰时期来重启。大家看下我们某个微信号的非高峰时间,这真的很痛苦,一般都是重启完才能睡着的。

流量图-腾讯分析

其次,你可以在服务器上对每个微信号启动两份docker,比如bot1, bot1Shadow,对应同一个微信号,这样如果bot1正在运行,需要它重启的时候就去启动bot1Shadow然后扫码把bot1踢下来,这样可以减少宕机时间。另外wechaty的Contact有个findAll方法,可以自己加一个消息指令,比如checkContacts,然后重启好以后发送一下,看看Contacts是不是加载完了,你有这个指令以后就会发现Contacts初始化还是需要一点点时间的,这期间如果根据alias查找联系人是会报错的,可以单独和用户沟通一下:),每次在手机上和用户沟通用户都会很惊讶怎么机器人会说话。

和公众号的互动

我们使用个人号最根本的原因是公众号无法方便的接收图文消息,因为银行的那个活动分享出来的红包是图文消息,用公众号也可以实施但是体验就很差了。但是个人号运营很痛苦,有被腾讯封杀网页版接口的风险,被封杀了会提示你新注册的账号无法使用网页版,这当然是个说辞,来了这个提示你就无法使用wechaty来自动化你的微信了。但是如果你有耐心过段时间时间(大概是一个月)腾讯会解封这个限制,但还是有被封的可能。 有这些痛苦就有了和公众号的互动的想法,我现在还没有开始实施,但是已经有了方案,大致思路是用公众号作为保留客户的基地,然后通过一些方法通知到用户让他们去加个人微信号,这样可以操作的手段就多了,可以做到足够分散和均匀,比如你可以给他发指定的邀请码和个人号二维码,让他在加好友的时候备注这个邀请码,然后个人号收到这个邀请码后再通过,至于如何绑定个人号和公众号,可以通过在个人号的欢迎语里加一个绑定链接,绑定链接带上个人号的临时唯一编号,然后通过公众号的隐式授权获得公众号的openid(我不知道微信公众号这些接口的字段命名为什么这么恶心,为什么不用驼峰式,搞的我代码里一会驼峰一会小写!),然后服务器再去通知wechaty把个人号的备注改成这个openid或者是用户的某个编号。

一些杂七杂八的事情

微信桌面客户端(我用的是mac)和微信网页版对视频poster的提取是不一样的,我的合伙人是个做产品的,他做完视频以后会让poster上显示一个他觉得满意的画面,每次都是mac客户端发给我,看起来都是赞赞的,可是我放到wechaty里发出去以后并不是显示的那一帧poster,找了很久原因才想到两个版本的poster提取方法不一样。 docker容器中默认的时间不是东八区,一定要重新搞一下,我吃了很多亏,数据库和服务器上报的时间不一致,但是我刚写这个东西的时候发现已经支持时区更改了:Add timezone in to Dockerfile。 我开始写代码的时候把业务逻辑和wechaty对微信自动化的逻辑都写到一个项目了,这样维护的时候很痛苦,改动一个业务逻辑就必须重启一次wechaty,会有服务中断,后来把业务逻辑包装成http请求,wechaty里只做简单的收发消息,踢人,拉人,自动好友等操作,把消息发给业务逻辑,然后再得到指令后操作,这样可以维护的方便一点。 群邀请也是需要养的,新建的一个群别指望发群邀请把人拉进来,最开始无法拉人,需要给用户回复一张群二维码让他扫码进群,等人多一点,但是不要等到100个人,因为100个人以后就只能通过邀请才能加人了。

先写这么多吧,最后说一下,我的个人号已经于9月份全军覆没了,正好是我过生日的那天,还是在三亚度假的时候,我整个人都有点懵了,但仔细想想一点都不可惜,有了这些经验东山再起不是什么问题,我和那个产品经理已经重新开始弄公众号了,圈子里有了品牌,用户做起来是分分钟的事情,待把公众号做稳一点了,还是会继续实施上面的公众号和个人号互动的想法,应该没那么容易被封了,不会傻乎乎的一个号上整那么多人,给自己找那么多麻烦了。 以上这么多废话是答应lijiarui小姐9月份写的,可是又要忙工作,又要忙这个娱乐项目,每天都是凌晨2,3点睡觉,6,7点起床,直到现在也如此,实在没有什么完整的时间,对于这种严重的拖延我深表歉意。

最后,谢谢你用这么多时间看了我写的字。