requests 库之响应编码问题

使用python 的requests模块进行网络请求的时候,我们有时候会遇到响应中的中文内容无法正常解析,这种情况下通常是编码的问题导致

比如:

url = 'http://httpbin.org/post'
reqbody = {'张三':19}
res = requests.post(url=url,data=reqbody)
print(res.text)

打印的内容是:

{
  "args": {}, 
  "data": "", 
  "files": {}, 
  "form": {
    "\u5f20\u4e09": "19"
  }

我们看到 中文 张三 没有被正常展示出来,而是以\u开头的字符串  \u5f20\u4e09 

我们在打印一下这串字符 ,可以看到,输出的内容就是张三

requests 库之响应编码问题

 

 

为什么会出现这种情况呢?

 

我们来看一下  响应内容的编码格式

res.encoding

#输出的是
None

我们在来看一下r.text的源码

@property
    def text(self):
        """Content of the response, in unicode.

        If Response.encoding is None, encoding will be guessed using
        ``chardet``.

        The encoding of the response content is determined based solely on HTTP
        headers, following RFC 2616 to the letter. If you can take advantage of
        non-HTTP knowledge to make a better guess at the encoding, you should
        set ``r.encoding`` appropriately before accessing this property.
        """

大概意思就是

r.text输出的是一个 Unicode 格式字符串,如果响应的编码格式为None 则调用chardet 去猜测 编码方式,

再往下看 源码

if self.encoding is None:
    encoding = self.apparent_encoding

我看到 当响应对象 的encoding 为None时,在text中调用了 apparent_encoding 去获取 响应对象的编码方式

我们试着也调用一下该方法

res.apparent_encoding

输出的是:
ascii

至此 我们找到了问题的原因:

我们的接口响应 没有设置对应的编码方式,encoding 为None 

我们通过 r.text获取响应的文本内容使用的编码是Unicode,通过 chardet  获取内容编码方式为ascii ,

而在python 3+之后的版本,无论输入输出是什么格式,中间转接的都是Unicode格式。在python运行时,自动给你转到Unicode,输出的时候再转一遍换成需要的输出格式。  

上面我们获取到的编码格式为ascii ,但是中文是又无法通过ascii进行解码输出(其他英文数字等部分已经通过ascii正常解码输出了),故这里直接以Unicode编码格式进行输出。所以我们看到中文 张三 是以\u开头的字符串输出  \u5f20\u4e09 

 

现在我们要做的是:

将unicode格式输出 转换成我们想要的中文 张三

通过

r.text.encode('latin-1').decode('unicode_escape')

输出:

{
  "args": {},
  "data": "",
  "files": {},
  "form": {
  "张三": "19"
}

 

同理 r.content 获取到的是 bytes  二进制的响应内容,在以上相同场景下,也会存在类似问题

我们通过  content.decode('unicode_escape') 将Unicode 转换成我们想要的输出

r.content.decode('unicode_escape')

输出:

{
  "args": {}, 
  "data": "", 
  "files": {}, 
  "form": {
    "张三": "19"
  }     

 

 总结:

 1、str.encode()  把一个字符串转换为其raw bytes形式

    2、bytes.decode()   把raw bytes转换为其字符串形式

遇到类似的编码问题时,先检查响应内容text是什么类型

type(text) is bytes时:

text.decode('unicode_escape')

如果type(text) is str:

text.encode('latin-1').decode('unicode_escape')

 

上一篇:Requests库学习


下一篇:Python爬虫requests.exceptions.InvalidURL: Proxy URL had no scheme, should start with http:// or https: