Получение несмежного текста с помощью lxml / ElementTree - PullRequest
4 голосов
/ 10 сентября 2010

Предположим, у меня есть HTML-код такого типа, из которого мне нужно выбрать "text2" с помощью lxml / ElementTree:

<div>text1<span>childtext1</span>text2<span>childtext2</span>text3</div>

Если у меня уже есть элемент div в качестве mydiv, то mydiv.text возвращает просто «text1».

Использование itertext () в лучшем случае кажется проблематичным или обременительным, поскольку обходит все дерево под div.

Есть ли какой-нибудь простой / элегантный способ извлечь не первый фрагмент текста из элемента?

Ответы [ 4 ]

12 голосов
/ 24 сентября 2010

Хорошо, lxml.etree предоставляет полную поддержку XPath, которая позволяет вам обращаться к текстовым элементам:

>>> import lxml.etree
>>> fragment = '<div>text1<span>childtext1</span>text2<span>childtext2</span>text3</div>'
>>> div = lxml.etree.fromstring(fragment)
>>> div.xpath('./text()')
['text1', 'text2', 'text3']
6 голосов
/ 10 сентября 2010

Такой текст будет в атрибутах tail дочерних элементов вашего элемента.Если бы ваш элемент был в elem, то:

elem[0].tail

дал бы вам хвостовой текст первого потомка в элементе, в вашем случае "text2", который вы ищете.

4 голосов
/ 19 сентября 2010

Как сказал llasram, любой текст, отсутствующий в атрибуте text, будет находиться в атрибутах tail дочерних узлов.

В качестве примера, вот самый простой способ извлечь всех фрагментов текста (первого и других) в узле:

html = '<div>text1<span>childtext1</span>text2<span>childtext2</span>text3</div>'

import lxml.html    # ...or lxml.etree as appropriate
div = lxml.html.fromstring(html)

texts = [div.text] + [child.tail for child in div]
# Result: texts == ['text1', 'text2', 'text3']
# ...and you are guaranteed that div[x].tail == texts[x+1]
# (which can be useful if you need to access or modify the DOM)

Если вы предпочли бы пожертвовать этим отношением, чтобы не дать texts потенциально содержать пустые строки, вы можете использовать это вместо:

texts = [div.text] + [child.tail for child in div if child.tail]

Я не проверял это с простым старым stdlib ElementTree, но он должен работать и с этим. (Что-то, что пришло мне в голову, как только я увидел решение Шейна Холлоуэя для lxml, специфичное для lxml), я просто предпочитаю LXML, потому что он получил лучшую поддержку идеосинкразий HTML, и я обычно уже установил его для lxml.html.clean

1 голос
/ 30 октября 2012

Используйте node.text_content(), чтобы получить весь текст ниже узла в виде одной строки.

...