Как удалить HTML-сущности (и многое другое) с помощью lxml? - PullRequest
5 голосов
/ 04 мая 2011

У меня есть html-файл, в котором есть какой-то текст, который выглядит следующим образом (после запуска через lxml.html parse, lxml.html clean, и это результат etree.tostring(table, pretty_print=True))

 <tr><td>&#13;
224&#13;
9:00 am&#13;
-3:00 pm&#13;
NPHC Leadership</td>&#13;
<td>&#13;
<font>ALSO IN 223; WALL OPEN</font></td>&#13;

Документация, которую я нашел на lxml, была несколько пятнистой .Мне удалось немало сделать, чтобы добраться до этого момента, но я хотел бы удалить все теги, кроме <table>, <td> и <tr>.Я также хотел бы удалить все атрибуты из этих тегов, и я также хотел бы избавиться от сущностей, таких как &#13;.

Чтобы удалить атрибуты, которые я использую в настоящее время:

    etree.strip_attributes(tree, 'width', 'href', 'style', 'onchange',
                           'ondblclick', 'class', 'colspan', 'cols',
                           'border', 'align', 'color', 'value',
                           'cellpadding', 'nowrap', 'selected',
                           'cellspacing')

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

Я пытался использовать Cleaner, но когда я его пропустил allow_tags, вот так:

ошибка: Cleaner(allow_tags=['table', 'td', 'tr']).clean_html(tree) это дало мне эту ошибку:

ValueError: It does not make sense to pass in both allow_tags and remove_unknown_tags.Кроме того, когда я добавляю remove_unkown_tags=False, я получаю эту ошибку:

Traceback (most recent call last):
  File "parse.py", line 73, in <module>
    SParser('schedule.html').test()
  File "parse.py", line 38, in __init__
    self.clean()
  File "parse.py", line 42, in clean
    Cleaner(allow_tags=['table', 'td', 'tr'], remove_unknown_tags=False).clean_html(tree)
  File "/usr/lib/python2.6/dist-packages/lxml/html/clean.py", line 488, in clean_html
    self(doc)
  File "/usr/lib/python2.6/dist-packages/lxml/html/clean.py", line 390, in __call__
    el.drop_tag()
  File "/usr/lib/python2.6/dist-packages/lxml/html/__init__.py", line 191, in drop_tag
    assert parent is not None
AssertionError

Итак, чтобы подвести итог:

  1. Я хочу удалить объекты HTML, такие как &#13;
  2. Я хочу удалить все теги, кроме <table>, <tr> и <td>
  3. Я хочу удалить все атрибуты из оставшихся тегов.

Любая помощь будет принята с благодарностью!

Ответы [ 2 ]

4 голосов
/ 04 мая 2011

Вот пример удаления всех атрибутов и разрешения только тегов в [table, tr, td].Я добавил несколько объектов Unicode для иллюстрации.

DATA = '''<table border="1"><tr colspan="4"><td rowspan="2">\r
224&#13;
&#8220;hi there&#8221;
9:00 am\r
-3:00 pm&#13;
NPHC Leadership</td>\r
<td rowspan="2">\r
<font>ALSO IN 223; WALL OPEN</font></td>\r
</table>'''

import lxml.html
from lxml.html import clean

def _clean_attrib(node):
    for n in node:
        _clean_attrib(n)
    node.attrib.clear()

tree = lxml.html.fromstring(DATA)
cleaner = clean.Cleaner(allow_tags=['table','tr','td'],
                        remove_unknown_tags=False)
cleaner.clean_html(tree)
_clean_attrib(tree)

print lxml.html.tostring(tree, encoding='utf-8', pretty_print=True, 
                         method='html')

Результат:

<table><tr>
<td>
224
“hi there”
9:00 am
-3:00 pm
NPHC Leadership</td>
<td>
<font>ALSO IN 223; WALL OPEN</font>
</td>
</tr></table>

Вы уверены, что хотите удалить все объекты?&#13; соответствует возврату каретки, и когда lxml анализирует документ, он преобразует все сущности в соответствующие им символы Unicode.

То, будут ли сущности отображаться, также зависит от метода вывода и кодировки.Например, если вы используете lxml.html.tostring(encoding='ascii', method='xml'), символы '\r' и Unicode будут выводиться как объекты:

<table>
  <tr><td>&#13;
  &#8220;hi there&#8221;
...
3 голосов
/ 04 мая 2011

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

Операторы if в тексте и хвосте, потому что они возвращают None, а не "" при нулевой длине.

def ctext(el):
    result = [ ]
    if el.text:
        result.append(el.text)
    for sel in el:
        if sel.tag in ["tr", "td", "table"]:
            result.append("<%s>" % sel.tag)
            result.append(ctext(sel))
            result.append("</%s>" % sel.tag)
        else:
            result.append(ctext(sel))
        if sel.tail:
            result.append(sel.tail)
    return "".join(result)

html = """your input string"""
el = lxml.html.fromstring(html)
print ctext(el)

Помните, что отношение:

  <b>text of the bold <i>text of the italic</i> tail of the italic</b>
...