Извлечение текстового содержимого ячейки таблицы с помощью xpath в строках для потребления? - PullRequest
3 голосов
/ 22 февраля 2012

У меня есть что-то вроде следующего в терминах HTML.Я хотел бы извлечь различное содержимое ячеек таблицы, однако я обнаружил, что в ячейках иногда есть некоторые встроенные элементы div и, возможно, другие странности, в которых я пока не уверен:

<p align="center">
    <img src="some_image.gif" alt="Some Title">
</p>
<TABLE WIDTH=500 BORDER=1 class=textwhite ALIGN=center CELLPADDING=0 CELLSPACING=0>
<TR>
<TD colspan=4 ALIGN=center><b>Title</b></TD>
</TR>
<TR>
<TD ALIGN=center>Title</TD>
<TD ALIGN=center>date</TD>
<TD ALIGN=center>value</TD>
<TD ALIGN=center>value</TD>
</TR><TR>
  <TD ALIGN=center>Title2</TD>
  <TD ALIGN=center></TD>
  <TD ALIGN=center><div class=redtext>----</div></TD>
  <TD>&nbsp;</TD>
</TR><TR>
  <TD ALIGN=center>Title3</TD>
  <TD ALIGN=center><div class=yellowtext>value</div></TD>
  <TD ALIGN=center><div class=redtext>value</div></TD>
  <TD ALIGN=center>value<SUP>6</SUP></TD>
</TR><TR>
  <TD ALIGN=center>Title4</TD>
  <TD ALIGN=center><div class=bluetext>value</div></TD>
  <TD ALIGN=center><div class=redtext>value</div></TD>
  <TD>&nbsp;</TD>
</TR></TABLE>

<blockquote>
    <p class="textstyle">
        Text.
    </p>
</blockquote>

Мой первыйИмпульсом было извлечь ВСЕ тексты элементов и просто программно нарезать их.Я бы проследил, чтобы Title1, Title2 и т. Д. Знали, когда начинается строка, а затем, если найдено «----», означающее отсутствие значения, просто пропустите эту строку и продолжайте.Однако я понял, что, вероятно, есть лучший способ справиться с этим напрямую с помощью xpath.

Как это можно решить с помощью xpath, чтобы по существу дать конечному дочернему текстовому содержимому каждой ячейки против необходимости заходить в каждый div, если он существует?Или есть способ, более похожий на xpath, чтобы приблизиться к этому?

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

Ответы [ 3 ]

3 голосов
/ 22 февраля 2012

Предоставленный текст не является правильно сформированным XML-документом, поэтому XPath не применим .

Если вы исправите и преобразуете его в правильно сформированный XML-документ как единыйниже может пригодиться такое выражение:

