Python3下的requests乱码问题

Python leaves 2年前 (2018-07-24) 853次浏览 0个评论

很多同学以为python3下没有乱码问题,遇到问题觉得这句话是神坑。刚刚由python2.7升级到python3,小试牛刀来爬了一部分数据,把遇到的问题及解决办法分享给大家:
1. 区分requests的content和text,来看源码:

文件: requests.models.py
@property
def apparent_encoding(self):
    """The apparent encoding, provided by the chardet library"""
    return chardet.detect(self.content)['encoding']
@property
def content(self):
    """Content of the response, in bytes."""
    if self._content is False:
        # Read the contents.
        try:
            if self._content_consumed:
                raise RuntimeError(
                    'The content for this response was already consumed')
            if self.status_code == 0:
                self._content = None
            else:
                self._content = bytes().join(self.iter_content(CONTENT_CHUNK_SIZE)) or bytes()
        except AttributeError:
            self._content = None
    self._content_consumed = True
    # don't need to release the connection; that's been handled by urllib3
    # since we exhausted the data.
    return self._content
@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.
    """
    # Try charset from content-type
    content = None
    encoding = self.encoding
    if not self.content:
        return str('')
    # 当为空的时候会使用chardet来猜测编码.
    if self.encoding is None:
        encoding = self.apparent_encoding
    # Decode unicode from given encoding.
    try:
        content = str(self.content, encoding, errors='replace')
    except (LookupError, TypeError):
        # A LookupError is raised if the encoding was not found which could
        # indicate a misspelling or similar mistake.
        #
        # A TypeError can be raised if encoding is None
        #
        # So we try blindly encoding.
        content = str(self.content, errors='replace')

分析requests的源代码发现,text返回的是处理过的Unicode型的数据,而使用content返回的是bytes型的原始数据。也就是说,res.content相对于res.text来说节省了计算资源,content是把内容bytes返回. 而text是decode成Unicode. 如果headers没有charset字符集的化,text()会调用chardet来计算字符集,这又是消耗cpu的事情。
接下来看一个有意思的试验:

In [9]: r = requests.get('http://cn.python-requests.org/en/latest/')
In [10]: r.encoding
Out[10]: 'ISO-8859-1'
# text返回unicode
In [11]: type(r.text)
Out[11]: unicode
# content返回的是str
In [12]: type(r.content)
Out[12]: str
In [13]: r.apparent_encoding
Out[13]: 'utf-8'
In [14]: chardet.detect(r.content)
Out[14]: {'confidence': 0.99, 'encoding': 'utf-8'}

这个是个requests的bug,不过官方反馈是按照http rfc设计的,并没打算改啊~
看到这你可能就大致的了解了,res.text比较适合返回的问题,而如果返回是图像、文件等格式内容res.content更合适;
2. 看看哪些会影响乱码:
1. IDE及文件的编码格式UTF-8,这种配置可以去百度;
2. python自身的编码格式,可以通过sys.getdefalutencoding()来获得
3. 代码的缺省编码:文件头上# -*- coding: utf-8 –*-
4. 访问url的响应header及网页的默认编码
……
《HTTP权威指南》里第16章国际化里提到,如果HTTP响应中Content-Type字段没有指定charset,则默认页面是’ISO-8859-1’编码。啥是’ISO-8859-1’?这种编码又被叫做Latin-1或“西欧语言”,所以处理英文ok,处理中文就会乱码了。
3. 解决办法,采用res.apparent_encoding判断编码类型

# 如果在确定使用text,并已经得知该站的字符集编码时,可以使用 r.encoding = ‘xxx’ 模式, 当你指定编码后,requests在text时会根据你设定的字符集编码进行转换.
# 使用apparent_encoding可以获得真实编码
1 >>> response.apparent_encoding
'GB2312'
# 这是程序自己分析的,会比较慢,还可以从html的meta中抽取
1 >>> requests.utils.get_encodings_from_content(response.text)
['gb2312']
解决方法
1 # response.encoding = response.apparent_encoding
2 response.encoding = 'gb2312'

版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:Python3下的requests乱码问题
喜欢 (0)
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址