Django开发微信公众号消息自动回复
通过python的中文分词jieba包和xml处理包xmltodict结合Django实现微信公众号的消息自动回复,用户通过微信公众号的对话框向后端发消息时,微信服务器将POST消息的XML数据包推送开发者填写的URL上。具体流程如下:

本文以接收和回复文本消息为主,微信公众号支持回复文本、图片、图文、语音、视频、音乐等类型的消息。根据微信官方的安全要求,需要用秘钥对收到的密文消息体进行解密,回复消息体也用此秘钥加密。
微信公众平台为开发者提供了5种语言的示例代码(包括C++、php、Java、Python和C#版本)下载地址如下:
https://wximg.gtimg.com/shake_tv/mpwiki/cryptoDemo.zip
首先,以粉丝给公众号发送文本消息:“欢迎进入公众号交流”,在开发者后台收到公众平台发送的xml如下:
<xml><ToUserName><![CDATA[公众号]]></ToUserName><FromUserName><![CDATA[粉丝号]]></FromUserName><CreateTime>1460537339</CreateTime><MsgType><![CDATA[text]]></MsgType><Content><![CDATA[欢迎进入公众号交流]]></Content><MsgId>6272960105994287618</MsgId></xml>
说明:
createTime 是微信公众平台记录粉丝发送该消息的具体时间
text: 用于标记该xml 是文本消息,一般用于区别判断
欢迎进入公众号交流: 说明该粉丝发给公众号的具体内容是欢迎进入公众号交流
MsgId: 是公众平台为记录识别该消息的一个标记数值, 微信后台系统自动产生
所以回复给用户的消息格式基本也如上,如想回复给粉丝一条文本消息,内容为“test”, 那么开发者发送给公众平台后台的xml 内容如下:
<xml><ToUserName><![CDATA[粉丝号]]></ToUserName><FromUserName><![CDATA[公众号]]></FromUserName><CreateTime>1460541339</CreateTime><MsgType><![CDATA[text]]></MsgType><Content><![CDATA[test]]></Content></xml>
说明:
1)ToUserName(接受者)、FromUserName(发送者)。
2)createtime用于标记开发者回复消息的时间。
3)text : 此次行为是发送文本消息 (当然可以是image/voice等类型)。
4)文本换行 ‘\n’。
关于微信公众号开发后端配置的可以去查看我的过往文章,有不清楚的可以留言交流。
回到本次的重点,Django来实现微信公众号自动回复消息
安装中文分词包jieba和xmltodict,jieba用于对接收的消息进行分词,然后判断关键词并进行回复,xmltodict主要是xml消息
pip install jieba xmltodict
直接上开发代码
# -*- coding: utf-8 -*-from django.shortcuts import renderimport hashlib# Create your views here.from django.http.response import HttpResponsefrom django.views.decorators.csrf import csrf_exemptimport xmltodictimport jiebaimport time@csrf_exemptdef wechat(request):if request.method == 'GET':signature = request.GET.get('signature')timestamp = request.GET.get('timestamp', '')nonce = request.GET.get('nonce', '')echo_str = request.GET.get('echostr', '')token='你的'hashlist = [token, timestamp, nonce]hashlist.sort()list2 = ''.join(hashlist)sha1 = hashlib.sha1()sha1.update(list2.encode('utf-8'))hashcode = sha1.hexdigest()if hashcode == signature:return HttpResponse(echo_str, content_type="text/plain")else:return HttpResponse('error', content_type="text/plain")elif request.method == 'POST':dict_xml=request.body.decode('utf-8')xmlData = xmltodict.parse(dict_xml)msg_type = xmlData['xml']['MsgType']if msg_type == 'text':contents = jieba.cut(xmlData['xml']['Content'])for i in contents:if i=="微信公众号开发" or i=="小程序开发" :content = "请关注Django与python学习"resp_data = {"xml": {"ToUserName": xmlData['xml']['FromUserName'],"FromUserName": xmlData['xml']['ToUserName'],"CreateTime": int(time.time()),"MsgType": 'text',"Content": content,}}xmltodict.unparse(resp_data)response = HttpResponse(xmltodict.unparse(resp_data), content_type="text/plain")return responseelse:content = xmlData['xml']['Content']resp_data={"xml":{"ToUserName":xmlData['xml']['FromUserName'],"FromUserName":xmlData['xml']['ToUserName'],"CreateTime":int(time.time()),"MsgType":'news',"ArticleCount": 1,"Articles": {"item": {"Title": "搜索"+content+"的结果","Description": "和"+content+"相关的内容","PicUrl": "https://www.baidu.com/img/flexible/logo/pc/result.png","Url": "https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&tn=baidu&wd="+content}},}}xmltodict.unparse(resp_data)response = HttpResponse(xmltodict.unparse(resp_data), content_type="text/plain")return responseelif msg_type == 'image':content = "欢迎您"resp_data = {"xml": {"ToUserName": xmlData['xml']['FromUserName'],"FromUserName": xmlData['xml']['ToUserName'],"CreateTime": int(time.time()),"MsgType": 'image',"Content": content,}}xmltodict.unparse(resp_data)response = HttpResponse(xmltodict.unparse(resp_data), content_type="text/plain")return responseelif msg_type == 'voice':content="欢迎您"resp_data={"xml":{"ToUserName":xmlData['xml']['FromUserName'],"FromUserName":xmlData['xml']['ToUserName'],"CreateTime":int(time.time()),"MsgType":'voice',"Content":content,}}xmltodict.unparse(resp_data)response = HttpResponse(xmltodict.unparse(resp_data), content_type="text/plain")return responseelif msg_type == 'video':content = "欢迎您"resp_data = {"xml": {"ToUserName": xmlData['xml']['FromUserName'],"FromUserName": xmlData['xml']['ToUserName'],"CreateTime": int(time.time()),"MsgType": 'video',"Content": content,}}xmltodict.unparse(resp_data)print(xmltodict.unparse(resp_data))response = HttpResponse(xmltodict.unparse(resp_data), content_type="text/plain")return responseelif msg_type == 'music':content = "欢迎您"resp_data = {"xml": {"ToUserName": xmlData['xml']['FromUserName'],"FromUserName": xmlData['xml']['ToUserName'],"CreateTime": int(time.time()),"MsgType": 'music',"Content": content,}}xmltodict.unparse(resp_data)response = HttpResponse(xmltodict.unparse(resp_data), content_type="text/plain")return responseelif msg_type == 'news':resp_data = {"xml": {"ToUserName": xmlData['xml']['FromUserName'],"FromUserName": xmlData['xml']['ToUserName'],"CreateTime": int(time.time()),"MsgType": 'news',"ArticleCount":1,"Articles": {"item":{"Title":"Django之微信公众号开发接入","Description":"Django之微信公众号开发接入","PicUrl":"","Url":"https://mp.weixin.qq.com/s?__biz=MzAwNjE5MTE3Mw==&mid=2449814757&idx=1&sn=2f8a89d5bee110f4b598528303174480&chksm=8ce0b5cfbb973cd9c90b29d5a214e7489f88f0ea3bd1304c6fe503b727b7277c3c6809a1d39d&token=2126286068&lang=zh_CN#rd"}},}}xmltodict.unparse(resp_data)response = HttpResponse(xmltodict.unparse(resp_data), content_type="text/plain")return responseelif msg_type == 'event':if xmlData['xml']['Event']=='subscribe':content="谢谢您的关注"resp_data={"xml":{"ToUserName":xmlData['xml']['FromUserName'],"FromUserName":xmlData['xml']['ToUserName'],"CreateTime":int(time.time()),"MsgType":'text',"Content":content,}}xmltodict.unparse(resp_data)response = HttpResponse(xmltodict.unparse(resp_data), content_type="text/plain")return responseif xmlData['xml']['Event']=='unsubscribe':content="您取关后将接受不到我们的推送服务"resp_data={"xml":{"ToUserName":xmlData['xml']['FromUserName'],"FromUserName":xmlData['xml']['ToUserName'],"CreateTime":int(time.time()),"MsgType":'text',"Content":content,}}xmltodict.unparse(resp_data)response = HttpResponse(xmltodict.unparse(resp_data), content_type="text/plain")return responseif xmlData['xml']['Event']=='LOCATION':content="我们已收到你发送的定位"openid = xmlData['xml']['FromUserName'] # 发送者的openidLatitude=xmlData['xml']['Latitude']#地理位置纬度Longitude=xmlData['xml']['Longitude']#地理位置经度Precision=xmlData['xml']['Precision']#地理位置精度resp_data={"xml":{"ToUserName":xmlData['xml']['FromUserName'],"FromUserName":xmlData['xml']['ToUserName'],"CreateTime":int(time.time()),"MsgType":'text',"Content":content,}}xmltodict.unparse(resp_data)response = HttpResponse(xmltodict.unparse(resp_data), content_type="text/plain")return responseif xmlData['xml']['Event']=='CLICK':content="我们已收到你发送的定位"openid=xmlData['xml']['FromUserName']#发送者的openidEventKey=xmlData['xml']['EventKey']#事件 KEY 值,与自定义菜单接口中 KEY 值对应resp_data={"xml":{"ToUserName":xmlData['xml']['FromUserName'],"FromUserName":xmlData['xml']['ToUserName'],"CreateTime":int(time.time()),"MsgType":'text',"Content":content,}}xmltodict.unparse(resp_data)response = HttpResponse(xmltodict.unparse(resp_data), content_type="text/plain")return responseif xmlData['xml']['Event']=='VIEW':content="我们已收到你发送的定位"openid=xmlData['xml']['FromUserName']#发送者的openidEventKey=xmlData['xml']['EventKey']#事件 KEY 值,设置的跳转URLresp_data={"xml":{"ToUserName":xmlData['xml']['FromUserName'],"FromUserName":xmlData['xml']['ToUserName'],"CreateTime":int(time.time()),"MsgType":'text',"Content":content,}}xmltodict.unparse(resp_data)response = HttpResponse(xmltodict.unparse(resp_data), content_type="text/plain")return responseelse:content = "这是其他消息,不便回复"resp_data = {"xml": {"ToUserName": xmlData['xml']['FromUserName'],"FromUserName": xmlData['xml']['ToUserName'],"CreateTime": int(time.time()),"MsgType": 'text',"Content": content,}}xmltodict.unparse(resp_data)response = HttpResponse(xmltodict.unparse(resp_data), content_type="text/plain")return response
完成上述代码,配置url既可实现自动回复。
消息回复的内容可以建立一个库或者加入ChatGPT也可实现微信公众号上对用户消息的判断回复。




