获取网页字符集的好方法是啥?

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,然后通过 &lt;meta http-equiv="Content-Type" content="text/html; charset=utf-8"&gt; 设置编码 - 虽然这是一个丑陋的 hack(对页面作者而言)并且不太常见。

【讨论】:

【参考方案4】:

你检查过这个吗?

How to download any(!) webpage with correct charset in python?

【讨论】:

所以我错过了一些东西,即.headers.getparam('charset'),它简化了很多。

以上是关于获取网页字符集的好方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章

在R中,聚合字符串数据的好方法是啥

通过套接字以字符串形式发送数据的好方法是啥?

从用户代理中识别 iOS 设备的好方法是啥?

在Django中获取页面动态标题的好方法是啥?

开发简单的序列号生成器/验证器的好方法是啥?

获取城市内所有邮政编码/邮政编码的好方法是啥?