如何从没有尾巴的lxml中的节点删除标签?

Posted

技术标签:

【中文标题】如何从没有尾巴的lxml中的节点删除标签?【英文标题】:How delete tag from node in lxml without tail? 【发布时间】:2017-08-13 10:57:11 【问题描述】:

例子:

html = <a><b>Text</b>Text2</a>

美人汤代码

[x.extract() for x in html.findAll(.//b)]

在出口我们有:

html = <a>Text2</a>

Lxml代码:

[bad.getparent().remove(bad) for bad in html.xpath(".//b")]

在出口我们有:

html = <a></a>

因为 lxml 认为“Text2”是&lt;b&gt;&lt;/b&gt; 的尾巴

如果我们只需要标签连接中的文本行,我们可以使用:

for bad in raw.xpath(xpath_search):
    bad.text = ''

但是,如何在不更改文本的情况下删除没有尾部的标签?

【问题讨论】:

不确定我是否正确理解了您的问题,但也许drop_tag 可能会有所帮助? @phoibos,感谢您的回答,但不,drop_tag,只需删除 self 标记并将文本保存在其中,但还需要一些其他内容。我们有 foobar 如果我们在 结果上使用 drop_tag 我们得到 foo bar 但在结果中需要 bar . 【参考方案1】:

虽然从 phlou 接受的答案会起作用,但有更简单的方法可以删除标签而不删除它们的尾巴。

如果你想删除一个特定的元素,那么你正在寻找的 LXML 方法是drop_tree

来自文档:

删除元素及其所有子元素。与 el.getparent().remove(el) 不同,它不会删除尾部文本;使用 drop_tree,尾部文本与前一个元素合并。

如果要删除特定标记的所有实例,可以将lxml.etree.strip_elementslxml.html.etree.strip_elementswith_tail=False 结合使用。

从树中删除所有具有提供的标签名称的元素或 子树。这将删除元素及其整个子树, 包括它们的所有属性、文本内容和后代。它 还将删除元素的尾部文本,除非您 将 with_tail 关键字参数选项显式设置为 False。

因此,对于原始帖子中的示例:

>>> from lxml.html import fragment_fromstring, tostring
>>>
>>> html = fragment_fromstring('<a><b>Text</b>Text2</a>')
>>> for bad in html.xpath('.//b'):
...    bad.drop_tree()
>>> tostring(html, encoding="unicode")
'<a>Text2</a>'

>>> from lxml.html import fragment_fromstring, tostring, etree
>>>
>>> html = fragment_fromstring('<a><b>Text</b>Text2</a>')
>>> etree.strip_elements(html, 'b', with_tail=False)
>>> tostring(html, encoding="unicode")
'<a>Text2</a>'

【讨论】:

根据 drop_tag 的帮助,它还保留了文本。结果应该是:TextText2 @TMikonos 谢谢,我的意思是输入drop_tree 而不是drop_tag。我已经更新了那个例子。【参考方案2】:

编辑:

请看@Joshmakers 答案https://***.com/a/47946748/8055036,这显然是更好的答案。

我执行以下操作以将尾部文本保护到前一个兄弟或父级。

def remove_keeping_tail(self, element):
    """Safe the tail text and then delete the element"""
    self._preserve_tail_before_delete(element)
    element.getparent().remove(element)

def _preserve_tail_before_delete(self, node):
    if node.tail: # preserve the tail
        previous = node.getprevious()
        if previous is not None: # if there is a previous sibling it will get the tail
            if previous.tail is None:
                previous.tail = node.tail
            else:
                previous.tail = previous.tail + node.tail
        else: # The parent get the tail as text
            parent = node.getparent()
            if parent.text is None:
                parent.text = node.tail
            else:
                parent.text = parent.text + node.tail

HTH

【讨论】:

以上是关于如何从没有尾巴的lxml中的节点删除标签?的主要内容,如果未能解决你的问题,请参考以下文章

python爬虫lxml基本用法

如何遍历lxml对象的节点以查看属性是不是存在?

如何使用 JAVA 删除 XML 中的节点

如何使用 jquery 从没有任何 id 或类的 div 中删除锚标记?

LeetCode - 25. K 个一组翻转链表 -- java - 细节

P4556 [Vani有约会]雨天的尾巴 (线段树合并 + 树上差分)