python微信公众号之关键词自动回复


Posted in Python onJune 15, 2018

最近忙国赛的一个项目,我得做一个微信公众号。功能就是调数据并回复给用户,需要用户发送给公众号一个关键词,通过关键词自动回复消息。

这时就是查询微信公众平台文档了,地址如下: 文档

按照它的入门指南,我基本上了解了用户给公众号发送消息的一个机制,并且一旦给公众号发送消息,在开发者后台,会收到公众平台发送的一个xml,所以通过编写Python脚本进行xml的解析与自动发送功能。

如果用户给公众号发送一段text消息,比如“hello”,那么后台就会收到一个xml为:

<xml>
<ToUserName><![CDATA[公众号]]></ToUserName>
<FromUserName><![CDATA[粉丝号]]></FromUserName>
<CreateTime>1460541339</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[hello]]></Content>
</xml>

注意这里面有一些标记对于我们开发者来说是非常有用的:ToUserName,FromUserName,MsgType,Content
所以我们只要知道了这些信息,我们就能做到自动回复的功能。

我们发现这个MsgType 为 ‘text'。而微信中的MsgType有“text”(文本)、“image”(图像)、“voice”(语音)、“video”(视频)、“shortvideo”(短视频)、“location”(位置)、“link”(链接)、“event”(事件)

首先我们写一个main.py文件

main.py

# -*- coding: utf-8 -*-
# filename: main.py
import web
from handle import Handle

urls = (
 '/wx', 'Handle',
)

if __name__ == '__main__':
 app = web.application(urls, globals())
 app.run()

然后写一个receive.py,作为接受用户发送过来的数据,并解析xml,返回数据的脚本。

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':
  #print('text')
  return TextMsg(xmlData)
 elif msg_type == 'image':
  return ImageMsg(xmlData)
 elif msg_type == 'location':
  #print('location')
  return LocationMsg(xmlData)
 elif msg_type == 'event':
  #print('event')
  return EventMsg(xmlData)

class Event(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.Eventkey = xmlData.find('EventKey').text

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.encode("utf-8")

class ImageMsg(Msg):
 def __init__(self, xmlData):
  Msg.__init__(self, xmlData)
  self.PicUrl = xmlData.find('PicUrl').text
  self.MediaId = xmlData.find('MediaId').text

class LocationMsg(Msg):
 def __init__(self, xmlData):
  Msg.__init__(self, xmlData)
  self.Location_X = xmlData.find('Location_X').text
  self.Location_Y = xmlData.find('Location_Y').text

class EventMsg(Msg):
 def __init__(self, xmlData):
  Event.__init__(self, xmlData)
  self.Event = xmlData.find('Event').text

其中,我们使用xml.etree.ElementTree,这是一个简单而有效的用户解析和创建XML数据的API。而fromstring()就是解析xml的函数,然后通过标签进行find(),即可得到标记内的内容。

同时还要写一个reply.py,作为自动返回数据的脚本。
刚才提到了,用户给公众号发送消息,公众号的后台会接收到一个xml,那么如果公众号给用户发送消息呢,其实也就是公众号给用户发送一个xml,只是ToUserName,FromUserName换了一下而已,内容自己定。

<xml>
<ToUserName><![CDATA[粉丝号]]></ToUserName>
<FromUserName><![CDATA[公众号]]></FromUserName>
<CreateTime>1460541339</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[test]]></Content>
</xml>

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)

接着我们要写一个handle.py,作为对消息进行反映处理(自动回复)的脚本。

handle.py

