我希望能够解决使用lxml爬取HTML时出现的编码问题。以下是我遇到的三个HTML示例文档:
1.
<!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>
3.
<?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" />
标签。从这里的解决方法将正确识别样本1为utf-8,因此在功能上等同于我的原始代码。
lxml文档似乎存在冲突:
从这里的示例中,似乎建议我们使用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))
然而,在这里它说:
如果你尝试在指定了标题meta标签中的字符集的unicode字符串中解析HTML数据,则会出现错误。通常应避免将XML / HTML数据转换为Unicode,然后将其传递给解析器。这既慢又容易出错。
如果我尝试按照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已经可以正常工作,但由于<?xml version="1.0" encoding="utf-8"?>
标签的原因,样例3会导致错误。
是否有一种正确的方法来处理所有这些情况?是否有比以下方法更好的解决方案?
dammit = UnicodeDammit(raw_html)
try:
doc = fromstring(dammit.unicode_markup)
except ValueError:
doc = fromstring(raw_html)