Python 如何使用ElementTree获取元素的完整XML或HTML内容?

Python 如何使用ElementTree获取元素的完整XML或HTML内容?,python,xml,api,elementtree,Python,Xml,Api,Elementtree,也就是说,所有的文本和子标签,没有一个元素本身的标签 拥有 <p>blah <b>bleh</b> blih</p> 废话 我想要 blah <b>bleh</b> blih 废话 element.text返回“blah”,etree.tostring(element)返回: 废话 ElementTree工作正常,您必须自己组装答案。像这样的 "".join( [ "" if t.text is None else

也就是说,所有的文本和子标签,没有一个元素本身的标签

拥有

<p>blah <b>bleh</b> blih</p>
废话

我想要

blah <b>bleh</b> blih
废话
element.text返回“blah”,etree.tostring(element)返回:

废话


ElementTree工作正常,您必须自己组装答案。像这样的

"".join( [ "" if t.text is None else t.text ] + [ xml.tostring(e) for e in t.getchildren() ] )
感谢JV amd PEZ指出错误


编辑

>将xml.etree.ElementTree导入为xml
>>>s='诸如此类

\n' >>>t=xml.fromstring(s) >>>“”.join([t.text]+[xml.tostring(e)表示t.getchildren()中的e) “呜呜呜呜” >>>

不需要尾部。

不知道是否可以选择外部库,但无论如何——假设页面上有一个
,jQuery解决方案是:

alert($('p').html()); // returns blah <b>bleh</b> blih
alert($('p').html());//返回废话

我怀疑ElementTree是否是用于此目的的工具。但是假设您有充分的理由使用它,那么您可以尝试从片段中剥离根标记:

 re.sub(r'(^<%s\b.*?>|</%s\b.*?>$)' % (element.tag, element.tag), '', ElementTree.tostring(element))
re.sub(r'(^ |$)'%(element.tag,element.tag),“”,ElementTree.tostring(element))

这是我最终使用的解决方案:

def element_to_string(element):
    s = element.text or ""
    for sub_element in element:
        s += etree.tostring(sub_element)
    s += element.tail
    return s

这些都是很好的答案,回答了OP的问题,特别是当问题仅限于HTML时。但文档本身就很混乱,元素嵌套的深度通常无法预测

要模拟DOM的getTextContent(),必须使用(非常)简单的递归机制

要仅获取纯文本,请执行以下操作:

def get_deep_text( element ):
    text = element.text or ''
    for subelement in element:
        text += get_deep_text( subelement )
    text += element.tail or ''
    return text
print( get_deep_text( element_of_interest ))
要获取原始文本之间边界的所有详细信息,请执行以下操作:

root_el_of_interest.element_count = 0
def get_deep_text_w_boundaries( element, depth = 0 ):
    root_el_of_interest.element_count += 1
    element_no = root_el_of_interest.element_count 
    indent = depth * '  '
    text1 = '%s(el %d - attribs: %s)\n' % ( indent, element_no, element.attrib, )
    text1 += '%s(el %d - text: |%s|)' % ( indent, element_no, element.text or '', )
    print( text1 )
    for subelement in element:
        get_deep_text_w_boundaries( subelement, depth + 1 )
    text2 = '%s(el %d - tail: |%s|)' % ( indent, element_no, element.tail or '', )
    print( text2 )
get_deep_text_w_boundaries( root_el_of_interest )
LibreOffice Writer文档(.fodt文件)中单个段落的输出示例:

关于混乱的一点是,对于文本样式何时表示单词边界以及何时不表示单词边界,没有硬性规定:紧跟在单词后面的上标(没有空格)在我能想象的所有用例中都意味着一个单独的单词。例如,有时您可能会发现文档中的第一个字母出于某种原因以粗体显示,或者可能会对第一个字母使用不同的样式以大写形式表示,而不是简单地使用普通的UC字符


当然,这种讨论越不以“英语为中心”,其微妙性和复杂性就越大

这里的大多数答案都基于XML解析器
ElementTree
,甚至部分依赖ElementTree


所有这些都很好,适用于大多数用例,但为了完整起见,值得注意的是,
ElementTree.tostring(…)
将为您提供一个等效的代码片段,但并不总是与原始负载相同。如果出于某种非常罕见的原因,您希望按原样提取内容,则必须使用基于纯正则表达式的解决方案。这是我如何使用基于正则表达式的解决方案。

这个答案是对Pupeno的回答的轻微修改。在这里,我在“tostring”中添加了编码类型。这个问题花了我好几个小时。我希望这个小小的修正能帮助其他人

def element_to_string(element):
        s = element.text or ""
        for sub_element in element:
            s += ElementTree.tostring(sub_element, encoding='unicode')
        s += element.tail
        return s

只是指出了一个拼写错误的方法名——“finall”,我想应该是“findall”。即使使用findall,也会导致这种情况。请修改你的答案。我正在做一些类似的事情,但要看一看。实际上,您缺少尾部。尾部是构造的结束标记后的额外空白。如果没有文本或没有尾部,这将失败,不是吗?PEZ,是的,如果没有文本,它将失败,只是通过运行我的代码找到它并修复它。我有很多没有尾巴的例子,这并没有失败。不知道为什么。只是吹毛求疵:字符串上的+=性能较差。最好累积字符串和“”的列表。在末尾加入它。您可能希望递归并再次调用子元素上的
element\u to\u string
,以捕获所有文本,即
对于元素中的sub\u元素:s+=element\u to\u string(sub\u element)
root_el_of_interest.element_count = 0
def get_deep_text_w_boundaries( element, depth = 0 ):
    root_el_of_interest.element_count += 1
    element_no = root_el_of_interest.element_count 
    indent = depth * '  '
    text1 = '%s(el %d - attribs: %s)\n' % ( indent, element_no, element.attrib, )
    text1 += '%s(el %d - text: |%s|)' % ( indent, element_no, element.text or '', )
    print( text1 )
    for subelement in element:
        get_deep_text_w_boundaries( subelement, depth + 1 )
    text2 = '%s(el %d - tail: |%s|)' % ( indent, element_no, element.tail or '', )
    print( text2 )
get_deep_text_w_boundaries( root_el_of_interest )
(el 1 - attribs: {'{urn:oasis:names:tc:opendocument:xmlns:text:1.0}style-name': 'Standard'})
(el 1 - text: |Ci-après individuellement la "|)
  (el 2 - attribs: {'{urn:oasis:names:tc:opendocument:xmlns:text:1.0}style-name': 'T5'})
  (el 2 - text: |Partie|)
  (el 2 - tail: |" et ensemble les "|)
  (el 3 - attribs: {'{urn:oasis:names:tc:opendocument:xmlns:text:1.0}style-name': 'T5'})
  (el 3 - text: |Parties|)
  (el 3 - tail: |", |)
(el 1 - tail: |
   |)
def element_to_string(element):
        s = element.text or ""
        for sub_element in element:
            s += ElementTree.tostring(sub_element, encoding='unicode')
        s += element.tail
        return s