我试图最终解决一些编码问题,这些问题是从试图用lxml刮HTML时突然出现的。下面是我遇到的三个HTML文档示例:
一。
<!DOCTYPE html>
<html lang='en'>
<head>
<title>Unicode Chars: 은 —’</title>
<meta charset='utf-8'>
</head>
<body></body>
</html>
2。
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ko-KR" lang="ko-KR">
<head>
<title>Unicode Chars: 은 —’</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
</head>
<body></body>
</html>
三。
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Unicode Chars: 은 —’</title>
</head>
<body></body>
</html>
我的基本脚本:
from lxml.html import fromstring
...
doc = fromstring(raw_html)
title = doc.xpath('//title/text()')[0]
print title
结果是:
Unicode Chars: ì ââ
Unicode Chars: 은 —’
Unicode Chars: 은 —’
所以,很明显,示例1和缺少的<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
标记有问题。来自here的解决方案将正确地将示例1识别为utf-8,因此它在功能上等同于我的原始代码。
lxml文档似乎有冲突:
从here的例子看来,我们应该使用UnicodeDammit将标记编码为unicode。
from BeautifulSoup import UnicodeDammit
def decode_html(html_string):
converted = UnicodeDammit(html_string, isHTML=True)
if not converted.unicode:
raise UnicodeDecodeError(
"Failed to detect encoding, tried [%s]",
', '.join(converted.triedEncodings))
# print converted.originalEncoding
return converted.unicode
root = lxml.html.fromstring(decode_html(tag_soup))
但是here上面说:
[Y]ou will get errors when you try [to parse] HTML data in a unicode string that specifies a charset in a meta tag of the header. You should generally avoid converting XML/HTML data to unicode before passing it into the parsers. It is both slower and error prone.
如果我尝试遵循lxml文档中的第一个建议,我的代码现在是:
from lxml.html import fromstring
from bs4 import UnicodeDammit
...
dammit = UnicodeDammit(raw_html)
doc = fromstring(dammit.unicode_markup)
title = doc.xpath('//title/text()')[0]
print title
我现在得到以下结果:
Unicode Chars: 은 —’
Unicode Chars: 은 —’
ValueError: Unicode strings with encoding declaration are not supported.
示例1现在可以正常工作,但是示例3由于<?xml version="1.0" encoding="utf-8"?>
标记而导致错误。
有没有正确的方法来处理所有这些案件?有比下面更好的解决方案吗?
dammit = UnicodeDammit(raw_html)
try:
doc = fromstring(dammit.unicode_markup)
except ValueError:
doc = fromstring(raw_html)
这个问题可能源于这样一个事实,即
<meta charset>
是一个相对较新的标准(如果我没有弄错的话,那就是HTML5,或者它之前并没有真正使用过)在更新
lxml.html
库以反映它之前,您需要特别处理该情况。如果您只关心ISO-8859-*和UTF-8,并且能够舍弃非ASCII兼容的编码(例如UTF-16或东亚传统字符集),那么您可以对字节字符串执行正则表达式替换,将较新的
<meta charset>
替换为较旧的http-equiv
格式。否则,如果您需要一个正确的解决方案,您最好自己修补库(并在修复过程中提供修补程序)。您可能需要询问lxml开发人员是否有针对此特定错误的半生不熟的代码,或者他们是否首先在其错误跟踪系统上跟踪该错误。
lxml
与处理Unicode相关的severalissues。最好(目前)在显式指定字符编码时使用字节:输出
相关问题 更多 >
编程相关推荐