Python元素树 - 从元素中提取文本,剥离标签

Posted

技术标签:

【中文标题】Python元素树 - 从元素中提取文本,剥离标签【英文标题】:Python element tree - extract text from element, stripping tags 【发布时间】:2013-10-22 14:08:23 【问题描述】:

使用 Python 中的 ElementTree,如何从节点中提取所有文本,剥离该元素中的所有标签并仅保留文本?

例如,假设我有以下内容:

<tag>
  Some <a>example</a> text
</tag>

我想返回Some example text。我该怎么做呢?到目前为止,我所采取的方法都产生了相当灾难性的后果。

【问题讨论】:

IIRC BeautifulSoup 有一些简单的方法可以解决这个问题... 点赞this 如果可能的话,我想避免使用额外的外部库 无疑这是不正确的(我认为),因为正则表达式对 XML 不利,但您可以尝试re.sub(r'\&lt;.*?\&gt;', '', text) 【参考方案1】:

如果你在 Python 3.2+ 下运行,你可以使用itertext

itertext 创建一个文本迭代器,它按文档顺序循环该元素和所有子元素,并返回所有内部文本:

import xml.etree.ElementTree as ET
xml = '<tag>Some <a>example</a> text</tag>'
tree = ET.fromstring(xml)
print(''.join(tree.itertext()))

# -> 'Some example text'

如果您在较低版本的 Python 中运行,则可以通过将 the implementation of itertext() 附加到 Element 类来重用它,之后您可以像上面一样调用它:

# original implementation of .itertext() for Python 2.7
def itertext(self):
    tag = self.tag
    if not isinstance(tag, basestring) and tag is not None:
        return
    if self.text:
        yield self.text
    for e in self:
        for s in e.itertext():
            yield s
        if e.tail:
            yield e.tail

# if necessary, monkey-patch the Element class
if 'itertext' not in ET.Element.__dict__:
    ET.Element.itertext = itertext

xml = '<tag>Some <a>example</a> text</tag>'
tree = ET.fromstring(xml)
print(''.join(tree.itertext()))

# -> 'Some example text'

【讨论】:

谢谢,找了一阵子!【参考方案2】:

Aslo 有一个非常简单的解决方案,以防可以使用 XPath。它被称为 XPath 轴:more about it can be found here。

当有一个节点(如标签div)本身包含文本和其他节点(如标签acenter或另一个div)内部有文本或它只包含文本时,我们要选择该div 节点中的所有文本,可以使用以下XPath:current_element.xpath("descendant-or-self::*/text()").extract()。我们将得到一个当前元素中所有文本的列表,如果有的话,去掉里面的标签。

它的好处是不需要递归函数,XPath 会处理所有这些(使用递归本身,但对我们来说它是尽可能干净的)。

Here is *** question concerning this proposed solution.

【讨论】:

n.b.:这仅适用于 lxmlxml.etree 包不知道足够的 XPath 来执行此操作。【参考方案3】:

如文档所述,如果您只想读取文本而不需要任何中间标签,则必须以正确的顺序递归连接所有 texttail 属性。

但是,最新版本(包括 2.7 和 3.2 中的 stdlib 中的版本,但不包括 2.6 或 3.1,以及 PyPI 上 ElementTreelxml 的当前发布版本)可以自动为您执行此操作在tostring 方法中:

>>> s = '''<tag>
...   Some <a>example</a> text
... </tag>'''
>>> t = ElementTree.fromstring(s)
>>> ElementTree.tostring(s, method='text')
'\n  Some example text\n'

如果您还想从文本中去除空格,则需要手动执行此操作。在您的简单情况下,这很容易:

>>> ElementTree.tostring(s, method='text').strip()
'Some example text'

然而,在更复杂的情况下,如果您想要去除中间标记中的空白,您可能不得不退回到递归处理texts 和tails。这并不难。您只需要记住处理属性可能是None 的可能性。例如,这里有一个框架,你可以在上面挂上你自己的代码:

def textify(t):
    s = []
    if t.text:
        s.append(t.text)
    for child in t.getchildren():
        s.extend(textify(child))
    if t.tail:
        s.append(t.tail)
    return ''.join(s)

此版本仅在 texttail 保证为 strNone 时有效。对于您手动构建的树,这不能保证是正确的。

【讨论】:

以上是关于Python元素树 - 从元素中提取文本,剥离标签的主要内容,如果未能解决你的问题,请参考以下文章

Python定位页面元素一个标签中有两个文本,如何定位其中一个文本

PHP DOM获取nodevalue html? (不剥离标签)

从中提取文本元素结束 分子

Python BeautifulSoup 提取元素之间的文本

selenium.common.exceptions.NoSuchElementException 使用 Selenium Python 从#shadow-root (open) 中提取元素文本时出错

Python/BeautifulSoup - 如何从元素中删除所有标签?