您当前的位置:首页 > 电脑百科 > 程序开发 > 语言 > Python

给你的公众号添加一个智能机器人

时间:2020-09-25 11:12:01  来源:  作者:



环境和工具

  • 公众号一个
  • 云服务器一台
  • Python 环境
  • Flask(Python 第三方库)
  • 图灵机器人账号

以上就是我们实现公众号后台智能对话机器人需要的环境和工具,前两个就不多说了。我们代码使用 Python 开发,所以需要配置好 Python 开发环境,安装 Flash 库。最后需要注册一个图灵机器人账号,调用其 API 接口。

欢迎到我的公众号 码小白TM 里调戏机器人,去看看这个机器人智不智能!

Web 服务器搭建

我们想要接收公众号后台发送的消息,就需要搭建一个 Web 服务器了。我们在云服务器上安装好 Python 和 Flask 后,就可以进行 Web 服务器的搭建了。

我们首先搭建一个非常简单的 Web 服务器,就是在网页显示出 HelloWorld!,来跑通我们的代码。我们来看一下主程序代码。

main.py

from flask import Flask
App = Flask(__name__)@app.route("/")
def index():
    return "Hello World!"
if __name__ == "__main__":
    app.run(host='0.0.0.0')

代码非常简单,我们直接运行代码,启动 Web 服务器:

python main.py

运行成功后,我们可以在云服务器机器浏览器上访问 127.0.0.1,如果我们能看到 Hello World! 就说明我们服务器启动成功了。我们也可以在外网机器浏览器上访问你云服务器的外网 IP,来检测 Web 服务器是否成功启动。

公众号后台配置和验证

然后我们去公众号后台开发->基本配置页找到服务器配置,可以看到我们需要一个服务器的 URL 地址、Token 令牌、消息加解密密钥。

给你的公众号添加一个智能机器人

 

公众号后台配置

服务器的 URL 地址就是:http://服务器外网IP/wechat,/ 前面是你的云服务外网 IP 地址,后边是我们在代码里定义的路由入口(可以自己定义),后边我们会在代码中看到。Token 令牌是我们自己定义的,后边代码中也会用到。消息加解密密钥可以通过自动生成,消息加解密方式我们选择明文模式即可。

你第一次配置的时候下边会有保存按钮,这个时候我们先不要点击,因为我们需要在 Web 服务器端对消息字段进行解析处理,然后回传结果进行验证。

我们到微信公众号开发文档里看一下消息验证流程。

给你的公众号添加一个智能机器人

验证流程

根据上图流程我们进行我们的代码编写。

main.py

from flask import Flask
from flask import request
import hashlibapp = Flask(__name__)@app.route("/")
def index():    return "Hello World!"
# 公众号后台消息路由入口@app.route("/wechat", methods=["GET", "POST"])
def wechat(): # 验证使用的是GET方法    if request.method == "GET":
        signature = request.args.get('signature')
        timestamp = request.args.get('timestamp')
        nonce = request.args.get('nonce')
        echostr = request.args.get('echostr')
        token = "公众号后台填写的token"
  # 进行排序        dataList = [token, timestamp, nonce]        dataList.sort()        result = "".join(dataList)
  #哈希加密算法得到hashcode        sha1 = hashlib.sha1()        sha1.update(result.encode("utf-8"))
        hashcode = sha1.hexdigest()        if hashcode == signature:
            return echostr
        else:
            return ""
if __name__ == "__main__":
    app.run(host='0.0.0.0', port=80) #公众号后台只开放了80端口

这里需要注意 http 的端口号固定使用80,不可填写其他。这里坑了我很久,因为我的服务器上还有我自己的博客,80端口被博客占用了,为了把80端口让出来,我重新搭了我的博客,修改了端口,导致现在访问我的博客后边必须加上修改后的端口。这里如果有同学有更高的方法,还请劳烦告知一下!

好了,现在我们的验证流程完成,运行我们的 Web 服务器。然后到公众号后台配置处点击保存,如果提示验证通过,那么恭喜你完成了验证。

如果提示验证失败,我们自己根据报错提示来查看是哪里的问题。

实现“你问我答”和“图”上往来

我们验证成功了,下面就要开始处理粉丝在公众号发过来的消息了。我们先来实现一个简单的“你问我答”, 粉丝给公众号一条文本消息,公众号立马回复一条相同文本消息给粉丝;还有图上往来,接受粉丝发送的图片消息,并立马回复相同的图片给粉丝。

我们通过公众号文档知道,普通用户向公众号发消息是用的 POST 方法,消息分为文本消息、图片消息、语音消息、视频消息等很多种。这里我们只对文本消息和图片消息进行处理和回复(后续你也可以针对其他消息进行处理和回复)。

