【问题标题】:lxml.etree, element.text doesn't return the entire text from an elementlxml.etree,element.text 不会从元素返回整个文本
【发布时间】:2011-06-13 19:13:02
【问题描述】:

我通过 xpath 废弃了一些 html,然后将其转换为 etree。类似的东西:

<td> text1 <a> link </a> text2 </td>

但是当我调用 element.text 时,我只得到 text1(它必须在那里,当我在 FireBug 中检查我的查询时,元素的文本被突出显示,嵌入锚元素之前和之后的文本......

【问题讨论】:

  • 这是一种方法(代码 sn-p 来自我的小 python 抓取处理器)。想知道这是否是一个 lxml 错误?
  • 这里是sn-p的代码:
  • if element.tag == "td": children = element.getchildren() if len(children) > 0: topic = (element.text + children[0].tail) else: topic = element.text print("\tTopic:\t\t%s" % 主题)

标签: python xml lxml elementtree xml.etree


【解决方案1】:

使用element.xpath("string()")lxml.etree.tostring(element, method="text") - 请参阅the documentation

【讨论】:

  • toString(element, method="text") 几乎可以工作,但它也返回嵌入锚元素的文本,这是我不想要的。
  • element.text + child.tail 有效,但我希望 element.text 按我希望的方式工作:)
  • element.xpath("string()") 返回与 *.tostring() 相同的结果。我尝试了 xpath("text()") ,它不返回锚元素的文本,但它返回 2 个字符串的列表。感谢您指出一些东西。
【解决方案2】:

为可能像我一样懒惰的人们提供公共服务。这是上面的一些代码,您可以运行。

from lxml import etree

def get_text1(node):
    result = node.text or ""
    for child in node:
        if child.tail is not None:
            result += child.tail
    return result

def get_text2(node):
    return ((node.text or '') +
            ''.join(map(get_text2, node)) +
            (node.tail or ''))

def get_text3(node):
    return (node.text or "") + "".join(
        [etree.tostring(child) for child in node.iterchildren()])


root = etree.fromstring(u"<td> text1 <a> link </a> text2 </td>")

print root.xpath("text()")
print get_text1(root)
print get_text2(root)
print root.xpath("string()")
print etree.tostring(root, method = "text")
print etree.tostring(root, method = "xml")
print get_text3(root)

输出是:

snowy:rpg$ python test.py 
[' text1 ', ' text2 ']
 text1  text2 
 text1  link  text2 
 text1  link  text2 
 text1  link  text2 
<td> text1 <a> link </a> text2 </td>
 text1 <a> link </a> text2 

【讨论】:

    【解决方案3】:

    对我来说看起来像一个 lxml 错误,但如果您阅读文档,则根据设计。我已经这样解决了:

    def node_text(node):
        if node.text:
            result = node.text
        else:
            result = ''
        for child in node:
            if child.tail is not None:
                result += child.tail
        return result
    

    【讨论】:

    • 这不是一个错误,实际上它是允许您在构建 XML 元素时在子元素之间插入文本的功能:stackoverflow.com/q/38520331/694360
    • 感谢您指出这一点。我想这很有用,但是恕我直言,如果.text 只返回全文并且其他一些适当命名的属性将只包含直到第一个子元素的部分,那会更清楚。 node.head 怎么样。这也提供了一个线索,即您接下来需要的是 child.tail,而不必先使用 stackoverflow。
    【解决方案4】:

    另一个似乎可以很好地从元素中提取文本的方法是"".join(element.itertext())

    【讨论】:

      【解决方案5】:
      <td> text1 <a> link </a> text2 </td>
      

      它是这样的(忽略空格):

      td.text == 'text1'
      a.text == 'link'
      a.tail == 'text2'
      

      如果您不想要子元素内的文本,那么您可以只收集它们的尾部:

      text = td.text + ''.join([el.tail for el in td])
      

      【讨论】:

        【解决方案6】:
        def get_text_recursive(node):
            return (node.text or '') + ''.join(map(get_text_recursive, node)) + (node.tail or '')
        

        【讨论】:

          【解决方案7】:

          如果element 等于&lt;td&gt;。您可以执行以下操作。

          element.xpath('.//text()')
          

          它将为您提供来自self(点的含义)的所有文本元素的列表。 // 表示它将获取所有元素,最后text() 是提取文本的函数。

          【讨论】:

            【解决方案8】:
            element.xpath('normalize-space()') also works.
            

            【讨论】:

            • 仅粘贴代码是不够的。您还应该解释它为什么起作用:)
            猜你喜欢
            • 1970-01-01
            • 2019-09-04
            • 2012-02-19
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2020-05-03
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多