import web
import reply
import receive
import JsonData
import xml.dom.minidom
class Handle(object):
 def GET(self):
  try:
   data = web.input()
   if len(data) == 0:
    return "hello, this is handle view"
   signature = data.signature
   timestamp = data.timestamp
   nonce = data.nonce
   echostr = data.echostr
   token = "hello2016"

   list = [token, timestamp, nonce]
   list.sort()
   sha1 = hashlib.sha1()
   map(sha1.update, list)
   hashcode = sha1.hexdigest()
   #print("handle/GET func: hashcode, signature: ", hashcode, signature)
   if hashcode == signature:
    return echostr
   else:
    return ""
  except Exception as Argument:
   return Argument
 def POST(self):
  try:
   webData = web.data()
   #print(webData)
   recMsg = receive.parse_xml(webData)
   #print(recMsg)
   if isinstance(recMsg, receive.Msg):
    toUser = recMsg.FromUserName
    fromUser = recMsg.ToUserName
    if recMsg.MsgType == 'text':
     try:
      a = JsonData.praserJsonFile()
      #print(a)
     except Exception as Argument:
      return Argument
     if a['status'] == '1':
      content = "No equipment"
     else:
      if a['data'][0]['weather']=='0':
       israin = '7.没有下雨'
      else:
       israin = '7.下雨'
      #print(israin)
      content = "此设备数据如下:\n"+"1.id号为 "+a['data'][0]['id']+"\n"+"2.温度为 "+a['data'][0]['temp']+"\n"+"3.湿度为 "+a['data'][0]['humidity']+"\n"+"4.PM2.5浓度为 "+a['data'][0]['pm25']+"ug\n"+"5.PM10浓度为 "+a['data'][0]['pm10']+"\n"+"6.光照 "+a['data'][0]['illumination']+"L\n"+israin
      #content = "%s\n%s %s\n%s %s\n%s %s\n%s %s\n%s %s\n%s" %('环境数据如下:','设备id号为',a['data']['id'],'temp is', a['data']['temp'], 'humidity is', a['data']['humidity'],'PM25 is',a['data']['pm25'],'illumination',a['data']['illumination'],israin)
      #print(content)
     replyMsg = reply.TextMsg(toUser, fromUser, content)
     return replyMsg.send()
    if recMsg.MsgType == 'image':
     mediaId = recMsg.MediaId
     replyMsg = reply.ImageMsg(toUser, fromUser, mediaId)
     return replyMsg.send()
    if recMsg.MsgType == 'location':
     location_x = recMsg.Location_X
     location_y = recMsg.Location_Y
     content = "您所在的位置是在:经度为"+location_x+";纬度为:"+location_y
     replyMsg = reply.TextMsg(toUser, fromUser, content)
     return replyMsg.send()
    if recMsg.MsgType == 'event':
     #print('yes')
     event = recMsg.Event
     if event == 'subscribe':
      content = "欢迎关注,您好!雨燕城市环境小助手微信公众号:发送 获取数据,公众号会自动发送当前环境数据(目前为调试数据,不是真实数据).将要调试GPS,根据手机定位位置与设备位置相关联,取最近距离的设备所获取到的数据并进行返回."
      replyMsg = reply.TextMsg(toUser, fromUser, content)
      return replyMsg.send()
    else:
     return reply.Msg().send()
   else:
    print("not do")
    return reply.Msg().send()
  except Exception as Argment:
   return Argment

注:代码贴了目前写的所有功能,接收关键字并自动返回数据;关注后自动回复欢迎文字;发送定位获得GPS信息。

那么我怎么样使用微信公众号去调取服务器上的数据呢,因为有了数据的json文件,我们就可以使用Python脚本进行json的解析,然后将数据在content中体现出来就可以了。

Json文件解析

import types
import urllib.request
import json


def praserJsonFile():
 url = "http://118.89.244.53:8080/index.php/home/api/present_data"
 data = urllib.request.urlopen(url).read()
 value = json.loads(data.decode())
 #print(value) 
 #print(value['data'])
 return value

#praserJsonFile()

