获取网页字符集的好方法是啥?
Posted
技术标签:
【中文标题】获取网页字符集的好方法是啥?【英文标题】:What is a nice, reliable short way to get the charset of a webpage?获取网页字符集的好方法是什么? 【发布时间】:2011-05-29 11:13:46 【问题描述】:我有点惊讶,用 Python 获取网页的字符集是如此复杂。我错过了一条路吗? HTTPMessage 有很多函数,但没有这个。
>>> google = urllib2.urlopen('http://www.google.com/')
>>> google.headers.gettype()
'text/html'
>>> google.headers.getencoding()
'7bit'
>>> google.headers.getcharset()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: HTTPMessage instance has no attribute 'getcharset'
所以你必须得到标题,然后拆分它。两次。
>>> google = urllib2.urlopen('http://www.google.com/')
>>> charset = 'ISO-8859-1'
>>> contenttype = google.headers.getheader('Content-Type', '')
>>> if ';' in contenttype:
... charset = contenttype.split(';')[1].split('=')[1]
>>> charset
'ISO-8859-1'
对于这样一个基本功能,步骤数量惊人。我错过了什么吗?
【问题讨论】:
来自 RFC 2616 (HTTP1.1)The "charset" parameter is used with some media types to define the character set (section 3.4) of the data. When no explicit charset parameter is provided by the sender, media subtypes of the "text" type are defined to have a default charset value of "ISO-8859-1" when received via HTTP.
,作为默认为 ASCII 的旁注。
@plundra:嗯,ISO-8859-1 是 ASCII 的超集,但你是对的 - 它是不同的编码。
@Piskvor:例如,如果将上面的 charset
与 s.decode() 一起使用,事情就会中断(页面发送 iso-8859-1 并依赖于隐式)
啊,所以我应该检查类型,如果是文本,它应该默认为 latin-1,否则它可能是二进制的,根本不应该被解码。 :) 又是复杂的一步。
【参考方案1】:
我做了一些研究并想出了这个解决方案:
response = urllib.request.urlopen(url)
encoding = response.headers.get_content_charset()
这就是我在 Python 3 中的做法。我尚未在 Python 2 中对其进行测试,但我猜你必须使用 urllib2.request
而不是 urllib.request
。
这是它的工作原理,因为官方 Python 文档没有很好地解释它:urlopen
的结果是一个http.client.HTTPResponse
对象。这个对象的headers
属性是一个http.client.HTTPMessage
对象,根据文档,它“使用email.message.Message
类实现”,它有一个名为get_content_charset
的方法,它试图确定并返回字符一组响应。
默认情况下,如果无法确定字符集,则此方法返回None
,但您可以通过传递failobj
参数来覆盖此行为:
encoding = response.headers.get_content_charset(failobj="utf-8")
【讨论】:
get_content_charset
在 Python 2 中不可用。您应该可以改用 headers.getparam("charset")
(仅限 Python 2;Python 3 将其重命名为 get_param
)。【参考方案2】:
我会选择chardet Universal Encoding Detector。
>>> import urllib
>>> urlread = lambda url: urllib.urlopen(url).read()
>>> import chardet
>>> chardet.detect(urlread("http://google.cn/"))
'encoding': 'GB2312', 'confidence': 0.99
您做得对,但是对于在 meta
标记上声明字符集或根本未声明字符集的页面,您的方法将失败。
如果您仔细查看 Chardet 的源代码,它有一个 charsetprober/charsetgroupprober
模块可以很好地处理这个问题。
【讨论】:
对我来说,这不是一个好的答案:chardet 是“猜测 [HTML] 文件的编码”(参见 github.com/erikrose/chardet)。当然,您应该首先查看标头(如果已声明)。请参阅 Leniel 指出的问题。【参考方案3】:你没有错过任何东西。它在做正确的事 - HTTP 响应的编码是 Content-Type 的子部分。
另请注意,某些页面可能只发送 Content-Type: text/html
,然后通过 <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
设置编码 - 虽然这是一个丑陋的 hack(对页面作者而言)并且不太常见。
【讨论】:
【参考方案4】:你检查过这个吗?
How to download any(!) webpage with correct charset in python?
【讨论】:
所以我错过了一些东西,即.headers.getparam('charset')
,它简化了很多。以上是关于获取网页字符集的好方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章