【问题标题】:XML Parsing with ElementTree and Requests使用 ElementTree 和请求进行 XML 解析
【发布时间】:2014-06-26 20:22:54
【问题描述】:

我正在尝试使用 Yahoo Weather API,但在解析 API 响应的 XML 时遇到了一些问题。我正在使用Python 3.4。这是我正在使用的代码:

weather_url = 'http://weather.yahooapis.com/forecastrss?w=%s&u=%s'
url = weather_url % (zip_code, units)

try:
    rss = parse(requests.get(url, stream=True).raw).getroot()

    conditions = rss.find('channel/item/{%s}condition' % weather_ns)

    return {
        'current_condition': conditions.get('text'),
        'current_temp': conditions.get('temp'),
        'title': rss.findtext('channel/title')
    }
except:
    raise

这是我得到的堆栈跟踪:

Traceback (most recent call last):
  File "<input>", line 1, in <module>
  File "/home/jonathan/PycharmProjects/pyweather/pyweather/pyweather.py", line 42, in yahoo_conditions
    rss = parse(requests.get(url, stream=True).raw).getroot()
  File "/usr/lib/python3.4/xml/etree/ElementTree.py", line 1187, in parse
    tree.parse(source, parser)
  File "/usr/lib/python3.4/xml/etree/ElementTree.py", line 598, in parse
    self._root = parser._parse_whole(source)
  File "<string>", line None
xml.etree.ElementTree.ParseError: not well-formed (invalid token): line 1, column 0

xml.etree.ElementTree 解析函数不喜欢请求库返回的原始对象。深入研究一下,原始对象解析为

>>> r = requests.get('http://weather.yahooapis.com/forecastrss?w=2502265', stream=True)
>>> r.raw
<requests.packages.urllib3.response.HTTPResponse object at 0x7f32c24f9e48>

我引用了this solution,但它仍然导致同样的问题。为什么上面的方法不起作用? ElementTree.parse 函数不支持 urllib3 响应对象吗?我已经阅读了所有文档,但它们根本没有启发我。

文档列表在这里:

编辑: 经过更多的实验,我仍然没有找到解决上述问题的方法。但是,我找到了一种解决方法。如果对 XML 内容使用 ElementTree 的 fromstring 方法,一切正常。

def fetch_xml(url):
    """
    Fetch a url and parse the document's XML.

    :param url: the URL that the XML is located at.
    :return: the root element of the XML.
    :raises:
        :requests.exceptions.RequestException: Requests could not open the URL.
        :xml.etree.ElementTree.ParseError: xml.etree.ElementTree failed to parse the XML document.
    """

    return ET.fromstring(requests.get(url).content)

我想这种方法的缺点是它使用更多的内存。你怎么看?我想征求社区意见。

【问题讨论】:

    标签: xml python-3.x python-requests elementtree


    【解决方案1】:

    您为什么使用流式传输请求来下载一些 RSS XML 数据?您想始终保持连接打开吗?天气变化不会那么快,那么为什么不每 5 分钟轮询一次服务呢?

    以下是使用 BeautifulSoup 和请求进行投票和解析的完整代码。短而甜。

    import requests
    from bs4 import BeautifulSoup
    
    r = requests.get('http://weather.yahooapis.com/forecastrss?w=%s&u=%s' % (2459115, "c"))
    if r.status_code == 200:
        soup = BeautifulSoup(r.text)
        print("Current condition: ", soup.find("description").string)
        print("Temperature: ", soup.find('yweather:condition')['temp'])
        print("Title: ", soup.find("title").string)
    else:
        r.raise_for_status()
    

    输出:

    Current condition:  Yahoo! Weather for New York, NY
    Temperature:  28
    Title:  Yahoo! Weather - New York, NY
    

    您可以使用 Beautifulsoup 做更多事情。查看其出色的文档。

    【讨论】:

    • 我启用了“stream=True”,因为 API 需要它来获取原始数据。请参阅文档here。我的第二个解决方案更优雅且功能齐全。不过感谢建议的库,我得看看!
    【解决方案2】:

    如果对 XML 内容使用 ElementTree 的 fromstring 方法,一切正常。

    def fetch_xml(url):
        """
        Fetch a url and parse the document's XML.
    
        :param url: the URL that the XML is located at.
        :return: the root element of the XML.
        :raises:
            :requests.exceptions.RequestException: Requests could not open the URL.
            :xml.etree.ElementTree.ParseError: xml.etree.ElementTree failed to parse the XML document.
        """
    
        return ET.fromstring(requests.get(url).content)
    

    我想这种方法的缺点是它使用更多的内存。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-06-20
      • 1970-01-01
      • 2020-12-03
      • 2017-03-16
      • 1970-01-01
      • 2018-02-16
      • 1970-01-01
      相关资源
      最近更新 更多