/*/TABLE//TD//text()

или даже:

//TABLE//TD//text()

Вот хорошо оформленный документ XML, построенный из предоставленного HTML:

<html>
    <p align="center">
        <img src="some_image.gif" alt="Some Title"/>
    </p>
    <TABLE WIDTH="500" BORDER="1" class="textwhite" ALIGN="center" CELLPADDING="0" CELLSPACING="0">
        <TR>
            <TD colspan="4" ALIGN="center">
                <b>Title</b>
            </TD>
        </TR>
        <TR>
            <TD ALIGN="center">Title</TD>
            <TD ALIGN="center">date</TD>
            <TD ALIGN="center">value</TD>
            <TD ALIGN="center">value</TD>
        </TR>
        <TR>
            <TD ALIGN="center">Title2</TD>
            <TD ALIGN="center"></TD>
            <TD ALIGN="center">
                <div class="redtext">----</div>
            </TD>
            <TD>&#xA0;</TD>
        </TR>
        <TR>
            <TD ALIGN="center">Title3</TD>
            <TD ALIGN="center">
                <div class="yellowtext">value</div>
            </TD>
            <TD ALIGN="center">
                <div class="redtext">value</div>
            </TD>
            <TD ALIGN="center">value
                <SUP>6</SUP>
            </TD>
        </TR>
        <TR>
            <TD ALIGN="center">Title4</TD>
            <TD ALIGN="center">
                <div class="bluetext">value</div>
            </TD>
            <TD ALIGN="center">
                <div class="redtext">value</div>
            </TD>
            <TD>&#xA0;</TD>
        </TR>
    </TABLE>
    <blockquote>
        <p class="textstyle">         Text.     </p>
    </blockquote>
</html>
0 голосов
/ 22 февраля 2012

Я полагаю, что ваша программа столкнется с множеством проблем при манипулировании входными данными - что если изменится регистр 'title' или произойдет опечатка?

В действительности это невозможнопринять строгое решение для очистки чужого сайта, так как они могут без предварительного уведомления полностью изменить все.Обычно лучше написать толерантный и гибкий код, который, по крайней мере, пытается проверить, что его вывод является нормальным.В этом случае, вероятно, лучше всего перебрать результаты '// table / tr', затем внутри этого цикла обработать элементы td:

import lxml.etree
tree = lxml.etree.fromstring("<table><tr><td>test</td></tr><tr><td><div>test2</div></td></tr></table>")
stringify = lambda x : "".join(x.xpath(".//text()"))
for x in tree.xpath("//table/tr"):
    print "New row"
    for y in x.xpath("td"):
        print stringify(y)

Вывод:

New row
test
New row
test2

Следующий код, однако, получит список, который вы запрашиваете:

print map(stringify, tree.xpath("//table/tr/td"))

Вывод:

['test', 'test2']

Это найдет все текстовые элементы, которые вообще происходят от td, который являетсяпрямой потомок tr, который, в свою очередь, является прямым потомком таблицы.

(Простой запрос всех элементов text () создаст несколько забавных ошибок при работе с HTML, который содержит «

Foo * 1018»).* бар "или аналогичный.)
0 голосов
/ 22 февраля 2012

Так что, может быть, вы не хотите ходить по div, но вот мое решение с использованием lxml, которое я настоятельно рекомендую:

import re
from cStringIO import StringIO
from lxml import etree

def getTable(html, table_xpath, rows_xpath, cells_xpath):
    """Get a table on a webpage"""
    parser = etree.HTMLParser()
    # Build document tree and get table
    root = etree.parse(StringIO(html), parser)
    table = root.find(table_xpath)
    if table == None:
        print 'No table.'
        return []
    rows = table.findall(rows_xpath)
    document = []
    def cleanText(text):
        """Clean up text by replacing line breaks and tabs. """
        return re.sub(r'[\r\n\t]+','',str(text).strip())
    # iterate over the table rows and collect text from each cell.
    for r in rows:
        cells = r.findall(cells_xpath)
        rowdata = []
        for c in cells:
            text = ''
            it = c.itertext()
            for i in it:
                text += cleanText(i) + ' '
            rowdata.append(text)
        document.append(rowdata)
    return document


html = """
<html><head><title></title></head><body>
<p align="center">
    <img src="some_image.gif" alt="Some Title">
    </p>
    <TABLE WIDTH=500 BORDER=1 class=textwhite ALIGN=center CELLPADDING=0 CELLSPACING=0>
    <TR>
    <TD colspan=4 ALIGN=center><b>Title</b></TD>
    </TR>
    <TR>
    <TD ALIGN=center>Title</TD>
    <TD ALIGN=center>date</TD>
    <TD ALIGN=center>value</TD>
    <TD ALIGN=center>value</TD>
    </TR><TR>
    <TD ALIGN=center>Title2</TD>
    <TD ALIGN=center></TD>
    <TD ALIGN=center><div class=redtext>----</div></TD>
    <TD>&nbsp;</TD>
    </TR><TR>
    <TD ALIGN=center>Title3</TD>
    <TD ALIGN=center><div class=yellowtext>value</div></TD>
    <TD ALIGN=center><div class=redtext>value</div></TD>
    <TD ALIGN=center>value<SUP>6</SUP></TD>
    </TR><TR>
    <TD ALIGN=center>Title4</TD>
    <TD ALIGN=center><div class=bluetext>value</div></TD>
    <TD ALIGN=center><div class=redtext>value</div></TD>
    <TD>&nbsp;</TD>
</TR></TABLE>   
</body>
</html>
"""
tp = "//table[@width='500']"
rt = "tr"
cp = "td[@align='center']"

doc = getTable(html, tp, rt, cp)
print repr(doc)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...