Requests库ISO-8859-1编码问题

Requests.Response的encoding保存了网页的编码类型,如:

In [5]: resp = requests.get('http://www.baidu.com')

In [6]: resp.encoding
Out[6]: 'utf-8'

Requests的网页编码类型取自于服务器的HTTP响应头中Content-type字段的charset:

Content-Type:text/html; charset=utf-8

不少网站不会返回charset,这种情况下Requests默认为ISO-8859-1字符。为了识别出页面的编码,还可以考虑HTML中的charset,以下为我写的一个提取函数:

def get_charset_from_html(html):
    """从HTML中提取编码类型
    """
    import re
    search = (re.search(r'charset=["\']([^"]+)["\']', html) or
	      re.search('charset=\w+', html))

    if not search:
	return None

    search_result = search.group()
    if search_result.find('=') > -1:
	return search_result.split('=')[1] \
			    .strip().replace("'", "") \
			    .replace('"', "")

    return None


def test_get_charset_from_html():
    assert(get_charset_from_html("<meta charset='gbk2312'/>") == "gbk2312")
    assert(get_charset_from_html("<meta charset=\"gbk2312\"/>") == "gbk2312")
    assert(get_charset_from_html("<meta charset=gbk2312/>") == "gbk2312")
    assert(get_charset_from_html("content='text/html; charset=GBK'>") == "GBK")

所以,可以这样相对较好的方法取HTML:

def url_to_html(url, headers=default_headers, timeout=10):
    req = requests.get(url, timeout=timeout, headers=headers)
    # requests未能正确识别的编码就默认返回ISO-885901
    # 所以尝试从HTML中找定义的编码
    if req.text and req.encoding == 'ISO-8859-1':
	encoding = get_charset_from_html(req.text)
	# XXX 如果页面也没定义编码?遇到再说吧
	if encoding:
	    req.encoding = encoding

    return req.text