使用python编辑html,但lxml将漂亮的html实体转换为奇怪的编码
Posted
技术标签:
【中文标题】使用python编辑html,但lxml将漂亮的html实体转换为奇怪的编码【英文标题】:Using python to edit html, but lxml converts nice html entities to strange encoding 【发布时间】:2011-06-20 02:07:39 【问题描述】:我正在尝试使用 python(带有 pyquery 和 lxml)来更改和清理一些 html。
Eg. html = "<div><!-- word style><bleep><omgz 1,000 tags><--><p>It’s a spicy meatball!</div>"
lxml.html.clean 函数 clean_html() 运行良好,只是它替换了漂亮的 html 实体,例如
’
带有一些 unicode 字符串
\xc2\x92
unicode 在不同的浏览器中看起来很奇怪(firefox 和 opera 使用自动编码、utf8、latin-1 等),就像一个空盒子。如何停止 lxml 转换实体?如何以 latin-1 编码获得所有内容?一个专门为 html 构建的模块会这样做似乎很奇怪。
我不能确定那里有哪些字符,所以我不能只使用
replace("\xc2\x92","’").
我试过了
clean_html(html).encode('latin-1')
但 unicode 仍然存在。
是的,我会告诉人们停止使用 word 来编写 html,但我会听到整个
“我喜欢它,你不能把我当成hitlr”。
编辑:一个漂亮的汤解决方案:
from BeautifulSoup import BeautifulSoup, Comment
soup = BeautifulSoup(str(desc[desc_type]))
comments = soup.findAll(text=lambda text:isinstance(text, Comment))
[comment.extract() for comment in comments]
print soup
【问题讨论】:
好奇:你为什么不用 BeautifulSoup @inspector:据我了解,BeautifulSoup 已不再积极开发,鼓励用户寻求其他解决方案(如 lxml)。 @SethJohnson:我不知道。谢谢你告诉我 【参考方案1】:有几件事——如果你知道的话——会导致最简单/最好的解决方案:
clean_html()
返回的类型与你提供给它的类型相同:如果你给它一个字符串,它会返回一个字符串,但是如果你给它一个 Element 或 ElementTree,它将分别返回一个 Element 或 ElementTree
您可以控制 Element 或 ElementTree 的序列化方式,方法是为 lxml.html.tostring()
方法或树的 write()
方法提供编码选项(顺便说一下,xml 也是如此)。例如,您可以使用encoding='utf-8'
执行此操作。
任何可以在该编码中编码的内容都将作为编码字符串输出,任何不能作为实体“转义”的内容。使用 encoding="ascii"
将强制任何非 ascii 字符为您希望的“漂亮”实体。
合起来,这意味着:首先将字符串解析为一个元素(或树,如果您愿意),清理它,并根据需要对其进行序列化:
html = lxml.html.fromstring("<div><!-- word style><bleep><omgz 1,000 tags><--><p>It’s a spicy meatball!</div>")
html = clean_html(html)
result = lxml.html.tostring(html, encoding="ascii")
(还有一个稍微脏一点的技巧是在 unicode 字符串的 encode()
方法上使用 errors 参数:尝试使用 s.encode('ascii', 'xmlcharrefreplace')
对包含“特殊”字符的 unicode 字符串进行编码,看看会发生什么......)
【讨论】:
【参考方案2】:我假设&#146;
应该是一个引号。字节值为146的str对象chr(146)
,解码为cp1252
是引号:
In [46]: print(chr(146).decode('cp1252'))
’
所以,你可以这样做:
import lxml.html.clean as clean
import re
html = "<div><!-- word style><bleep><omgz 1,000 tags><--><p>It’s a spicy meatball!</div>"
html=re.sub('&#(\d+);',lambda m: chr(int(m.group(1))).decode('cp1252'),html)
print(html)
# <div><!-- word style><bleep><omgz 1,000 tags><--><p>It’s a spicy meatball!</div>
print(type(html))
# <type 'unicode'>
print(clean.clean_html(html))
# <div><p>It’s a spicy meatball!</p></div>
或者,
doc=lh.fromstring(html)
clean.clean(doc)
注意引号的unicode码位值是8217。即ord(chr(146).decode('cp1252'))
等于8217,所以lh.tostring
返回:
print(lh.tostring(doc))
# <div><p>It’s a spicy meatball!</p></div>
您可以像这样在 cp1252 中重新编码:
print(repr(lh.tostring(doc,encoding='cp1252')))
# '<div><p>It\x92s a spicy meatball!</p></div>'
不知道怎么哄lxml返回
'<div><p>It’s a spicy meatball!</p></div>'
但要匹配 BeautifulSoup 代码的输出。好吧,显然它可以用正则表达式完成(颠倒我上面所做的),但我不知道这是否必要或可取,因为 lxml 应该已经返回其他应用程序可以理解的 html。
result=re.sub('&#(\d+);',lambda m: '&#n;'.format(
n=ord(unichr(int(m.group(1))).encode('cp1252'))),
lh.tostring(doc))
print(result)
# <div><p>It’s a spicy meatball!</p></div>
【讨论】:
【参考方案3】:您也可以将 utf8 字符串转换为带有 xml 字符的 ascii
result = result.decode('utf-8').encode('ascii', 'xmlcharrefreplace')
【讨论】:
以上是关于使用python编辑html,但lxml将漂亮的html实体转换为奇怪的编码的主要内容,如果未能解决你的问题,请参考以下文章
将 python 脚本转换为使用 lxml 的 etree 模块的 linux 二进制文件的问题
Python:使用`lxml.html`将HTML内容注入标签