最近忙国赛的一个项目,我得做一个微信公众号。功能就是调数据并回复给用户,需要用户发送给公众号一个关键词,通过关键词自动回复消息。
这时就是查询微信公众平台文档了,地址如下: 文档
按照它的入门指南,我基本上了解了用户给公众号发送消息的一个机制,并且一旦给公众号发送消息,在开发者后台,会收到公众平台发送的一个xml,所以通过编写Python脚本进行xml的解析与自动发送功能。
如果用户给公众号发送一段text消息,比如“hello”,那么后台就会收到一个xml为:
1
2
3
4
5
6
7
|
< 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
1
2
3
4
5
6
7
8
9
10
11
12
|
# -*- 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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
|
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换了一下而已,内容自己定。
1
2
3
4
5
6
7
|
< xml > < ToUserName > <![CDATA[粉丝号]]> </ ToUserName > < FromUserName > <![CDATA[公众号]]> </ FromUserName > < CreateTime >1460541339</ CreateTime > < MsgType > <![CDATA[text]]> </ MsgType > < Content > <![CDATA[test]]> </ Content > </ xml > |
reply.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
|
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
|
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文件解析
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
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
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。
原文链接:https://blog.csdn.net/karry_zzj/article/details/78451901