iTesting软件测试知识分享

微信公众号开发系列--自动回复实现天气预报查询

上次我们讲了微信公众号的部署,今天我们来实现一个小功能,自动回复天气预报的播报。

使用方法如下: 在iTesting公众号里直接回复 “城市 天气”,将会把上海最近的天气信息返回给你, 例如输入上海 天气 , 会返回给你上海的天气情况。

通过仔细阅读微信开发文档,我们知道:

当用户发送消息给公众号时(或某些特定的用户操作引发的事件推送时),会产生一个POST请求,开发者可以在响应包(Get)中返回特定XML结构,来对该消息进行响应(现支持回复文本、图片、图文、语音、视频、音乐)。严格来说,发送被动响应消息其实并不是一种接口,而是对微信服务器发过来消息的一次回复。

简单来说,当你输入信息要求微信服务器返回你一个信息时,是在做一个Post请求,这个post请求是text格式的,微信收到会转给你自己的服务器,你的服务器处理好后,按照微信的要求把内容返回,然后你就可以看到回复了。
原理知道了,那么如何开发?步骤如下:

  1. 首先把回复的xml准备好,放在文件里,例如 txt_message.xml.

    1
    2
    3
    4
    5
    6
    <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>
  2. 调用天气预报API生成天气。

    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
    # -*- coding: UTF-8 -*-
    import sys
    reload(sys)
    sys.setdefaultencoding("utf-8")
    import requests
    import settings
    class GetWeather(object):
    headers = {'apikey': settings.baidu_apikey}
    def get_city_code(self, city):
    url = 'http://apis.baidu.com/apistore/weatherservice/citylist?cityname=%s'%city
    r = 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 content
    else:
    return "您输入的城市有误,请重新输入."
    else:
    return "您输入的城市有误,请重新输入."
    if __name__ == "__main__":
    w = GetWeather()
    print w.get_weather('上海')
  3. 把上述步骤里得到的返回值,嵌入到step1的变量里,返回给微信Server。具体做法:

    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
    @app.route('/', methods=['GET', 'POST'])
    def wechat():
    if request.method == 'GET':
    if len(request.args) > 0:
    temparr = []
    token = settings.token
    signature = 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.text
    msgtype = msg['MsgType']
    tou = msg['ToUserName']
    fromu = msg['FromUserName']
    time_str = str(int(time.time()))
    if msgtype == "event":
    event_msg = xml_raw.find('Event').text
    print event_msg
    if event_msg == "subscribe":
    sub_content = settings.welcome_message
    else:
    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数据,处理后返回结果,我们收到结果后,自己写代码处理完毕,再按照微信要求的格式传给我们的服务器,服务器接收后,展示或者返回相应结果。

到现在为止,我们基本解锁了微信开发,高大上的微信开发也不过是接口测试而已。。。

我相信通过上述解释大家肯定可以实现更多好玩的功能了, 大家可以尝试下我写的自动回复机器人功能,有问题直接留言给我, 我会答疑解惑:)

🐶 您的支持将鼓励我继续创作 🐶
-------------评论, 吐槽, 学习交流,请关注微信公众号 iTesting-------------
请关注微信公众号 iTesting wechat
扫码关注,跟作者互动