上次我们讲了微信公众号的部署,今天我们来实现一个小功能,自动回复天气预报的播报。
使用方法如下: 在iTesting公众号里直接回复 “城市 天气”,将会把上海最近的天气信息返回给你, 例如输入上海 天气 , 会返回给你上海的天气情况。
通过仔细阅读微信开发文档,我们知道:
当用户发送消息给公众号时(或某些特定的用户操作引发的事件推送时),会产生一个POST请求,开发者可以在响应包(Get)中返回特定XML结构,来对该消息进行响应(现支持回复文本、图片、图文、语音、视频、音乐)。严格来说,发送被动响应消息其实并不是一种接口,而是对微信服务器发过来消息的一次回复。
简单来说,当你输入信息要求微信服务器返回你一个信息时,是在做一个Post请求,这个post请求是text格式的,微信收到会转给你自己的服务器,你的服务器处理好后,按照微信的要求把内容返回,然后你就可以看到回复了。
原理知道了,那么如何开发?步骤如下:
首先把回复的xml准备好,放在文件里,例如 txt_message.xml.
123456<xml><ToUserName><![CDATA[{to_user}]]></ToUserName><FromUserName><![CDATA[{from_user}]]></FromUserName><CreateTime>{c_time}</CreateTime><MsgType><![CDATA[text]]></MsgType><Content><![CDATA[{content_value}]]></Content></xml>调用天气预报API生成天气。
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950# -*- coding: UTF-8 -*-import sysreload(sys)sys.setdefaultencoding("utf-8")import requestsimport settingsclass GetWeather(object):headers = {'apikey': settings.baidu_apikey}def get_city_code(self, city):url = 'http://apis.baidu.com/apistore/weatherservice/citylist?cityname=%s'%cityr = requests.get(url, headers=self.headers)j = r.json()['retData']for i in j:if i['name_cn'] == city:return i['area_id']def get_weather(self, city):city_code = self.get_city_code(city)url = 'http://apis.baidu.com/apistore/weatherservice/recentweathers?cityname={}&cityid={}'.format(city, city_code)r = requests.get(url, headers=self.headers)raw_data = r.json()if raw_data.has_key("retData"):if type(raw_data['retData']) == dict:j = raw_data['retData']['today']content = "今日{city}的天气情况如下:\n" \"日期:{date}," \"{week}, " \"当前温度:{curTemp}, " \"{type}, {fengxiang}, {fengli}" \"最高气温:{hightemp}, " \"最低气温:{lowtemp}, " \"PM值:{aqi}" .format(city=city, date=j['date'], week=j['week'], curTemp=j['curTemp'],type=j['type'],\fengxiang=j['fengxiang'], fengli=j['fengli'], hightemp=j['hightemp'],\lowtemp=j['lowtemp'], aqi=j['aqi'])return contentelse:return "您输入的城市有误,请重新输入."else:return "您输入的城市有误,请重新输入."if __name__ == "__main__":w = GetWeather()print w.get_weather('上海')把上述步骤里得到的返回值,嵌入到step1的变量里,返回给微信Server。具体做法:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778def wechat():if request.method == 'GET':if len(request.args) > 0:temparr = []token = settings.tokensignature = request.args["signature"]timestamp = request.args["timestamp"]nonce = request.args["nonce"]echostr = request.args["echostr"]temparr.append(token)temparr.append(timestamp)temparr.append(nonce)temparr.sort()newstr = "".join(temparr)sha1str = hashlib.sha1(newstr)temp = sha1str.hexdigest()if signature == temp:return make_response(echostr)else:return make_response("Access denied")else:return make_response("Wrong args received")else:raw_data = request.stream.read()xml_raw = ET.fromstring(raw_data)msg = {}for child in xml_raw:msg[child.tag] = child.textmsgtype = msg['MsgType']tou = msg['ToUserName']fromu = msg['FromUserName']time_str = str(int(time.time()))if msgtype == "event":event_msg = xml_raw.find('Event').textprint event_msgif event_msg == "subscribe":sub_content = settings.welcome_messageelse:sub_content = "error"xml_reader = XMLHelper().read_xml("txt_message.xml")response = make_response(xml_reader.format(to_user=fromu, from_user=tou, c_time=time_str, content_value=sub_content))elif msgtype == "image":media_id = msg['MediaId']xml_reader = XMLHelper().read_xml("img_message.xml")response = make_response(xml_reader.format(to_user=fromu, from_user=tou, c_time=time_str, media_id=media_id))elif msgtype == "voice":media_id = msg['MediaId']xml_reader = XMLHelper().read_xml("voice_message.xml")response = make_response(xml_reader.format(to_user=fromu, from_user=tou, c_time=time_str, media_id=media_id))elif msgtype == 'text':# co = xml_raw.find('Content').text.strip().split(' ')# if co[len(co)-1] == '天气':# weather = GetWeather()# auto_response_content = weather.get_weather(co[:-1][0])# else:r = RobotHelper()auto_response_content = r.get_robot(xml_raw.find('Content').text)xml_reader = XMLHelper().read_xml("txt_message.xml")response = make_response(xml_reader.format(to_user=fromu, from_user=tou, c_time=time_str, content_value=auto_response_content))elif msgtype in ["video","shortvideo"]:title = "My video"description = "Check out my video"media_id = msg['MediaId']xml_reader = XMLHelper().read_xml("video_message.xml")response = make_response(xml_reader.format(to_user=fromu, from_user=tou, c_time=time_str, media_id=media_id, title=title, description=description))else:unknown_content = u"""我不知道你在干什么,无法回复你"""xml_reader = XMLHelper().read_xml("txt_message.xml")response = make_response(xml_reader.format(to_user=fromu, from_user=tou, c_time=time_str, content_value=unknown_content))response.content_type = 'application/xml'return response
这样就实现了基于文本格式的天气预报功能,是不是没有那么难?
其实,如果你仔细研究下微信开发文档你就发现,微信开发的本质是接口测试,不过接口测试的结果被我们的服务器拿来使用,变成了一个个功能而已。
怎么理解呢?我们开发一个个功能时,实际上就是一次次对微信接口发起请求,微信通过开放给我们一个个接口,接收按照固定格式的post数据,处理后返回结果,我们收到结果后,自己写代码处理完毕,再按照微信要求的格式传给我们的服务器,服务器接收后,展示或者返回相应结果。
到现在为止,我们基本解锁了微信开发,高大上的微信开发也不过是接口测试而已。。。
我相信通过上述解释大家肯定可以实现更多好玩的功能了, 大家可以尝试下我写的自动回复机器人功能,有问题直接留言给我, 我会答疑解惑:)