最近忙國賽的一個項目,我得做一個微信公眾號。功能就是調數據并回復給用戶,需要用戶發送給公眾號一個關鍵詞,通過關鍵詞自動回復消息。
這時就是查詢微信公眾平臺文檔了,地址如下: 文檔
按照它的入門指南,我基本上了解了用戶給公眾號發送消息的一個機制,并且一旦給公眾號發送消息,在開發者后臺,會收到公眾平臺發送的一個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
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持億速云。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。