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

Ant*_*ick 6 python lxml beautifulsoup html-parsing

例:

html = <a><b>Text</b>Text2</a>
Run Code Online (Sandbox Code Playgroud)

BeautifullSoup代码

[x.extract() for x in html.findAll(.//b)]
Run Code Online (Sandbox Code Playgroud)

在退出我们有:

html = <a>Text2</a>
Run Code Online (Sandbox Code Playgroud)

Lxml代码:

[bad.getparent().remove(bad) for bad in html.xpath(".//b")]
Run Code Online (Sandbox Code Playgroud)

在退出我们有:

html = <a></a>
Run Code Online (Sandbox Code Playgroud)

因为lxml认为"Text2"是它的尾巴 <b></b>

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

for bad in raw.xpath(xpath_search):
    bad.text = ''
Run Code Online (Sandbox Code Playgroud)

但是,如何在不更改文本的情况下执行此操作,但删除没有尾部的标

Jos*_*ker 8

虽然phlou接受的答案可行,但有更简单的方法可以在不删除标签的情况下删除标签.

如果要删除特定元素,那么您正在寻找的LXML方法是drop_tree.

来自文档:

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

如果要删除特定标记的所有实例,可以使用lxml.etree.strip_elementslxml.html.etree.strip_elements使用withtails=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_tag()
>>> tostring(html)
'<a>Text2</a>'
Run Code Online (Sandbox Code Playgroud)

要么

>>> 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)
'<a>Text2</a>'
Run Code Online (Sandbox Code Playgroud)

  • @TMikonos 谢谢,我的意思是输入“drop_tree”而不是“drop_tag”。我已经更新了该示例。 (2认同)

phl*_*lou 6

Edit:

Please look at @Joshmakers answer /sf/answers/3356272391/, which is clearly the better one.

我执行以下操作以将尾文本安全地保存到前一个兄弟或父级。

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
Run Code Online (Sandbox Code Playgroud)

HTH