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 相关文章推荐
tornado捕获和处理404错误的方法
Feb 26 Python
python实现多线程暴力破解登陆路由器功能代码分享
Jan 04 Python
Python与人工神经网络:使用神经网络识别手写图像介绍
Dec 19 Python
python中使用print输出中文的方法
Jul 16 Python
浅谈django orm 优化
Aug 18 Python
详解numpy的argmax的具体使用
May 27 Python
python实现五子棋游戏
Jun 18 Python
python 的 scapy库,实现网卡收发包的例子
Jul 23 Python
浅谈Python 敏感词过滤的实现
Aug 15 Python
Pandas DataFrame中的tuple元素遍历的实现
Oct 23 Python
解决python脚本中error: unrecognized arguments: True错误
Apr 20 Python
python可视化分析的实现(matplotlib、seaborn、ggplot2)
Feb 03 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 json_encode奇怪问题说明
2011/09/27 PHP
PHP中构造函数和析构函数解析
2014/10/10 PHP
php递归删除指定文件夹的方法小结
2015/04/20 PHP
typecho插件编写教程(三):保存配置
2015/05/28 PHP
php、java、android、ios通用的3des方法(推荐)
2016/09/09 PHP
详解no input file specified 三种解决方法
2019/11/29 PHP
JQuery 入门实例1
2009/06/25 Javascript
javascript 动态table添加colspan\rowspan 参数的方法
2009/07/25 Javascript
js汉字排序问题 支持中英文混排,兼容各浏览器,包括CHROME
2011/12/20 Javascript
JavaScript 5 新增 Array 方法实现介绍
2012/02/06 Javascript
原生javascript兼容性测试实例
2013/07/01 Javascript
jquery实现叠层3D文字特效代码分享
2015/08/21 Javascript
利用jQuery及AJAX技术定时更新GridView的某一列数据
2015/12/04 Javascript
JQuery ztree 异步加载实例讲解
2016/02/25 Javascript
利用Angularjs和原生JS分别实现动态效果的输入框
2016/09/01 Javascript
详解AngularJS中ng-src指令的使用
2016/09/07 Javascript
js html5 css俄罗斯方块游戏再现
2016/10/17 Javascript
javascript实现获取图片大小及图片等比缩放的方法
2016/11/24 Javascript
nodejs制作爬虫实现批量下载图片
2017/05/19 NodeJs
浅谈Node.js 沙箱环境
2018/05/15 Javascript
如何为你的JS项目添加智能提示与类型检查详解
2019/03/12 Javascript
ES6 class类链式继承,实例化及react super(props)原理详解
2020/02/15 Javascript
[47:42]Fnatic vs Liquid 2018国际邀请赛小组赛BO2 第一场 8.16
2018/08/17 DOTA
python rsa 加密解密
2017/03/20 Python
python pandas模块基础学习详解
2019/07/03 Python
python GUI库图形界面开发之PyQt5开发环境配置与基础使用
2020/02/25 Python
python爬虫工具例举说明
2020/11/30 Python
墨尔本复古时尚品牌:Dangerfield
2018/12/12 全球购物
全球领先的在线cosplay服装商店:RoleCosplay
2020/01/18 全球购物
新郎婚宴答谢词
2014/01/19 职场文书
企业新年寄语
2014/04/04 职场文书
劳资协议书范本
2014/04/23 职场文书
学生个人评语大全
2015/01/04 职场文书
入党积极分子群众意见
2015/06/01 职场文书
Python中threading库实现线程锁与释放锁
2021/05/17 Python
python 爬取京东指定商品评论并进行情感分析
2021/05/27 Python