消息的格式为XML数据包,下面看一下文本消息的实例:

<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>
  • ToUserName 开发者微信号
  • FromUserName 发送方帐号(一个OpenID)
  • CreateTime 消息创建时间 (整型)
  • MsgType 消息类型,文本为text,图片为image
  • Content 文本消息内容
  • MsgId 消息id,64位整型

被动回复文本消息,就是我们回复给用户的文本消息类型为:

<xml>
 <ToUserName><![CDATA[粉丝号]]></ToUserName>
 <FromUserName><![CDATA[公众号]]></FromUserName>
 <CreateTime>1460541339</CreateTime>
 <MsgType><![CDATA[text]]></MsgType>
 <Content><![CDATA[test]]></Content>
</xml>
  • Content 回复的消息内容

回复的图片消息类型:

<xml>
  <ToUserName><![CDATA[toUser]]></ToUserName>
  <FromUserName><![CDATA[fromUser]]></FromUserName>
  <CreateTime>12345678</CreateTime>
  <MsgType><![CDATA[image]]></MsgType>
  <Image>
    <MediaId><![CDATA[media_id]]></MediaId>
  </Image>
</xml>
  • MediaId 通过素材管理中的接口上传多媒体文件,得到的id。

接收和回复消息的格式我们知道了,下面我们来看一下整个流程。

给你的公众号添加一个智能机器人

 


给你的公众号添加一个智能机器人

 

我们根据流程来修改一下我们的代码。我们增加两个文件来处理接收的消息,和回复的消息 receive.py,reply.py。

receive.py

import xml.etree.ElementTree as ET
def parse_xml(web_data):    if len(web_data) == 0:
        return None
    xmlData = ET.fromstring(web_data)    msg_type = xmlData.find('MsgType').text
    if msg_type == 'text':
        return TextMsg(xmlData)
    elif msg_type == 'image':
        return ImageMsg(xmlData)
class Msg(object):
    def __init__(self, xmlData):
        self.ToUserName = xmlData.find('ToUserName').text
        self.FromUserName = xmlData.find('FromUserName').text
        self.CreateTime = xmlData.find('CreateTime').text
        self.MsgType = xmlData.find('MsgType').text
        self.MsgId = xmlData.find('MsgId').text
class TextMsg(Msg):    def __init__(self, xmlData):
        Msg.__init__(self, xmlData)        self.Content = xmlData.find('Content').text
class ImageMsg(Msg):    def __init__(self, xmlData):
        Msg.__init__(self, xmlData)        self.PicUrl = xmlData.find('PicUrl').text
        self.MediaId = xmlData.find('MediaId').text

reply.py

import time
class Msg(object):    def __init__(self):        pass    def send(self):        return "success"class TextMsg(Msg):    def __init__(self, toUserName, fromUserName, content):        self.__dict = dict()        self.__dict['ToUserName'] = toUserName        self.__dict['FromUserName'] = fromUserName        self.__dict['CreateTime'] = int(time.time())        self.__dict['Content'] = content    def send(self):        XmlForm = """            <xml>
                <ToUserName><![CDATA[{ToUserName}]]></ToUserName>
                <FromUserName><![CDATA[{FromUserName}]]></FromUserName>
                <CreateTime>{CreateTime}</CreateTime>
                <MsgType><![CDATA[text]]></MsgType>
                <Content><![CDATA[{Content}]]></Content>
            </xml>
            """        return XmlForm.format(**self.__dict)class ImageMsg(Msg):    def __init__(self, toUserName, fromUserName, mediaId):        self.__dict = dict()        self.__dict['ToUserName'] = toUserName        self.__dict['FromUserName'] = fromUserName        self.__dict['CreateTime'] = int(time.time())        self.__dict['MediaId'] = mediaId    def send(self):        XmlForm = """            <xml>
                <ToUserName><![CDATA[{ToUserName}]]></ToUserName>
                <FromUserName><![CDATA[{FromUserName}]]></FromUserName>
                <CreateTime>{CreateTime}</CreateTime>
                <MsgType><![CDATA[image]]></MsgType>
                <Image>
                <MediaId><![CDATA[{MediaId}]]></MediaId>
                </Image>
            </xml>
            """        return XmlForm.format(**self.__dict)

main.py

