Discuss / Python / 练习

练习

Topic source

xian_wen

#1 Created at ... [Delete] [Delete and Lock User]

高德地图天气查询 api 获取实时天气:

# -*- coding: utf-8 -*-
# @author xian_wen
# @date 5/14/2021 5:47 PM

from urllib import request
from xml.parsers.expat import ParserCreate


def parseXml(xml_str):
    """
    利用 SAX 解析高德地图的 XML 格式的天气预报

    获取实时天气:
    https://restapi.amap.com/v3/weather/weatherInfo?city=<城市编码>&key=<用户key>&output=xml
    获取预报天气:
    https://restapi.amap.com/v3/weather/weatherInfo?city=<城市编码>&key=<用户key>&extensions=all&output=xml

    :param xml_str: XML 格式的天气预报
    :return: 当前城市实时天气预报结果
    """
    print(xml_str)
    handler = DefaultSaxHandler()
    parser = ParserCreate()
    parser.StartElementHandler = handler.start_element
    parser.EndElementHandler = handler.end_element
    parser.CharacterDataHandler = handler.char_element
    parser.Parse(xml_str)
    data = handler.data
    return {
        'city': data['city'],
        'live': {
            'data': data['reporttime'],
            'weather': data['weather'],
            'temperature': data['temperature']
        }
    }


class DefaultSaxHandler(object):
    def __init__(self):
        self.name = ''
        self.data = {}

    def start_element(self, name, attrs):
        self.name = name
        print('sax:start_element: %s, attrs: %s' % (name, str(attrs)))

    def end_element(self, name):
        print('sax:end_element: %s' % name)

    def char_element(self, text):
        self.data[self.name] = text
        print('sax:char_data: %s' % text)


# 测试
ZIPCODE = 110000  # 北京市城市编码
AMAP_WEB_SERVICE_KEY = '<Your Key>'  # Web服务Key替换成自己的
URL = 'https://restapi.amap.com/v3/weather/weatherInfo?city=%s&key=%s&output=xml' % (ZIPCODE, AMAP_WEB_SERVICE_KEY)

with request.urlopen(URL, timeout=4) as f:
    data = f.read()

result = parseXml(data.decode('utf-8'))
print(result)
assert result['city'] == '北京市'

实时天气 XML 结果:

<response>
    <status>1</status>
    <count>1</count>
    <info>OK</info>
    <infocode>10000</infocode>
    <lives type="list">
        <live>
            <province>北京</province>
            <city>北京市</city>
            <adcode>110000</adcode>
            <weather>多云</weather>
            <temperature>21</temperature>
            <winddirection>东</winddirection>
            <windpower>≤3</windpower>
            <humidity>72</humidity>
            <reporttime>2021-05-14 19:33:56</reporttime>
        </live>
    </lives>
</response>

预报天气 XML 结果:

<response>
    <status>1</status>
    <count>1</count>
    <info>OK</info>
    <infocode>10000</infocode>
    <forecasts type="list">
        <forecast>
            <city>北京市</city>
            <adcode>110000</adcode>
            <province>北京</province>
            <reporttime>2021-05-14 18:33:48</reporttime>
            <casts type="list">
                <cast>
                    <date>2021-05-14</date>
                    <week>5</week>
                    <dayweather>多云</dayweather>
                    <nightweather>小雨</nightweather>
                    <daytemp>26</daytemp>
                    <nighttemp>17</nighttemp>
                    <daywind>东南</daywind>
                    <nightwind>东南</nightwind>
                    <daypower>≤3</daypower>
                    <nightpower>≤3</nightpower>
                </cast>
                <cast>
                    <date>2021-05-15</date>
                    <week>6</week>
                    <dayweather>小雨</dayweather>
                    <nightweather>小雨</nightweather>
                    <daytemp>21</daytemp>
                    <nighttemp>14</nighttemp>
                    <daywind>北</daywind>
                    <nightwind>北</nightwind>
                    <daypower>4</daypower>
                    <nightpower>4</nightpower>
                </cast>
                <cast>
                    <date>2021-05-16</date>
                    <week>7</week>
                    <dayweather>多云</dayweather>
                    <nightweather>晴</nightweather>
                    <daytemp>25</daytemp>
                    <nighttemp>13</nighttemp>
                    <daywind>西</daywind>
                    <nightwind>西</nightwind>
                    <daypower>≤3</daypower>
                    <nightpower>≤3</nightpower>
                </cast>
                <cast>
                    <date>2021-05-17</date>
                    <week>1</week>
                    <dayweather>晴</dayweather>
                    <nightweather>晴</nightweather>
                    <daytemp>30</daytemp>
                    <nighttemp>15</nighttemp>
                    <daywind>西南</daywind>
                    <nightwind>西南</nightwind>
                    <daypower>≤3</daypower>
                    <nightpower>≤3</nightpower>
                </cast>
            </casts>
        </forecast>
    </forecasts>
