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中itertools模块用法详解
Sep 25 Python
在Python的web框架中配置app的教程
Apr 30 Python
Python中random模块生成随机数详解
Mar 10 Python
Python中文分词实现方法(安装pymmseg)
Jun 14 Python
Python实现一个简单的验证码程序
Nov 03 Python
python使用Tkinter实现在线音乐播放器
Jan 30 Python
python3.6使用urllib完成下载的实例
Dec 19 Python
Python常用爬虫代码总结方便查询
Feb 25 Python
10款最好的Python开发编辑器
Jul 03 Python
解决pycharm下os.system执行命令返回有中文乱码的问题
Jul 07 Python
终于搞懂了Keras中multiloss的对应关系介绍
Jun 22 Python
python3爬虫中多线程进行解锁操作实例
Nov 25 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
escape unescape的php下的实现方法
2007/04/27 PHP
php5.2以下版本无json_decode函数的解决方法
2014/05/25 PHP
PHP实现事件机制的方法
2015/07/10 PHP
PHP获取input输入框中的值去数据库比较显示出来
2016/11/16 PHP
php实现XML和数组的相互转化功能示例
2017/02/08 PHP
JS 字符串连接[性能比较]
2009/05/10 Javascript
js 点击页面其他地方关闭弹出层(示例代码)
2013/12/24 Javascript
动态加载脚本提升javascript性能
2014/02/24 Javascript
jquery实现通用版鼠标经过淡入淡出效果
2014/06/15 Javascript
js获取页面description的方法
2015/05/21 Javascript
javascript实现抽奖程序的简单实例
2016/06/07 Javascript
详解vue+vueRouter+webpack的简单实例
2017/06/17 Javascript
JavaScript中常见的八个陷阱总结
2017/06/28 Javascript
基于Require.js使用方法(总结)
2017/10/26 Javascript
解决Js先触发失去焦点事件再执行点击事件的问题
2018/08/30 Javascript
Vue强制组件重新渲染的方法讨论
2020/02/03 Javascript
OpenLayer学习之自定义测量控件
2020/09/28 Javascript
[44:40]Serenity vs Pain 2018国际邀请赛小组赛BO2 第一场 8.19
2018/08/21 DOTA
[37:29]完美世界DOTA2联赛PWL S2 LBZS vs Forest 第二场 11.19
2020/11/19 DOTA
Python中isnumeric()方法的使用简介
2015/05/19 Python
django+js+ajax实现刷新页面的方法
2017/05/22 Python
django加载本地html的方法
2018/05/27 Python
Python基础类继承重写实现原理解析
2020/04/03 Python
python中Mako库实例用法
2020/12/31 Python
Araks官网:纽约内衣品牌
2020/10/15 全球购物
Hotels.com韩国:海外国内旅行所需的酒店和住宿预订网站
2020/05/08 全球购物
院药学专业个人求职信
2013/09/21 职场文书
拉丁舞学习者的自我评价
2013/10/27 职场文书
财务会计专业求职信
2014/06/09 职场文书
高一军训的心得体会
2014/09/01 职场文书
模范教师事迹材料
2014/12/16 职场文书
社区六一儿童节活动总结
2015/02/11 职场文书
护士辞职信怎么写
2015/02/27 职场文书
慰问信格式规范
2015/03/23 职场文书
2015年公共机构节能宣传周活动总结
2015/03/26 职场文书
2016年寒假政治学习心得体会
2015/10/09 职场文书