from flask import Flask
from flask import request
import hashlibimport receiveimport replyapp = Flask(__name__)@app.route("/")
def index():    return "Hello World!"
# 公众号后台消息路由入口@app.route("/wechat", methods=["GET", "POST"])
def wechat(): # 验证使用的GET方法    if request.method == "GET":
        signature = request.args.get('signature')
        timestamp = request.args.get('timestamp')
        nonce = request.args.get('nonce')
        echostr = request.args.get('echostr')
        token = "公众号后台填写的token"
  # 进行排序        dataList = [token, timestamp, nonce]        dataList.sort()        result = "".join(dataList)
  #哈希加密算法得到hashcode        sha1 = hashlib.sha1()        sha1.update(result.encode("utf-8"))
        hashcode = sha1.hexdigest()        if hashcode == signature:
            return echostr
        else:
            return ""
 else:
        recMsg = receive.parse_xml(request.data)
        if isinstance(recMsg, receive.Msg):
            toUser = recMsg.FromUserName            fromUser = recMsg.ToUserName            if recMsg.MsgType == 'text':
                content = recMsg.Content                replyMsg = reply.TextMsg(toUser, fromUser, content)                return replyMsg.send()
            elif recMsg.MsgType == 'image':
                mediaId = recMsg.MediaId                replyMsg = reply.ImageMsg(toUser, fromUser, mediaId)                return replyMsg.send()
            else:
                return reply.Msg().send()
        else:
            return reply.Msg().send()
if __name__ == "__main__":
    app.run(host='0.0.0.0', port=80) #公众号后台只开放了80端口

然后我们启动 Web 服务器,去公众号后台发消息发图片测试,如果成功的话立马就会回复你相同的文字和图片。

微信提供了一个在线测试的平台,可以很方便的进行开发中的各种测试。

接入图灵机器人

首先我们去图灵机器人官网注册一个账号。然后在后台创建一个机器人。

然后我们根据图灵机器人接入文档的使用说明:

  • 编码方式:调用调用图灵API的各个环节的编码方式均为 UTF-8
  • 接口地址:http://openapi.tuling123.com/openapi/api/v2
  • 请求方式: HTTP POST
  • 请求参数:参数格式为 json

请求参数示例:

{
 "reqType":0,
    "perception": {
        "inputText": {
            "text": "附近的酒店"
        },        "inputImage": {
            "url": "imageUrl"
        },        "selfInfo": {
            "location": {
                "city": "北京",
                "province": "北京",
                "street": "信息路"
            }        }    },    "userInfo": {
        "apiKey": "",
        "userId": ""
    }}

输出参数示例:

{
    "intent": {
        "code": 10005,
        "intentName": "",
        "actionName": "",
        "parameters": {
            "nearby_place": "酒店"
        }    },    "results": [
        {          "groupType": 1,
            "resultType": "url",
            "values": {
                "url": "http://m.elong.com/hotel/0101/nlist/#indate=2016-12-10&outdate=2016-12-11&keywords=%E4%BF%A1%E6%81%AF%E8%B7%AF"
            }        },        {          "groupType": 1,
            "resultType": "text",
            "values": {
                "text": "亲,已帮你找到相关酒店信息"
            }        }    ]}

其中 apiKey 是可以在我们创建的机器人的参数中找到,userId 是用户唯一标识。

好了,下面来编写我们的代码。我们增加一个 tuling.py 文件来接入图灵接口。

tuling.py

import json
import urllibapiKey = '从你创建的机器人获得'
tulingUrl = "http://openapi.tuling123.com/openapi/api/v2"
# content 是接收的消息,userId 是用户唯一标识def tulingReply(content, userId):    requestData = {        "reqType": 0,
        "perception": {
            "inputText": {
                "text": content
            },            "selfInfo": {
                "location": {
                    "city": "北京"
                }            }        },        "userInfo": {
            "apiKey": apiKey,
            "userId": userId
        }    }     requestData = json.dumps(requestData).encode('utf8')
    http_post = urllib.request.Request(        tulingUrl,        data=requestData,
        headers={'content-type': 'application/json'})
     response = urllib.request.urlopen(http_post)    response_str = response.read().decode('utf8')
    response_dic = json.loads(response_str)    results_code = response_dic['intent']['code']
  # 免费版每天有固定次数,如果超过之后会返回4003错误码
    if results_code == 4003:
        results_text = "4003:%s" % response_dic['results'][0]['values']['text']
    else:
        results_text = response_dic['results'][0]['values']['text']
    return results_text

修改 main.py

