Python lxml的XPath没有在<p>标签

时间:2015-10-24 14:30:00

标签: python xpath lxml

我对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>或其他任何内容那件事。)

更新:收到回复后更新了标题,以便让遇到相同问题的人更容易找到此问题。

2 个答案:

答案 0 :(得分:2)

ul个元素(或更一般地flow content)是not allowed inside p elements(只能包含phrasing content)。因此,lxml.htmltext解析为

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,例如