打造微信聊天机器人1

摘要:利用微信公众号开发一个聊天机器人。

前置条件

  • Linux基础
  • 一点儿CGI和Python基础
  • 一台运行Linux系统的云主机或VPS虚拟主机
  • 最好有个域名

原理

聊天机器人原理图

上图给出了聊天机器人的基本原理。用户A在微信客户端中给公众号发送一条消息,这条消息会通过微信服务器,转发到公众号指定的服务器上,也就是图中的“聊天机器人服务器”,聊天机器人服务器收到消息之后,经过“思考”,给出一个回复到微信服务器,然后微信服务器就会把这个回复发送到用户A的客户端,一次“对话”就完成了。整个过程中的大部分工作,都已经由微信包办了,我们要做的,只是红框中的聊天机器人服务器,让它按照微信指定的协议,接收消息和发送回复,就是这么简单!

微信服务器和聊天机器人之间通过HTTP通信,所以我们的聊天机器人服务器,实际上就是一个符合微信标准的CGI,基本上你可以用任何语言进行开发。本文将使用Python和Bottle框架进行开发。

申请微信公众号

微信公众平台注册一个帐号,注意这里使用的邮箱不能跟微信其他服务所绑定的邮箱相同,包括个人微信号、微信开放平台、微信小程序等等。幸好只是换邮箱注册,不是换手机注册。注册之后请按照官方的指引填写相关信息。公众平台提供了编辑和发布图文消息的功能,但是要实现一个聊天机器人,必须使用开发者模式。在"开发" -> "接口权限"下,可以查看当前公众号能够使用的接口,目前个人用户只能申请订阅号,并且不能进行认证,因此权限最低,能使用的接口有限。不过接收消息和自动回复的权限还是有的,并且没有调用次数的限制,这就足够了。

进入"开发" -> "基本配置" -> "服务器配置",修改服务器配置,这里的关键选项是URL和Token。URL就是原理图中,微信服务器和你的聊天机器人服务器之间通信的接口。Token让你的聊天机器人可以验证消息的来源,防止微信服务器之外的恶意调用。微信服务器发送的每条消息,都会带上一个使用Token加密的签名,我们只要使用相同的Token和算法,就能验证收到的消息是否来自微信服务器。关于签名的方法,微信官方的接入指南里有更详细的描述,以及对应的PHP实现。"消息加解密方式"选择"明文模式",EncodingAESKey直接点"随机生成",这样省去了消息加解密的麻烦。

此时直接点击“提交”是不能成功的,因为微信公众平台会立刻发送一个验证消息,检验URL是否可用。我们必须先让自己的服务器跑起来,才能通过验证。

一个最小的公众号服务器

这里我们使用Bottle这个小巧而美丽的Web框架来编写一个能通过验证的最简单的服务器。在你的云主机或者VPS上创建robot.py文件,内容如下:

from bottle import request, route, run
from hashlib import sha1

TOKEN = '这里填写你的Token'

def valid():
    l = [TOKEN, request.query.timestamp, request.query.nonce]
    l.sort()
    h = sha1()
    h.update("".join(l))
    if request.query.signature == h.hexdigest():
        return True
    return False

@route('/wx/chatbot')
def check():
    if valid():
        return request.query.echostr
    return "failed"

run(host='0.0.0.0', port=80)

这段端程序的含义是,服务器收到一个访问/wx/chatbot的GET请求时,按照微信指定的算法计算签名,跟请求中的signature参数进行对比,如果二者相符,就把请求中的echostr原样返回。事实上,这个服务器还不是最简单的。因为微信服务器只要收到了echostr,就会认为验证成功,因此我们完全可以跳过签名验证的过程,直接返回echostr。

运行这段程序必须要bottle模块,可以直接从这里下载压缩包,解压出里面的bottle.py放在你程序的目录下。不过更推荐的方法是使用pip,安装方法见这里

pip install bottle

现在让我们的服务器运行起来,然后回到微信公众平台的配置页面,在URL里填写“http://你的域名或ip/wx/chatbot”, 点击“提交”完成配置,再点击“启用”让我们的配置生效。

python robot.py

A Dumb Robot

到这里,我们已经有了一个可以接收微信消息的服务器了。微信发过来的消息是下面这个样子:

<xml>
<ToUserName><![CDATA[toUser]]></ToUserName>
<FromUserName><![CDATA[fromUser]]></FromUserName>
<CreateTime>1348831860</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[this is a test]]></Content>
<MsgId>1234567890123456</MsgId>
</xml>

这是一个XML文件,我们只关注3个字段:ToUserName、FromUserName和Content,分别表示消息的接收者(这里是我们的公众号ID,可以在公众平台的"设置" -> "公众号设置" -> "原始ID"中看到),发送者和内容。要回复消息给用户,也要返回一个指定格式的XML给微信服务器:

<xml>
<ToUserName><![CDATA[toUser]]></ToUserName>
<FromUserName><![CDATA[fromUser]]></FromUserName>
<CreateTime>12345678</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[你好]]></Content>
</xml>

知道了往返消息的格式(详细信息参见微信的开发文档),我们就可以开始“对话”了。在代码中添加下面内容:

from time import time

@route('/wx/chatbot', method='POST')
def chat():
    if not valid():
        return "invalid msg"
    return """
    <xml>
    <ToUserName><![CDATA[toUser]]></ToUserName>
    <FromUserName><![CDATA[fromUser]]></FromUserName>
    <CreateTime>12345678</CreateTime>
    <MsgType><![CDATA[text]]></MsgType>
    <Content><![CDATA[Hello]]></Content>
    </xml>
    """ % int(time()) 

chat()函数将接收来自微信服务器的POST请求,然后返回一个固定的回复。要让发消息的用户能够收到回复,还需要正确的填写回复中的toUser和fromUser。由于是回复消息,toUser和fromUser跟用户发送给公众号的消息正好是反过来的,我们可以用print语句把收到的消息打印出来,找到对应的字段填在回复里,这样就可以成功的回复消息了。因为toUser是写死的,这个公众号只能给固定的用户回复消息,而且只能say hello。不过,它总算是“活过来”了。在后续的内容里,我们将真正打造一个能够跟用户对话,并且具备一定智能的聊天机器人。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容

  • 点击查看原文 Web SDK 开发手册 SDK 概述 网易云信 SDK 为 Web 应用提供一个完善的 IM 系统...
    layjoy阅读 13,339评论 0 15
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,099评论 18 139
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 170,566评论 25 707
  • 既然爱,为什么不说出口,有些东西失去了,就在也回不来了! 人最软弱的地方,是舍不得。舍不得一段不再精采的感情,舍不...
    爱你的wo阅读 331评论 0 0
  • 大家好,今天是2016年里的最后一天。 此刻的你是否会对即将逝去的一年感到不舍?或者深叹口气觉得终于熬过了这一年?...
    遇见卡米拉阅读 171评论 0 0