如何使用lxml移除HTML实体(和更多)?
我有一个HTML文件,里面有一些文本,经过lxml.html parse
和lxml.html clean
处理后,使用etree.tostring(table, pretty_print=True)
得到的结果是这样的:
<tr><td>
224
9:00 am
-3:00 pm
NPHC Leadership</td>
<td>
<font>ALSO IN 223; WALL OPEN</font></td>
我找到的关于lxml的文档有点零散。我已经做了很多工作才能达到这个阶段,但我想做的是去掉所有标签,只保留<table>
、<td>
和<tr>
。我还想去掉这些标签的所有属性,并且想去掉像
这样的实体。
目前我用来去掉属性的方法是:
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: 同时传入allow_tags和remove_unknown_tags是没有意义的
。而且,当我添加remove_unknown_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
所以,总结一下:
- 我想去掉HTML实体,比如
- 我想去掉所有标签,除了
<table>
、<tr>
和<td>
- 我想去掉剩下标签的所有属性。
任何帮助都会非常感谢!
2 个回答
这里有一个例子,展示了如何去掉所有属性,只保留 [table, tr, td]
这些标签。我还加了一些Unicode字符来帮助说明。
DATA = '''<table border="1"><tr colspan="4"><td rowspan="2">\r
224
“hi there”
9:00 am\r
-3:00 pm
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>
你确定要去掉所有的字符实体吗?
代表的是换行符,当 lxml 解析文档时,它会把所有的字符实体转换成对应的Unicode字符。
字符实体是否显示出来,还取决于输出的方法和编码方式。例如,如果你使用 lxml.html.tostring(encoding='ascii', method='xml')
,那么 '\r'
和Unicode字符会以字符实体的形式输出:
<table>
<tr><td>
“hi there”
...
对我来说,基于文本、标签和尾部这几个基本元素来写代码,会让我们更容易调整行为,做到我们想要的效果,同时也能加入错误检查(比如确保输入的数据里没有意外的标签)。
这里提到的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>