这个value就是我们解析json出来的一个list

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python Web框架Flask中使用新浪SAE云存储实例
Feb 08 Python
Python使用scrapy采集时伪装成HTTP/1.1的方法
Apr 08 Python
Python Sql数据库增删改查操作简单封装
Apr 18 Python
python操作 hbase 数据的方法
Dec 18 Python
Python使用修饰器执行函数的参数检查功能示例
Sep 26 Python
python 把列表转化为字符串的方法
Oct 23 Python
详解python 利用echarts画地图(热力图)(世界地图,省市地图,区县地图)
Aug 06 Python
tensorflow pb to tflite 精度下降详解
May 25 Python
Python sklearn中的.fit与.predict的用法说明
Jun 28 Python
Python的3种运行方式:命令行窗口、Python解释器、IDLE的实现
Oct 10 Python
python基于exchange函数发送邮件过程详解
Nov 06 Python
Python利用imshow制作自定义渐变填充柱状图(colorbar)
Dec 10 Python
使用NumPy和pandas对CSV文件进行写操作的实例
Jun 14 #Python
python 读取.csv文件数据到数组(矩阵)的实例讲解
Jun 14 #Python
python的pandas工具包,保存.csv文件时不要表头的实例
Jun 14 #Python
使用python将大量数据导出到Excel中的小技巧分享
Jun 14 #Python
使用pandas将numpy中的数组数据保存到csv文件的方法
Jun 14 #Python
利用pandas将numpy数组导出生成excel的实例
Jun 14 #Python
详解Django 中是否使用时区的区别
Jun 14 #Python
You might like
php mssql 数据库分页SQL语句
2008/12/16 PHP
php foreach、while性能比较
2009/10/15 PHP
PHP 八种基本的数据类型小结
2011/06/01 PHP
linux使用crontab实现PHP执行计划定时任务
2014/05/10 PHP
PHP+MySQL删除操作实例
2015/01/21 PHP
PHP如何获取当前主机、域名、网址、路径、端口等参数
2017/06/09 PHP
PHP封装的简单连接MongoDB类示例
2019/02/13 PHP
PHP设计模式之简单工厂和工厂模式实例分析
2019/03/25 PHP
php的RSA加密解密算法原理与用法分析
2020/01/23 PHP
JavaScript 工具库 Cloudgamer JavaScript Library v0.1 发布
2009/10/29 Javascript
JavaScript入门之事件、cookie、定时等
2011/10/21 Javascript
jQuery自定义事件的简单实现代码
2014/01/27 Javascript
浅析javascript中的DOM
2015/03/01 Javascript
微信内置浏览器私有接口WeixinJSBridge介绍
2015/05/25 Javascript
基于javascript实现按圆形排列DIV元素(一)
2016/12/02 Javascript
Bootstrap基本插件学习笔记之模态对话框(16)
2016/12/08 Javascript
jQuery源码分析之init的详细介绍
2017/02/13 Javascript
无循环 JavaScript(map、reduce、filter和find)
2017/04/08 Javascript
AngularJS页面带参跳转及参数解析操作示例
2017/06/28 Javascript
js时间戳与日期格式之间转换详解
2017/12/11 Javascript
JS+HTML5本地存储Localstorage实现注册登录及验证功能示例
2020/02/10 Javascript
pycharm安装图文教程
2017/05/02 Python
Python3 适合初学者学习的银行账户登录系统实例
2017/08/08 Python
微信跳一跳python辅助软件思路及图像识别源码解析
2018/01/04 Python
Python发送邮件功能示例【使用QQ邮箱】
2018/12/04 Python
python图形工具turtle绘制国际象棋棋盘
2019/05/23 Python
详解python播放音频的三种方法
2019/09/23 Python
详解HTML5 window.postMessage与跨域
2017/05/11 HTML / CSS
Kangol帽子官网:坎戈尔袋鼠
2018/09/26 全球购物
建筑专业毕业生推荐信
2013/11/21 职场文书
《和我们一样享受春天》教学反思
2014/02/07 职场文书
反邪教宣传工作方案
2014/05/07 职场文书
安全环保演讲稿
2014/08/28 职场文书
影视广告专业求职信
2014/09/02 职场文书
蛋糕店创业计划书范文
2014/09/21 职场文书
广告业务员岗位职责
2015/02/13 职场文书