XPath text() 没有获取 link 节点的文本
XPath text() does not get the text of a link node
from lxml import etree
import requests
htmlparser = etree.HTMLParser()
f = requests.get('https://rss.orf.at/news.xml')
# without the ufeff this would fail because it tells me: "ValueError: Unicode strings with encoding declaration are not supported. Please use bytes input or XML fragments without declaration."
tree = etree.fromstring('\ufeff'+f.text, htmlparser)
print(tree.xpath('//item/title/text()')) #<- this does produce a liste of titles
print(tree.xpath('//item/link/text()')) #<- this does NOT produce a liste of links why ?!?!
好吧,这对我来说有点神秘,也许我只是忽略了最简单的事情,但是 XPath '//item/link/text()'
确实只生成一个空列表,而 '//item/title/text()'
完全按照预期工作. <link>
节点是否有任何特殊用途?我可以 select 所有这些 '//item/link'
我只是无法获得 text()
select 或处理它们。
您正在使用 etree.HTMLParser
解析 XML 文档。我怀疑这是处理 XML 命名空间的尝试,但我认为这可能是错误的解决方案。可能将 XML 文档视为 HTML 最终是问题的根源。
如果我们改用 XML 解析器,一切都会按预期工作。
首先,如果我们查看根元素,我们会看到它设置了一个默认命名空间:
<rdf:RDF
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
xmlns:orfon="http://rss.orf.at/1.0/"
xmlns="http://purl.org/rss/1.0/"
>
这意味着当我们在文档中看到一个 item
元素时,它实际上是一个“item
in the http://purl.org/rss/1.0/
namespace”元素。我们需要通过传入 namespaces
字典并在元素名称上使用命名空间前缀来在我们的 xpath 查询中提供该命名空间信息,如下所示:
>>> tree.xpath('//rss:item', namespaces={'rss': 'http://purl.org/rss/1.0/'})
[<Element {http://purl.org/rss/1.0/}item at 0x7f0497000e80>, ...]
您的第一个 xpath 表达式(查看 /item/title/text()
)变为:
>>> tree.xpath('//rss:item/rss:title/text()', namespaces={'rss': 'http://purl.org/rss/1.0/'})
['Amnesty dokumentiert Kriegsverbrechen', ..., 'Moskauer Börse startet abgeschirmten Handel']
你的第二个 xpath 表达式(查看 /item/link/text()
)变为:
>>> tree.xpath('//rss:item/rss:link/text()', namespaces={'rss': 'http://purl.org/rss/1.0/'})
['https://orf.at/stories/3255477/', ..., 'https://orf.at/stories/3255384/']
这使得代码看起来像:
from lxml import etree
import requests
f = requests.get('https://rss.orf.at/news.xml')
tree = etree.fromstring(f.content)
print(tree.xpath('//rss:item/rss:title/text()', namespaces={'rss': 'http://purl.org/rss/1.0/'}))
print(tree.xpath('//rss:item/rss:link/text()', namespaces={'rss': 'http://purl.org/rss/1.0/'}))
请注意,通过使用 f.content
(字节字符串)而不是 f.text
(unicode 字符串),我们避免了整个 unicode 解析错误。
from lxml import etree
import requests
htmlparser = etree.HTMLParser()
f = requests.get('https://rss.orf.at/news.xml')
# without the ufeff this would fail because it tells me: "ValueError: Unicode strings with encoding declaration are not supported. Please use bytes input or XML fragments without declaration."
tree = etree.fromstring('\ufeff'+f.text, htmlparser)
print(tree.xpath('//item/title/text()')) #<- this does produce a liste of titles
print(tree.xpath('//item/link/text()')) #<- this does NOT produce a liste of links why ?!?!
好吧,这对我来说有点神秘,也许我只是忽略了最简单的事情,但是 XPath '//item/link/text()'
确实只生成一个空列表,而 '//item/title/text()'
完全按照预期工作. <link>
节点是否有任何特殊用途?我可以 select 所有这些 '//item/link'
我只是无法获得 text()
select 或处理它们。
您正在使用 etree.HTMLParser
解析 XML 文档。我怀疑这是处理 XML 命名空间的尝试,但我认为这可能是错误的解决方案。可能将 XML 文档视为 HTML 最终是问题的根源。
如果我们改用 XML 解析器,一切都会按预期工作。
首先,如果我们查看根元素,我们会看到它设置了一个默认命名空间:
<rdf:RDF
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
xmlns:orfon="http://rss.orf.at/1.0/"
xmlns="http://purl.org/rss/1.0/"
>
这意味着当我们在文档中看到一个 item
元素时,它实际上是一个“item
in the http://purl.org/rss/1.0/
namespace”元素。我们需要通过传入 namespaces
字典并在元素名称上使用命名空间前缀来在我们的 xpath 查询中提供该命名空间信息,如下所示:
>>> tree.xpath('//rss:item', namespaces={'rss': 'http://purl.org/rss/1.0/'})
[<Element {http://purl.org/rss/1.0/}item at 0x7f0497000e80>, ...]
您的第一个 xpath 表达式(查看 /item/title/text()
)变为:
>>> tree.xpath('//rss:item/rss:title/text()', namespaces={'rss': 'http://purl.org/rss/1.0/'})
['Amnesty dokumentiert Kriegsverbrechen', ..., 'Moskauer Börse startet abgeschirmten Handel']
你的第二个 xpath 表达式(查看 /item/link/text()
)变为:
>>> tree.xpath('//rss:item/rss:link/text()', namespaces={'rss': 'http://purl.org/rss/1.0/'})
['https://orf.at/stories/3255477/', ..., 'https://orf.at/stories/3255384/']
这使得代码看起来像:
from lxml import etree
import requests
f = requests.get('https://rss.orf.at/news.xml')
tree = etree.fromstring(f.content)
print(tree.xpath('//rss:item/rss:title/text()', namespaces={'rss': 'http://purl.org/rss/1.0/'}))
print(tree.xpath('//rss:item/rss:link/text()', namespaces={'rss': 'http://purl.org/rss/1.0/'}))
请注意,通过使用 f.content
(字节字符串)而不是 f.text
(unicode 字符串),我们避免了整个 unicode 解析错误。