from flask import Flask
from flask import request
import hashlibimport reimport tulingimport receiveimport replyapp = Flask(__name__)@app.route("/")
def index():    return "Hello World!"
# 公众号后台消息路由入口@app.route("/wechat", methods=["GET", "POST"])
def wechat(): # 验证使用的GET方法    if request.method == "GET":
        signature = request.args.get('signature')
        timestamp = request.args.get('timestamp')
        nonce = request.args.get('nonce')
        echostr = request.args.get('echostr')
        token = "公众号后台填写的token"
  # 进行排序        dataList = [token, timestamp, nonce]        dataList.sort()        result = "".join(dataList)
  #哈希加密算法得到hashcode        sha1 = hashlib.sha1()        sha1.update(result.encode("utf-8"))
        hashcode = sha1.hexdigest()        if hashcode == signature:
            return echostr
        else:
            return ""
 else:
        recMsg = receive.parse_xml(request.data)
        if isinstance(recMsg, receive.Msg):
            toUser = recMsg.FromUserName            fromUser = recMsg.ToUserName            if recMsg.MsgType == 'text':
                content = recMsg.Content    # userId 长度小于等于32位
                if len(toUser) > 31:
                    userid = str(toUser[0:30])
                else:
                    userid = str(toUser)                userid = re.sub(r'[^A-Za-z0-9]+', '', userid)
                tulingReplay = tuling.tulingReply(content, userid)                replyMsg = reply.TextMsg(toUser, fromUser, tulingReplay)                return replyMsg.send()
            elif recMsg.MsgType == 'image':
                mediaId = recMsg.MediaId                replyMsg = reply.ImageMsg(toUser, fromUser, mediaId)                return replyMsg.send()
            else:
                return reply.Msg().send()
        else:
            return reply.Msg().send()
if __name__ == "__main__":
    app.run(host='0.0.0.0', port=80) #公众号后台只开放了80端口

耶,我们的机器人完成了,马上迫不及待的去试试。

给你的公众号添加一个智能机器人

 

wuLydg.png

可以愉快的和你的机器人对话了。

后面发现了第一关注公众号后的欢迎语没有了,因为你自己的服务器接管了公众号的消息,所以原来后台设置的欢迎语就失效了。在公众号文档中看到关注/取消关注属于事件。其消息的格式如下。

<xml>
  <ToUserName><![CDATA[toUser]]></ToUserName>
  <FromUserName><![CDATA[FromUser]]></FromUserName>
  <CreateTime>123456789</CreateTime>
  <MsgType><![CDATA[event]]></MsgType>
  <Event><![CDATA[subscribe]]></Event>
</xml>

我们只需要判断一下 MsgType 是 event,然后 Event 是 subscribe,然后回复我们的欢迎语就可以了,很简单,这个我们就不详细展开了。

欢迎到我的公众号 码小白TM 里调戏机器人。如果过程中遇到什么问题也可以在联系我找到我的微信。



