извлечь конкретный элемент из вложенных элементов с помощью lxml html - PullRequest
4 голосов
/ 14 апреля 2010

Привет всем У меня возникли проблемы, которые, я думаю, можно отнести к проблемам с xpath. Я использую модуль html из пакета lxml, чтобы попытаться получить некоторые данные. Ниже я приведу наиболее упрощенную ситуацию, но имейте в виду, что HTML-код, с которым я работаю, гораздо уродливее.

<table>
    <tr>
    <td>
        <table>
            <tr><td></td></tr>
            <tr><td>
                <table>
                    <tr><td><u><b>Header1</b></u></td></tr> 
                    <tr><td>Data</td></tr>
                </table>
            </td></tr>
        </table>
     </td></tr>
</table>

Что мне действительно нужно, так это глубоко вложенная таблица, так как в ней есть текст заголовка «Header1». Я пытаюсь так:

from lxml import html
page = '...'
tree = html.fromstring(page)
print tree.xpath('//table[//*[contains(text(), "Header1")]]')

но это дает мне все элементы таблицы. Я просто хочу одну таблицу, которая содержит этот текст. Я понимаю, что происходит, но мне трудно понять, как это сделать, кроме того, что вырыл какое-то противное регулярное выражение. Какие-нибудь мысли?

Ответы [ 4 ]

3 голосов
/ 14 апреля 2010

Используйте

//td[text() = 'Header1']/ancestor::table[1]
2 голосов
/ 14 апреля 2010

Найдите интересующий вас заголовок и вытащите его таблицу.

//u[b = 'Header1']/ancestor::table[1]

или

//td[not(.//table) and .//b = 'Header1']/ancestor::table[1]

Обратите внимание, что // всегда начинается с корня документа (!). Вы не можете сделать:

//table[//*[contains(text(), "Header1")]]

и ожидайте, что внутренний предикат (//*…) волшебным образом начнется в правильном контексте. Используйте .//, чтобы начать с узла контекста. Уже тогда это:

//table[.//*[contains(text(), "Header1")]]

не будет работать, поскольку даже самая внешняя таблица содержит текст 'Header1' где-то глубоко внизу, поэтому предикат оценивается как true для каждой таблицы в вашем примере. Используйте not(), как я, чтобы убедиться, что никакие другие таблицы не являются вложенными.

Кроме того, не проверяйте условие на каждом узле .//*, так как это не может быть правдой для каждого узла с самого начала. Более эффективно быть конкретным.

0 голосов
/ 14 апреля 2010
table, = tree.xpath('//*[.="Header1"]/ancestor::table[1]')
  • //*[text()="Header1"] выделяет элемент в любом месте документа с текстом Header1.
  • ancestor::table[1] выбирает первого предка элемента, который является table.

Полный пример

#!/usr/bin/env python
from lxml import html

page = """
<table>
    <tr>
    <td>
        <table>
            <tr><td></td></tr>
            <tr><td>
                <table>
                    <tr><td><u><b>Header1</b></u></td></tr> 
                    <tr><td>Data</td></tr>
                </table>
            </td></tr>
        </table>
     </td></tr>
</table>
"""

tree = html.fromstring(page)
table, = tree.xpath('//*[.="Header1"]/ancestor::table[1]')
print html.tostring(table)
0 голосов
/ 14 апреля 2010

Возможно, это подойдет вам:

tree.xpath("//table[not(descendant::table)]/*[contains(., 'Header1')]")

Бит not(descendant::table) гарантирует, что вы получаете самую внутреннюю таблицу.

...