我对pythons lxml的XPath函数有问题。一个最小的例子是以下python代码:
from lxml import html, etree
text = """
<p class="goal">
<strong>Goal</strong> <br />
<ul><li>test</li></ul>
</p>
"""
tree = html.fromstring(text)
thesis_goal = tree.xpath('//p[@class="goal"]')[0]
print etree.tostring(thesis_goal)
运行代码会产生
<p class="goal">
<strong>Goal</strong> <br/>
</p>
如您所见,整个<ul>
块都丢失了。这也意味着无法使用<ul>
的XPath来解决//p[@class="goal"]/ul
,因为<ul>
不会被视为<p>
的子级。
这是lxml的错误还是功能,如果是后者,我如何才能访问<p>
的全部内容?该内容嵌入在一个较大的网站中,并且无法保证甚至 一个<ul>
标记(内部可能还有另一个<p>
或其他任何内容那件事。)
更新:收到回复后更新了标题,以便让遇到相同问题的人更容易找到此问题。
答案 0 :(得分:2)
ul
个元素(或更一般地flow content)是not allowed inside p
elements(只能包含phrasing content)。因此,lxml.html
将text
解析为
In [45]: print(html.tostring(tree))
<div><p class="goal">
<strong>Goal</strong> <br>
</p><ul><li>test</li></ul>
</div>
ul
跟在p
元素之后。所以你可以使用XPath找到ul
元素
In [47]: print(html.tostring(tree.xpath('//p[@class="goal"]/following::ul')[0]))
<ul><li>test</li></ul>
答案 1 :(得分:2)
@unutbu有正确的答案。您的HTML无效,html解析器将产生意外结果。正如在lxml文档中所述,
解析破坏的HTML的支持完全取决于libxml2 恢复算法。如果你找到文件,这不是lxml的错 如此严重破坏,解析器无法处理它们。那里 也不能保证生成的树将包含所有数据 来自原始文件。解析器可能不得不严重丢弃 在努力保持解析时破碎的部分。特别放错地方 元标记可能会受此影响,这可能会导致编码问题。
根据您要实现的目标,您可以回退到xml解析器
# Changing html to etree here will produce behaviour you expect
tree = etree.fromstring(text)
或转移到更高级的网站解析包,例如BeautifulSoup4,例如