</response>

存在问题:

天气预报数据只需在url中添加参数extensions=all,即可获得之后数日的天气情况,但需要改写DefaultSaxHandler类。

当前类的实现,会自动覆盖之前的天气数据,因为不同 date 各结点名称相同,以至于输出的 dict 后面的天气数据会自动覆盖前面的天气数据,最终只留下了最后一天即 17 号的天气。希望大神能帮忙改写成功。

我的方法,定义一个下标,当遇到<cast>时自增1

# 导入模块

import xml.sax

from urllib import request

class WeatherHandler(xml.sax.ContentHandler):

    def __init__(self):

        self.currentdata = ''

        self.province = ''

        self.date = ''

        self.daytemp = ''

        self.nighttemp = ''

        # 定义下标

        self.number = -1

        # 定义返回的字典

        self.weather_dict = {

        'city': '',

        'forecast': [

            {

                'date': '',

                'high': '',

                'low' : ''

            },

            {

                'date': '',

                'high': '',

                'low' : ''

            },

            {

                'date': '',

                'high': '',

                'low' : ''

            }, 

            {

                'date': '',

                'high': '',

                'low' : ''

            }

        ]

    }

    # 定义开始处理事件

    def startElement(self,name,attrs):

        self.currentdata = name

        if self.currentdata == 'cast':

            self.number += 1 

    # 定义标签处理标签直接内部文本事件 text为标签之间的文本

    def characters(self,text):

        if self.currentdata == 'province':

            self.weather_dict['city'] = text

        if self.currentdata == 'date':

            self.weather_dict['forecast'][self.number]['date'] = text

        elif self.currentdata == 'daytemp':

            self.weather_dict['forecast'][self.number]['high'] = text

        elif self.currentdata == 'nighttemp':

            self.weather_dict['forecast'][self.number]['low'] = text

    # 定义标签结尾事件即遇到</str>

    def endElement(self,name):

        pass

    def weather_return(self):

        return self.weather_dict

def parseXml(xml_str):

    H = WeatherHandler()

    xml.sax.parseString(xml_str,H)

    weather = H.weather_return()

    return weather

#  获取天气xml

citycode = '110101'

key = "Your key"

URL = "https://restapi.amap.com/v3/weather/weatherInfo?extensions=all&output=XML&city=%s&key=%s" %(citycode,key)

with request.urlopen(URL,timeout=4) as f:

    data = f.read()

result = parseXml(data.decode('utf-8'))

print(result)

assert result['city'] == '北京'

# 交作业,使用dom方式解析

# 导入模块

import xml.dom.minidom

from urllib import request

def parseXml(xml_str):

    #print(xml_str)

    # 使用parseString得到文档对象

    weather_document = xml.dom.minidom.parseString(xml_str)

    # 通过标签'province'得到city信息

    city = weather_document.getElementsByTagName('province')[0].firstChild.data

    # 通过标签'cast'得到文档信息,组成列表,本次天气预报有4个'cast'标签

    casts = weather_document.getElementsByTagName('cast')

    # 定义空列表分别用于存储日期,最高气温,和最低气温

    date = []

    high = []

    low = []

    # for遍历获取对应的日期,最高气温和最低气温

    for cast in casts:

        date.append(cast.getElementsByTagName('date')[0].firstChild.data)

        high.append(cast.getElementsByTagName('daytemp')[0].firstChild.data)

        low.append(cast.getElementsByTagName('nighttemp')[0].firstChild.data)

    # 返回

    return {

        'city': city,

        'forecast': [

            {

                'date': date[0],

                'high': high[0],

                'low' : low[0]

            },

            {

                'date': date[1],

                'high': high[1],

                'low' : low[1]

            },

            {

                'date': date[2],

                'high': high[2],

                'low' : low[2]

            },

            {

                'date': date[3],

                'high': high[3],

                'low' : low[3]

            }

        ]

    }

if __name__ == '__main__':

    # 利用高德地图获取天气信息格式为xml

    citycode = '110101'

    key = "Your key"

    URL = "https://restapi.amap.com/v3/weather/weatherInfo?extensions=all&output=XML&city=%s&key=%s" %(citycode,key)

    with request.urlopen(URL,timeout=4) as f:        

        weather_xml = f.read().decode('utf-8')

    #print(weather_xml)

    result = parseXml(weather_xml)

    #print(result)

    assert result['city'] == '北京'

    print('ok')


  • 1

Reply