最近有朋友问我,怎么实现一个微信机器人,比如用户可能问一些业务问题,如何自动回复?
我研究了一下这个场景,实现方式也很多,比如通过微信机器人方式。
也有人用微信个人号,有几个选择,但是这种方式我不是很推荐,很多坑。
-
wxpy,支持使用小号来使用它,不过就是python版本比较坑了,只支持
3.4~3.6
。这其实不是主要的,问题在于目前微信已经不支持网页登陆了,只能是老的账号可以用。 - wechaty,这个库使用相对繁琐,没有 wxpy 好用,需要收费。
- WeChatFerry,这个库需要客户端安装微信,其实还好,不算麻烦。但是很多bug,坑多,需要特定的微信版本,但是微信会提示你升级。
网上也有对个人微信号的总结:搭建微信机器人的方案都在这了,一句话,要么收费,要么用坑多的免费版本。
总之:微信号的方式不是官方支持的,坑多慎入,用公众号的方案比较推荐。
需要用到fastapi框架,参见web开发框架-fastapi - 简书。
公众号申请
查看:https://mp.weixin.qq.com/,可以注册一个,注册完后效果:
服务对接
这一步稍微要麻烦一点,需要几个步骤:
1)填写基本信息
主要是开发者密码、白名单的设置。
2) 服务器配置和验证
可以参见文档:微信开发者文档。
微信要求后台的接口是80/443接口。因为linux不允许普通用户以80端口运行,所以呢,如果是普通用户的话,可用这么做:
- 切换到root账号
- 运行如下命令并使之生效
$ vi /etc/sysctl.conf
net.ipv4.ip_forward = 1
# reload
$ sysctl -p /etc/sysctl.conf
- 将80端口转发到8080端口,这样后面服务可以用8080启动了
$ iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080
- 切换回普通账号
- 编写python程序(验证签名有效性)
import hashlib
import os
from fastapi import FastAPI
from starlette.requests import Request
from dotenv import load_dotenv
app = FastAPI()
load_dotenv()
WINXIN_TOKEN = os.getenv("WXGZH_API_KEY")
@app.get(
"/robot/api"
)
async def check_signature(
request: Request,
signature: str,
timestamp: str,
nonce: str,
echostr: int,
):
print(f"signature: {signature}")
print(f"timestamp: {timestamp}")
print(f"nonce: {nonce}")
print(f"echostr: {echostr}")
ll = [WINXIN_TOKEN, timestamp, nonce]
ll.sort()
hashcode = hashlib.sha1("".join(ll).encode('UTF-8')).hexdigest()
return echostr if hashcode == signature else "error"
- 启动代码(需要以8080)
$ uvicorn robot:app --host '0.0.0.0' --port 8080 --reload
- 然后就可以验证了,正常情况下会验证通过
3) 业务开发
- 预实现功能
粉丝给公众号一条文本消息,公众号立马回复一条文本消息给粉丝。
-
流程如下
消息格式
下面来看发送的消息格式:
<xml>
<ToUserName><![CDATA[公众号]]></ToUserName>
<FromUserName><![CDATA[粉丝号]]></FromUserName>
<CreateTime>1460537339</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[欢迎开启公众号开发者模式]]></Content>
<MsgId>6272960105994287618</MsgId>
</xml>
通过如下代码就可以查看:
@app.post(
"/robot/api"
)
async def handle_wx(request: Request):
content = await request.body()
print(f"request: {content}")
被动回复的消息格式:
<xml>
<ToUserName><![CDATA[粉丝号]]></ToUserName>
<FromUserName><![CDATA[公众号]]></FromUserName>
<CreateTime>1460541339</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[test]]></Content>
</xml>
- 回复的代码
我们采用wechatpy
包来实现整个逻辑,如下:
from wechatpy import parse_message
from wechatpy.replies import TextReply
@app.post(
"/robot/api"
)
async def handle_wx(request: Request):
xml = await request.body()
msg = parse_message(xml)
print(msg)
if msg.type == "text":
content = f"Reply: {msg.content}"
reply = TextReply(content=content, message=msg)
# 转换成 XML
return reply.render()
return TextReply(content="Not support type", message=msg)
最后启动即可:
$ uvicorn robot:app --host '0.0.0.0' --port 8080 --reload