在Python中使用xpath和lxml抓取数据的问题

时间:2015-01-14 16:25:08

标签: python xpath lxml

我试图抓住BC_1YEAR和NEW_DATE的内容,查看this data中的最后一个条目。

这是我的Google App Engine的Python代码:

import lxml.etree
from google.appengine.api import urlfetch

def foo():
    url = 'http://data.treasury.gov/feed.svc/DailyTreasuryYieldCurveRateData$filter=month(NEW_DATE)%20eq%201%20and%20year(NEW_DATE)%20eq%202015'
    response = urlfetch.fetch(url)
    tree = lxml.etree.fromstring(response.content)
    nsmap = {'atom': 'http://www.w3.org/2005/Atom',
             'd': 'http://schemas.microsoft.com/ado/2007/08/dataservices'}
    myData = tree.xpath("//atom:entry[last()]/d:BC_1YEAR", namespaces=nsmap)

但myData是一个空列表,而今天的数据应该是0.2。我已经花了好几个小时才开始工作,所以任何帮助都会非常感激。我假设NEW_DATE的工作方式类似。

1 个答案:

答案 0 :(得分:1)

据我所知,正确的网址是

http://data.treasury.gov/feed.svc/DailyTreasuryYieldCurveRateData?$filter=month%28NEW_DATE%29%20eq%201%20and%20year%28NEW_DATE%29%20eq%202015

而在您的代码中,?之后没有Data

http://data.treasury.gov/feed.svc/DailyTreasuryYieldCurveRateData$filter=month%28NEW_DATE%29%20eq%201%20and%20year%28NEW_DATE%29%20eq%202015

这就是您的代码当前生成以下XML的原因:

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<error xmlns="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata">
  <code></code>
  <message xml:lang="en-US">Resource not found for the segment 'DailyTreasuryYieldCurveRateData$filter=month'.</message>
</error>

当然,该错误消息中没有atom:entry


此外,您的XPath表达式:

//atom:entry[last()]/d:BC_1YEAR

不会检索d:BC_1YEAR,因为d:BC_1YEAR不是atom:entry的直接子项。使用

//atom:entry[last()]//d:BC_1YEAR

或者更好的是,在代码中注册m:前缀并使用

//atom:entry[last()]/atom:content/m:properties/d:BC_1YEAR

import lxml.etree
from google.appengine.api import urlfetch

def foo():
    url = 'http://data.treasury.gov/feed.svc/DailyTreasuryYieldCurveRateData?$filter=month%28NEW_DATE%29%20eq%201%20and%20year%28NEW_DATE%29%20eq%202015'
    response = urlfetch.fetch(url)
    tree = lxml.etree.fromstring(response.content)
    nsmap = {'atom': 'http://www.w3.org/2005/Atom',
             'd': 'http://schemas.microsoft.com/ado/2007/08/dataservices',
             'm': 'http://schemas.microsoft.com/ado/2007/08/dataservices/metadata'}
    myData = tree.xpath("//atom:entry[last()]/atom:content/m:properties/d:BC_1YEAR", namespaces=nsmap)

编辑:作为对您评论的回复:

  

我希望我的代码可以无限期地使用&#39;尽可能少的维护。我不知道命名空间的目的是什么,我想知道这些特定的命名空间是否是通用的,并且可以预期在未来几年保持这种状态?

我已经explained the purpose of namespaces in XML elsewhere了 - 请看一下这个答案。命名空间永远不是通用的,事实上,它们与泛型完全相反 - 它们应该是唯一的

也就是说,有一些方法可以忽略命名空间。像

这样的表达式
//atom:entry[last()]//d:BC_1YEAR

可以改写为

//*[local-name() = 'entry'][last()]//*[local-name() = 'BC_1YEAR']

查找元素而不管其名称空间。如果您有理由相信命名空间URI将来会发生变化,那么这将是一个选项。