如何使用lxml删除html实体(以及更多)?

时间:2011-05-03 20:01:15

标签: python html-parsing lxml

我有一个html文件有一些看起来像这样的文本(在lxml.html parselxml.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上找到的文档有点spotty。我已经能够做很多事情来达到这一点,但我想做的是删除除<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. 以外的所有代码
  4. 我想从剩余的标签中删除所有属性。
  5. 非常感谢任何帮助!

2 个答案:

答案 0 :(得分:4)

以下是删除所有属性并仅允许[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;
...

答案 1 :(得分:3)

对我来说,我发现基于文本,标签和尾部的基本元素编写它可以更容易地将行为专门化为您想要的并包括错误检查(例如,以确保传入数据中没有意外的标记)。

text和tail上的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>