【问题标题】:How can I get the text from this HTML snippet using lxml?如何使用 lxml 从此 HTML 片段中获取文本?
【发布时间】:2021-04-06 21:41:49
【问题描述】:

谁能解释为什么这个 sn-p 在断言上失败?

from lxml import etree

s = '<div><h2><img />XYZZY</h2></div>'

root = etree.fromstring(s)

elements = root.xpath(".//*[contains(text(),'XYZZY')]")  # Finds 1 element, as expected

for el in elements:
    assert el.text is not None

然后...如何访问“XYZZY”并将其更改为“ZYX”?

【问题讨论】:

    标签: python xml lxml


    【解决方案1】:

    谁能解释为什么这个 sn-p 在断言上失败?

    因为&lt;h2&gt; 元素的文本由lxml 存储在h2 元素的其中一个子元素中。您可以使用itertext() 来获取您要查找的内容。

    from lxml import etree
    s = '<div><h2><img />XYZZY</h2></div>'
    root = etree.fromstring(s)
    elements = root.xpath(".//*[contains(text(),'XYZZY')]")
    for el in elements:
        el_text = ''.join(el.itertext())
        assert el_text is not None
        print(el_text)
    

    更新:再看一遍之后,发现每个元素都有 3 个相关属性:.tag.text.tail

    对于 .tail 属性,there is a small part in the tutorial 对此进行了解释:

    &lt;html&gt;&lt;body&gt;Hello&lt;br/&gt;World&lt;/body&gt;&lt;/html&gt;

    这里,
    标签被文本包围。这通常被称为 文档样式或混合内容 XML。元素通过他们的支持这一点 尾属性。它包含直接跟随元素的文本, 直到 XML 树中的下一个元素

    .tail 的填充方式是again explained here

    LXML 附加尾随文本,该文本不包含在它自己的标签中,作为之前标签的.tail 属性。

    所以我们实际上可以编写以下代码,遍历元素树中的每个元素,找到文本XYZZY 所在的位置:

    from lxml import etree
    s = '<div><h2><img />XYZZY</h2></div>'
    root = etree.fromstring(s)
    
    context = etree.iterwalk(root, events=("start","end"))
    for action, elem in context:
        print("%s: %s : [text=%s : tail=%s]" % (action, elem.tag, elem.text, elem.tail))
    

    输出:

    start: div : [text=None : tail=None]
    start: h2 : [text=None : tail=None]
    start: img : [text=None : tail=XYZZY]
    end: img : [text=None : tail=XYZZY]
    end: h2 : [text=None : tail=None]
    end: div : [text=None : tail=None]
    

    所以它位于&lt;img&gt; 元素的.tail 属性中。

    关于你的第二个问题:

    然后...如何访问“XYZZY”并将其更改为“ZYX”?

    一种解决方案是遍历元素树,检查每个元素的文本或尾部是否有字符串,然后替换它:

    #!/usr/bin/python3
    from lxml import etree
    s = '<div><h2><img />XYZZY</h2></div>'
    root = etree.fromstring(s)
    
    search_string = "XYZZY"
    replace_string = "ZYX"
    
    context = etree.iterwalk(root, events=("start","end"))
    for action, elem in context:
        if elem.text and elem.text.strip() == search_string:
            elem.text = replace_string
        elif elem.tail and elem.tail.strip() == search_string:
            elem.tail = replace_string
    
    print(etree.tostring(root).decode("utf-8"))
    

    输出:

    <div><h2><img/>ZYX</h2></div>
    

    【讨论】:

      猜你喜欢
      • 2015-01-05
      • 2013-04-03
      • 1970-01-01
      • 1970-01-01
      • 2020-07-12
      • 1970-01-01
      • 2013-08-25
      • 2016-05-11
      • 1970-01-01
      相关资源
      最近更新 更多