Python爬虫requests爬取页面的编码问题.md
发现的问题
很多时候,我们发现,requests库返回的页面编码都是ISO-8859-1,需要指定为UTF-8才能正确读取。这是为什么呢?我们来看下requests文档中的描述。
https://requests.readthedocs.io/en/latest/user/advanced/
这里只贴上中文翻译
<引用开始>
当您收到响应时,Requests 会在您访问属性时猜测用于解码响应的编码。请求将首先检查 HTTP 标头中的编码,如果不存在,将使用 charset_normalizer 或chardet尝试猜测编码。
如果chardet已安装,requests则使用它,但是对于 python3 chardet不再是强制依赖项。该chardet 库是一个 LGPL 许可的依赖项,一些请求用户不能依赖于强制性 LGPL 许可的依赖项。
当您安装时requests没有指定[use_chardet_on_py3]额外的,并且chardet尚未安装,requests使用charset-normalizer (MIT-licensed)来猜测编码。
Requests 唯一不会猜测编码的情况是,如果 HTTP 标头中不存在显式字符集并且标Content-Type 头包含text. 在这种情况下,RFC 2616指定默认字符集必须是ISO-8859-1. 在这种情况下,请求遵循规范。如果你需要不同的编码,你可以手动设置Response.encoding 属性,或者使用 raw Response.content。
<引用结束>
这里最后一段的描述,特别重要,如果收到的响应HTTP头部为 Content-Type: text/html ,那么不会去猜测编码,直接返回编码是ISO-8859-1。
什么时候会出现 Content-Type: text/html 这种情况呢? 这就非常非常多了, 比如最典型的和常见的, nginx 没有设置charset 。
注意TIPS:这里说的是HTTP头部中的Content-Type字段,不是HTML页面中的 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
这是两个不同的字段。对于浏览器来说,先会采用HTTP头部中的Content-Type字段的编码,解析过程中如果发现页面中Content-Type字段有指定编码,会自动适配新的编码。
这种为了遵循RFC,而造成的不便,也被好多人吐槽。
推荐的方法
明白了原理,我们来说下如何优化。
requests提供了apparent_encoding 来对编码进行猜测,所以我们,可以直接指定 apparent_encoding 来解码。
r= requests.get(url='http://www.stats.gov.cn/')
#默认返回的编码
print(r.encoding)
#猜测的编码
print(r.apparent_encoding)
#使用猜测的编码解码
print(html.decode(r.apparent_encoding))
但是呢, 一般我们处理的是中文,中文有GB2312、GBK、GB19030 三种编码方式,GB19030是最新也是最全的编码,有时候会发现网站编码是GB2312的,但是却包含了GB19030才能解析的字符。因此如果发现中文,都指定GB19030 才是正确的选择。
r = requests.get(url='http://www.stats.gov.cn/tjsj/tjbz/tjyqhdmhcxhfdm/2017/45/14/25/451425202.html')
encode_type = r.apparent_encoding
if r.apparent_encoding in ['GB2312', 'GBK', 'GB19030']:
encode_type = 'GB18030'
html = r.content
print(html.decode(encode_type))
有些同学用chardet.detect()
来进行猜测,还需要单独安装chardet,有点多余,不推荐。
转载请注明:IPCPU-网络之路 » Python爬虫requests爬取页面的编码问题