Python:如何从lxml元素获取原始文本

时间:2019-10-11 07:02:58

标签: python xml lxml

我想从根元素中获取以下内联文本字符串。

from lxml import etree

root = root = etree.fromstring(
'''<p>
    text-first
    <span>
        Child 1
    </span>
    text-middle
    <span>
        Child 2
    </span>
    text-last
</p>''')

root.text仅返回“文本优先”(包括换行符)

>>> build_text_list = etree.XPath("//text()")

>>> texts = build_text_list(root)
>>>
>>> texts
['\n    text-first\n    ', '\n        Child 1\n    ', '\n    text-middle\n    ', '\n        Child 2\n    ', '\n    text-last\n']
>>>
>>> for t in texts:
...     print t
...     print t.__dict__
...

    text-first

{'_parent': <Element p at 0x10140f638>, 'is_attribute': False, 'attrname': None, 'is_text': True, 'is_tail': False}

        Child 1

{'_parent': <Element span at 0x10140be18>, 'is_attribute': False, 'attrname': None, 'is_text': True, 'is_tail': False}

    text-middle

{'_parent': <Element span at 0x10140be18>, 'is_attribute': False, 'attrname': None, 'is_text': False, 'is_tail': True}

        Child 2

{'_parent': <Element span at 0x10140be60>, 'is_attribute': False, 'attrname': None, 'is_text': True, 'is_tail': False}

    text-last

{'_parent': <Element span at 0x10140be60>, 'is_attribute': False, 'attrname': None, 'is_text': False, 'is_tail': True}
>>>
>>> root.xpath("./p/following-sibling::text()") # following https://stackoverflow.com/a/39832753/1677041
[]

那么,如何从中获得text-first/middle/last部分呢?

有什么想法吗?谢谢!

4 个答案:

答案 0 :(得分:1)

etree完全有能力做到这一点:

from lxml import etree

root: etree.Element = etree.fromstring(
'''<p>
    text-first
    <span>
        Child 1
    </span>
    text-middle
    <span>
        Child 2
    </span>
    text-last
</p>''')

print(
    root.text,
    root[0].tail,
    root[1].tail,
)

所有元素都是其子元素的列表,因此此处的索引引用了2个<span>元素。任何元素的tail属性都在该元素之后直接包含文本。

它当然将包括换行符,因此您可能要剥离()结果:root.text.strip()

答案 1 :(得分:1)

您最初的猜测,<class 'str'> ФАО ЦЕСНАБАНК г. Степногорск <class 'str'> ежемесячно <class 'str'> Стандартный <class 'pandas._libs.tslibs.timestamps.Timestamp'> 2015-06-01 00:00:00 <class 'pandas._libs.tslibs.timestamps.Timestamp'> 2015-05-06 00:00:00 <class 'pandas._libs.tslibs.timestamps.Timestamp'> 2017-05-06 00:00:00 <class 'numpy.float64'> 220000.0 <class 'numpy.int64'> 25 <class 'numpy.float64'> 37.5 <class 'numpy.int64'> 0 <class 'str'> Акмолинская Область <class 'str'> Собственное <class 'str'> Казахстан <class 'str'> Потребительские цели <class 'pandas._libs.tslibs.timestamps.Timestamp'> 2015-05-06 00:00:00 <class 'numpy.int64'> 24 <class 'numpy.float64'> 6.0 <class 'pandas._libs.tslibs.timestamps.Timestamp'> 2015-05-04 00:00:00 <class 'numpy.float64'> 1.0 <class 'str'> Взнос наличными деньгами <class 'str'> От 1 года до 5 лет <class 'numpy.float64'> 1.0 <class 'numpy.float64'> 33862.11 的意思是:选择所有文本节点,无论它们在文档中的什么位置。如果文本节点是//text()的直接子代,或者不是p的子代,那么您实际上要选择的是文本节点。

给定要显示的输入文档,最准确的答案是span

/p/text()

您自己的解决方案>>> root = etree.fromstring( '''<p> text-first <span> Child 1 </span> text-middle <span> Child 2 </span> text-last </p>''') >>> etree.XPath("/p/text()")(root) ['\n text-first\n ', '\n text-middle\n ', '\n text-last\n'] 的意思是:如果文本节点是当前上下文节点的子节点,则选择它们。之所以起作用,是因为在这种情况下,使用根元素child::text()作为上下文来评估XPath表达式。这就是为什么p也可以工作的原因。

text()

答案 2 :(得分:0)

我的坏人,xpath最终救了我。

>>> root.xpath('child::text()')
['\n    text-first\n    ', '\n    text-middle\n    ', '\n    text-last\n']

答案 3 :(得分:0)

print(root.xpath('normalize-space(//*)'))