requests乱码问题

0x00 前言

最近使用requests get百度的时候,发现requests自动识别的编码总是ISO-8859-1,引发深夜调试。

0x01 requests自动识别编码

1
2
3
import requests
rsp = requests.get("https://www.baidu.com/")
print(rsp.encoding) # ISO-8859-1

1.png

可以看到这里显示是ISO-8859-1,为什么是这个编码,requests官方解释是因为按照RFC标准这样写的。

issues:https://github.com/psf/requests/issues/1774

2.png

只要在header头中Content-Type没有设置编码,就设置编码为ISO-8859-1。

requests官方也是早知道使用者会存在这样的问题,所以他提供了下面三种方法获取编码。

1
get_encodings_from_content从 响应的内容 中获取编码,get_encoding_from_headers从 HTTP 响应头部获取编码,chardet.detect使用工具从响应内容自动检测

requests官方就是要按照RFC标准去写,让开发人员自己决定使用。

0x02 百度有点狗

requests是能够根据 Content-Type自动获取编码的。为什么还是编码不对?来看下chrome的流量。

3.png

返回包设置了Content-Type,编码为utf8。

于是怀疑自己的requests版本过低了,于是更新了下版本还是一样的。然后又在linux和win环境测试了下,发现依旧没设置正确的编码。

于是debug requests的源码,找到对self.encoding进行写的地方。

adapters.py
4.png

发现response.headers中居然没有Content-Type
5.png

那为什么以前我记得百度是能够正常返回编码的。于是我加下User-Agent,正常返回Content-Type,编码utf-8。

1
2
3
4
5
6
import requests
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.80 Safari/537.36'
}
rsp = requests.get("https://www.baidu.com/",headers=headers)
print(rsp.encoding) # utf-8

百度这个设计把我忽悠瘸了。

0x03 解决

chardet.detect识别

1
2
3
4
import requests
rsp = requests.get("https://www.baidu.com/")
rsp.encoding = rsp.apparent_encoding if rsp.encoding == 'ISO-8859-1' else rsp.encoding
print(rsp.encoding)

这里不推荐使用get_encodings_from_content获取,因为官方说后面要废弃了。所以使用chardet.detect是猜测编码。

加user-agent

1
2
3
4
5
6
import requests
headers = {
'User-Agent': 'Mozilla/5.0 Safari/537.36'
}
rsp = requests.get("https://www.baidu.com/",headers=headers)
print(rsp.encoding)

6.png