Lxml.etree, element.text не возвращает весь текст из элемента

Я сломал некоторый html через xpath, и затем преобразовал его в этер. Что-то похожее на это:

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

но когда я вызываю element.text, я получаю text1 (он должен быть там, когда я проверяю свой запрос в FireBug, текст элементов выделяется, как текст до, так и после встроенных элементов привязки...

Ответ 1

Используйте element.xpath("string()") или lxml.etree.tostring(element, method="text") - см. документацию.

Ответ 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

Ответ 4

Другая вещь, которая, кажется, хорошо работает, чтобы получить текст из элемента, - "".join(element.itertext())

Ответ 5

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

Ответ 6

<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])

Ответ 7

Если element равно <td>. Вы можете сделать следующее.

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

Он предоставит вам список всех текстовых элементов из self (значение точки). // означает, что он примет все элементы и, наконец, text() - это функция для извлечения текста.

Ответ 8

element.xpath('normalize-space()') also works.