requests库 response 字符编码的问题

requests库 response 字符编码的问题

现象描述

有时候从网上下载或者爬取网页的时候,有时候拿到网页是乱码 。

模拟来启动一个server 服务端,编写app.py文件如下

# -*- coding: utf-8 -*- 

from flask import Flask
from flask import make_response

app = Flask(__name__)


@app.route('/')
@app.route('/index/')
def index():
    response = make_response("<lnci:content>28 U.S.C.A. § ≥ © & </lnci:content>")
    response.headers['content-type'] = 'application/xml;charset=Windows-1252'
    return response


if __name__ == '__main__':
    app.run()

注意 使用 make_response 创建 response , 默认 使用utf-8 编码,和设置headers 没有关系。 headers 只是告诉 客户端 我的文档使用什么编码方式。 如果指定了错误的方式,就有可能出现解码出现错误,或者乱码的问题。

client.py


import requests

url = 'http://127.0.0.1:5000/index'

if __name__ == '__main__':
    r = requests.get(url=url)
    print(r.encoding)

    print(r.text)

结果如下:

Windows-1252
<lnci:content>28 U.S.C.A. § ≥ © & </lnci:content>

发现有乱码 ,这些h5 的特殊字符变成了一些不认识的符号。

r.contenet 与 r.text 区别

requests库中返回 response 有两种分别是 r.text , r.content

r = requests.get(url=url)
r.text
r.content

它们的主要区别

r.text 返回 符串类型

r.content 返回的 bytes 类型, Binary Response Content

str 与 bytes 互转基础知识

补充 编码知识

我们知道 在python3 中 str 与 bytes 互转 分别是 encode ,decode 方法操作

img1

字符串类型 encode 变成一个 bytes 类型 , 然后 bytes 类型通过decode 方式 来转成 str 类型。注意这里 encode 与decode 编码要一样才能进行正常解码。

比如用 str.encode('utf-16') , 然后用 b.decode('utf-8') 就会出现错误,或者出现乱码问题。

>>> b = 'frank'.encode('utf-16')
>>> b
b'\xff\xfef\x00r\x00a\x00n\x00k\x00'
>>> b.decode('utf-8')
Traceback (most recent call last):
  File "<input>", line 1, in <module>
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 0: invalid start byte
>>> b.decode('utf-16')
'frank'

在 requests库中 r.text 返回类型 为字符串类型, 那么它用什么方式解码呢?

查看代码 发现 是通过 chardet 这个库来自动识别 ,这个编码方案 。 然后通过 str 构造方法 ,返回一个str 类型

    @property
    def apparent_encoding(self):
        """The apparent encoding, provided by the chardet library."""
        return chardet.detect(self.content)['encoding']

text 核心源码

content = str(self.content, encoding, errors='replace')

img-02

红色部分圈出来的代码,就是 推测 encoding 的编码方式。

请求发出后,Requests 会基于 HTTP 头部对响应的编码作出有根据的推测。当你访问 r.text 之时,Requests 会使用其推测的文本编码。你可以找出 Requests 使用了什么编码,并且能够使用 r.encoding 属性来改变它:

>>> r.encoding
'utf-8'
>>> r.encoding = 'ISO-8859-1'

所以 现在出现乱码的原因 可能是 encoding 不是我们想要的方式 ,我们可以直接修改 encoding 来 改变 解码方式。

解决方案

第一种方式 手动修改 r.encoding 属性

import requests

url = 'http://127.0.0.1:5000/'

if __name__ == '__main__':
    r = requests.get(url=url)
    print(f"auto detect encoding={r.encoding!r}")

    # 修改解码方式
    r.encoding = 'utf-8'
    print(r.text)

修改以后结果如下:

auto detect encoding='Windows-1252'
<lnci:content>28 U.S.C.A. § ≥ © & </lnci:content>

发现 结果没有乱码了。

第二种方式直接使用 r.content 进行解码

我们还可以通过 r.content 获取二进制内容, 通过decode手动解码 。

import requests

url = 'http://127.0.0.1:5000/'

if __name__ == '__main__':
    r = requests.get(url=url)
    print(f"auto detect encoding={r.encoding!r}")
    # 指定解码
    print(r.content.decode('utf-8'))

这种方式也是可以正常获取 xml 文档的。

总结

在抓取网页中出现乱码的原因,主要是 因为 网页的编码方式,和我们请求网页的解码方式 不一样而引起的,不想出现乱码,就要找到 服务端传输bytes流的时候使用的编码方式,这样才不会出现乱码问题。

参考文档

字符编码笔记:ASCII,Unicode 和UTF-8 - 阮一峰的网络日志

理解各种字符编码

response-content

HTML ISO-8859-1 参考手册

网页特殊符号(HTML字符实体)大全

分享快乐,留住感动. '2021-01-26 22:30:55' --frank
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值