Tags:公众号   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
其实现在大家做微信公众号涨粉的裂变活动还是挺多的;以海报裂变吸粉模式,比如一张海报,转发到朋友圈邀请好友助力,关注公众号,完成任务后获得奖励。第一,设定奖品诱饵的时候一定要...【详细内容】
2021-11-03  Tags: 公众号  点击:(35)  评论:(0)  加入收藏
以微信公众号为例说明,微信的用户很多,现在大家的社交,工作工具很多都是通过微信来完成的。很多公司和企业也都有自己的微信公众号,便于用户更加了解企业,也利于品牌形象的塑造。...【详细内容】
2021-10-26  Tags: 公众号  点击:(43)  评论:(0)  加入收藏
可能许多朋友在刷视频号的时候会发现,很多视频的底部会加上一个链接。 △ 博主动态展示(含扩展链接) 截图来源:友望数据-博主动态这个链接就是公众号的文章链接。 诞生在微信之...【详细内容】
2021-07-14  Tags: 公众号  点击:(58)  评论:(0)  加入收藏
在开发微信公众号时,需要不时请求URL和数据封装。为了不做重复的工作。提取公共部分进行封装。产生了相应的公众类。今天先来写下请求类,代码如下:public class HttpRequestP...【详细内容】
2021-06-16  Tags: 公众号  点击:(134)  评论:(0)  加入收藏
我在为单位职工扫健康码的过程中,发现有许多人打开健康码小程序非常麻烦,就教他们把微信小程序添加到手机桌面。于是我就想:如果把微信的常用联系人和公众号以及小程序添加到...【详细内容】
2021-05-08  Tags: 公众号  点击:(232)  评论:(0)  加入收藏
给文章加入音乐,会更容易让读者沉浸在文章中,享受文字的洗礼,直线式增加了用户体验。另外呢也会增加我们文章的多样性。。。。。。哈哈哈!好处多多!好啦,话不多说,我们就开始今天...【详细内容】
2021-04-07  Tags: 公众号  点击:(270)  评论:(0)  加入收藏
微信公众号报名用到的是微预约功能,也可以叫做万能表单功能,可以实现粉丝向公众号提交报名、预约等信息资料,同时公众号商家可以完全自定义表单的字段,轻松做到任意内容的收集。...【详细内容】
2021-02-18  Tags: 公众号  点击:(186)  评论:(0)  加入收藏
现在做微信运营的人员,都是希望通过微信公众号抽奖来增加粉丝的关注和提高粉丝的活跃度,公众号本身是不带抽奖活动的,所以公众号运营者需要使用微信人家微信第三方平台来添加微...【详细内容】
2021-02-18  Tags: 公众号  点击:(180)  评论:(0)  加入收藏
微官网是以微信为平台的移动网站。微官网在微信公众号上有许多的展示机会,它可以把企业信息、服务、活动等其他内容通过微信网页的方式展示给客户,不但可以提高信息量,还使得信...【详细内容】
2021-02-18  Tags: 公众号  点击:(272)  评论:(0)  加入收藏
微信公众号投票活动是需要用心策划的,这样才能够达到最好的效果。那么微信公众号的投票活动要如何策划呢?微信公众号投票活动应该如何策划一、活动目的首先明确自己举办这场...【详细内容】
2021-02-18  Tags: 公众号  点击:(176)  评论:(0)  加入收藏
▌简易百科推荐
Python 是一个很棒的语言。它是世界上发展最快的编程语言之一。它一次又一次地证明了在开发人员职位中和跨行业的数据科学职位中的实用性。整个 Python 及其库的生态系统使...【详细内容】
2021-12-27  IT资料库    Tags:Python 库   点击:(1)  评论:(0)  加入收藏
菜单驱动程序简介菜单驱动程序是通过显示选项列表从用户那里获取输入并允许用户从选项列表中选择输入的程序。菜单驱动程序的一个简单示例是 ATM(自动取款机)。在交易的情况下...【详细内容】
2021-12-27  子冉爱python    Tags:Python   点击:(1)  评论:(0)  加入收藏
有不少同学学完Python后仍然很难将其灵活运用。我整理15个Python入门的小程序。在实践中应用Python会有事半功倍的效果。01 实现二元二次函数实现数学里的二元二次函数:f(x,...【详细内容】
2021-12-22  程序汪小成    Tags:Python入门   点击:(32)  评论:(0)  加入收藏
Verilog是由一个个module组成的,下面是其中一个module在网表中的样子,我只需要提取module名字、实例化关系。module rst_filter ( ...); 端口声明... wire定义......【详细内容】
2021-12-22  编程啊青    Tags:Verilog   点击:(7)  评论:(0)  加入收藏
运行环境 如何从 MP4 视频中提取帧 将帧变成 GIF 创建 MP4 到 GIF GUI ...【详细内容】
2021-12-22  修道猿    Tags:Python   点击:(5)  评论:(0)  加入收藏
面向对象:Object Oriented Programming,简称OOP,即面向对象程序设计。类(Class)和对象(Object)类是用来描述具有相同属性和方法对象的集合。对象是类的具体实例。比如,学生都有...【详细内容】
2021-12-22  我头秃了    Tags:python   点击:(9)  评论:(0)  加入收藏
所谓内置函数,就是Python提供的, 可以直接拿来直接用的函数,比如大家熟悉的print,range、input等,也有不是很熟,但是很重要的,如enumerate、zip、join等,Python内置的这些函数非常...【详细内容】
2021-12-21  程序员小新ds    Tags:python初   点击:(5)  评论:(0)  加入收藏
Hi,大家好。我们在接口自动化测试项目中,有时候需要一些加密。今天给大伙介绍Python实现各种 加密 ,接口加解密再也不愁。目录一、项目加解密需求分析六、Python加密库PyCrypto...【详细内容】
2021-12-21  Python可乐    Tags:Python   点击:(7)  评论:(0)  加入收藏
借助pyautogui库,我们可以轻松地控制鼠标、键盘以及进行图像识别,实现自动抢课的功能1.准备工作我们在仓库里提供了2个必须的文件,包括: auto_get_lesson_pic_recognize.py:脚本...【详细内容】
2021-12-17  程序员道道    Tags:python   点击:(13)  评论:(0)  加入收藏
前言越来越多开发者表示,自从用了Python/Pandas,Excel都没有打开过了,用Python来处理与可视化表格就是四个字&mdash;&mdash;非常快速!下面我来举几个明显的例子1.删除重复行和空...【详细内容】
2021-12-16  查理不是猹    Tags:Python   点击:(20)  评论:(0)  加入收藏
最新更新
栏目热门
栏目头条