当您有一个text/* 响应并且没有在响应标头中指定内容类型时,Requests 会将response.encoding 属性设置为ISO-8859-1。
见Encoding section of the Advanced documentation:
Requests 唯一不会这样做的情况是,如果 HTTP 标头中没有明确的字符集并且Content-Type 标头包含text。 在这种情况下,RFC 2616 指定默认字符集必须为 ISO-8859-1。在这种情况下,请求遵循规范。如果您需要不同的编码,您可以手动设置Response.encoding 属性,或使用原始Response.content。
我的大胆强调。
您可以通过在 Content-Type 标头中查找 charset 参数来对此进行测试:
resp = requests.get(....)
encoding = resp.encoding if 'charset' in resp.headers.get('content-type', '').lower() else None
您的 HTML 文档在 <meta> 标头中指定了内容类型,并且该标头具有权威性:
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
HTML 5 还定义了一个<meta charset="..." /> 标签,参见<meta charset="utf-8"> vs <meta http-equiv="Content-Type">
如果 HTML 页面包含具有不同编解码器的此类标头,则您应该不将其重新编码为 UTF-8。在这种情况下,您至少必须更正该标题。
使用 BeautifulSoup:
# pass in explicit encoding if set as a header
encoding = resp.encoding if 'charset' in resp.headers.get('content-type', '').lower() else None
content = resp.content
soup = BeautifulSoup(content, from_encoding=encoding)
if soup.original_encoding != 'utf-8':
meta = soup.select_one('meta[charset], meta[http-equiv="Content-Type"]')
if meta:
# replace the meta charset info before re-encoding
if 'charset' in meta.attrs:
meta['charset'] = 'utf-8'
else:
meta['content'] = 'text/html; charset=utf-8'
# re-encode to UTF-8
content = soup.prettify() # encodes to UTF-8 by default
同样,其他文档标准也可能指定特定的编码;例如,XML 始终是 UTF-8,除非由 <?xml encoding="..." ... ?> XML 声明指定,这也是文档的一部分。