一个很好的方式来获得在Python HTTP响应的字符集/编码(A good way to get

2019-07-18 23:35发布

寻找一个简单的方法来使用Python的urllib2,或任何其他Python库的HTTP响应的字符集/编码信息。

>>> url = 'http://some.url.value'
>>> request = urllib2.Request(url)
>>> conn = urllib2.urlopen(request)
>>> response_encoding = ?

我知道,有时出现在“内容类型”头,但头有其他的信息,它的嵌入,我需要解析字符串。 例如,由谷歌返回的Content-Type头是

>>> conn.headers.getheader('content-type')
'text/html; charset=utf-8'

我可以与工作,但我不知道该格式将如何保持一致。 我敢肯定,这是可能的字符集是完全缺失的,所以我必须处理边缘情况。 某种字符串分割操作,以获得“UTF-8”出来的,好像它是错误的方式做这种事情。

>>> content_type_header = conn.headers.getheader('content-type')
>>> if '=' in content_type_header:
>>>  charset = content_type_header.split('=')[1]

这就是那种感觉就像它做太多的工作代码。 我也不知道是否会在任何情况下工作。 有没有人有更好的方式来做到这一点?

Answer 1:

要解析HTTP头,你可以使用cgi.parse_header()

_, params = cgi.parse_header('text/html; charset=utf-8')
print params['charset'] # -> utf-8

或使用响应对象:

response = urllib2.urlopen('http://example.com')
response_encoding = response.headers.getparam('charset')
# or in Python 3: response.headers.get_content_charset(default)

一般地,服务器可以位于关于编码或根本不报告它(默认取决于内容类型)或编码可能响应主体例如内被指定, <meta>在HTML文档或XML声明为xml元素文档。 作为最后的手段编码可以从内容本身猜测。

你可以使用requests获得Unicode文本:

import requests # pip install requests

r = requests.get(url)
unicode_str = r.text # may use `chardet` to auto-detect encoding

BeautifulSoup解析HTML(和转换为Unicode的副作用):

from bs4 import BeautifulSoup # pip install beautifulsoup4

soup = BeautifulSoup(urllib2.urlopen(url)) # may use `cchardet` for speed
# ...

bs4.UnicodeDammit直接任意内容(不一定是HTML):

from bs4 import UnicodeDammit

dammit = UnicodeDammit(b"Sacr\xc3\xa9 bleu!")
print(dammit.unicode_markup)
# -> Sacré bleu!
print(dammit.original_encoding)
# -> utf-8


Answer 2:

如果你恰好是熟悉瓶 / WERKZEUG网络开发堆栈,你会很高兴知道WERKZEUG库中有正是这种HTTP报头解析的答案,并解释了所有内容类型没有指定的情况下总之,像你所希望的。

 >>> from werkzeug.http import parse_options_header
 >>> import requests
 >>> url = 'http://some.url.value'
 >>> resp = requests.get(url)
 >>> if resp.status_code is requests.codes.ok:
 ...     content_type_header = resp.headers.get('content_type')
 ...     print content_type_header
 'text/html; charset=utf-8'
 >>> parse_options_header(content_type_header) 
 ('text/html', {'charset': 'utf-8'})

所以,那么你可以这样做:

 >>> content_type_header[1].get('charset')
 'utf-8'

请注意,如果charset不提供,这将产生相反:

 >>> parse_options_header('text/html')
 ('text/html', {})

它甚至如果你不提供什么,但一个空字符串或者字典的工作原理:

 >>> parse_options_header({})
 ('', {})
 >>> parse_options_header('')
 ('', {})

因此,它似乎正是你要找的人! 如果你看一下源代码,你会看到他们你的目的记: https://github.com/mitsuhiko/werkzeug/blob/master/werkzeug/http.py#L320-329

def parse_options_header(value):
    """Parse a ``Content-Type`` like header into a tuple with the content
    type and the options:
    >>> parse_options_header('text/html; charset=utf8')
    ('text/html', {'charset': 'utf8'})
    This should not be used to parse ``Cache-Control`` like headers that use
    a slightly different format.  For these headers use the
    :func:`parse_dict_header` function.
    ...

希望这可以帮助别人有一天! :)



Answer 3:

requests库使得这个简单的:

>>> import requests
>>> r = requests.get('http://some.url.value')
>>> r.encoding
'utf-8' # e.g.


Answer 4:

集可以在指定的许多方面 ,但它往往是在头这样做。

>>> urlopen('http://www.python.org/').info().get_content_charset()
'utf-8'
>>> urlopen('http://www.google.com/').info().get_content_charset()
'iso-8859-1'
>>> urlopen('http://www.python.com/').info().get_content_charset()
>>> 

这最后一个没有任何地方指定一个字符集,所以get_content_charset()返回None



Answer 5:

要正确(在IE浏览器样的方式 - 我们不能做的更好),解码HTML,你需要采取帐户:

  1. 内容类型HTTP标头值;
  2. BOM标志的;
  3. <meta>在页面主体标记;
  4. 定义的编码名称之间的差异在网中使用在Python STDLIB可用的编码名称;
  5. 作为最后的手段,如果一切都失败了,基于统计的猜测是一种选择。

所有上述在实施w3lib.encoding.html_to_unicode功能:它有html_to_unicode(content_type_header, html_body_str, default_encoding='utf8', auto_detect_fun=None)签名并返回(detected_encoding, unicode_html_content)元组。

请求,BeautifulSoup,UnicodeDamnnit,chardet的或瓶的parse_options_header不正确的解决方案,因为他们都失败的部分观点。



文章来源: A good way to get the charset/encoding of an HTTP response in Python