文档章节

Python+Requests编码识别Bug

Cnlouds
 Cnlouds
发布于 2015/08/16 20:05
字数 526
阅读 843
收藏 7

Requests 是使用 Apache2 Licensed 许可证的 HTTP 库。用 Python 编写,更友好,更易用。

Requests 使用的是 urllib3,因此继承了它的所有特性。Requests 支持 HTTP 连接保持和连接池,支持使用 cookie 保持会话,支持文件上传,支持自动确定响应内容的编码,支持国际化的 URL 和 POST 数据自动编码。现代、国际化、人性化。

最近在使用Requests的过程中发现一个问题,就是抓去某些中文网页的时候,出现乱码,打印encoding是ISO-8859-1。为什么会这样呢?通过查看源码,我发现默认的编码识别比较简单,直接从响应头文件的Content-Type里获取,如果存在charset,则可以正确识别,如果不存在charset但是存在text就认为是ISO-8859-1,见utils.py。


def get_encoding_from_headers(headers):
    """Returns encodings from given HTTP Header Dict.

    :param headers: dictionary to extract encoding from.
    """
    content_type = headers.get('content-type')

    if not content_type:
        return None

    content_type, params = cgi.parse_header(content_type)

    if 'charset' in params:
        return params['charset'].strip("'\"")

    if 'text' in content_type:
        return 'ISO-8859-1'

其实Requests提供了从内容获取编码,只是在默认中没有使用,见utils.py:


def get_encodings_from_content(content):
    """Returns encodings from given content string.

    :param content: bytestring to extract encodings from.
    """
    charset_re = re.compile(r'<meta.*?charset=["\']*(.+?)["\'>]', flags=re.I)
    pragma_re = re.compile(r'<meta.*?content=["\']*;?charset=(.+?)["\'>]', flags=re.I)
    xml_re = re.compile(r'^<\?xml.*?encoding=["\']*(.+?)["\'>]')

    return (charset_re.findall(content) +
            pragma_re.findall(content) +
            xml_re.findall(content))



还提供了使用chardet的编码检测,见models.py:

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



如何修复这个问题呢?先来看一下示例:

>>> r = requests.get('http://cn.python-requests.org/en/latest/')
>>> r.headers['content-type']
'text/html'
>>> r.encoding
'ISO-8859-1'
>>> r.apparent_encoding
'utf-8'
>>> requests.utils.get_encodings_from_content(r.content)
['utf-8']

>>> r = requests.get('http://reader.360duzhe.com/2013_24/index.html')
>>> r.headers['content-type']
'text/html'
>>> r.encoding
'ISO-8859-1'
>>> r.apparent_encoding
'gb2312'
>>> requests.utils.get_encodings_from_content(r.content)
['gb2312']



通过了解,可以这么用一个monkey patch解决这个问题:

import requests
def monkey_patch():
    prop = requests.models.Response.content
    def content(self):
        _content = prop.fget(self)
        if self.encoding == 'ISO-8859-1':
            encodings = requests.utils.get_encodings_from_content(_content)
            if encodings:
                self.encoding = encodings[0]
            else:
                self.encoding = self.apparent_encoding
            _content = _content.decode(self.encoding, 'replace').encode('utf8', 'replace')
            self._content = _content
        return _content
    requests.models.Response.content = property(content)
monkey_patch()

相关文章:

本文转载自:http://www.liguangming.com/python-requests-ge-encoding-from-headers

共有 人打赏支持
Cnlouds
粉丝 13
博文 95
码字总数 56136
作品 0
海淀
程序员
python+requests实现接口测试 - get与post请求使用

简介:Requests 是用Python语言编写,基于 urllib,采用 Apache2 Licensed 开源协议的 HTTP 库。它比 urllib 更加方便,可以节约我们大量的工作,完全满足 HTTP 测试需求。Requests 的哲学是...

上官夏洛特
09/04
0
0
python的requests库和urllib包对比

python中有多种库可以用来处理http请求,比如python的原生库:urllib包、requests类库。urllib和urllib2是相互独立的模块,python3.0以上把urllib和urllib2合并成一个库了,requests库使用了...

yzy121403725
07/04
0
0
linux下使用vim打开文件乱码问题解决方案

方案一:修改.vimrc文件 添加下面一行代码 set fileencodings=ucs-bom,utf-8,cp936,gb18030,big5,euc-jp,euc-kr,latin1 编码的前后顺序代表了vim在识别文件编码使用的优先次序,所以在不了解...

苗雨顺
2011/04/18
0
0
Gogs v0.8.10 发布,极易搭建的自助 Git 托管服务

Gogs v0.8.10 发布,该版本为 Bug 修复,可选升级。 Bug 修复 在 Windows 下无法识别 Git 版本 #2167 火狐下无法预览 Wiki #2176 使用 PostgreSQL 作为数据库时无法正常浏览仓库的关注者和称...

无闻
2015/12/18
1K
14
WebMagic 0.7.3 版本发布,Java 爬虫框架

WebMagic是一个简单灵活的Java爬虫框架。基于WebMagic,你可以快速开发出一个高效、易维护的爬虫。 本次更新增加了Downloader模块的一些功能。 #609 修复HttpRequestBody没有默认构造函数导致...

黄亿华
2017/07/31
1K
6

没有更多内容

加载失败,请刷新页面

加载更多

你为什么在Redis里读到了本应过期的数据

一个事故的故事 晚上睡的正香突然被电话吵醒,对面是开发焦急的声音:我们的程序在访问redis的时候读到了本应过期的key导致整个业务逻辑出了问题,需要马上解决。 看到这里你可能会想:这是不...

IT--小哥
今天
2
0
祝大家节日快乐,阖家幸福! centos GnuTLS 漏洞

yum update -y gnutls 修复了GnuTLS 漏洞。更新到最新 gnutls.x86_64 0:2.12.23-22.el6 版本

yizhichao
昨天
5
0
Scrapy 1.5.0之选择器

构造选择器 Scrapy选择器是通过文本(Text)或 TextResponse 对象构造的 Selector 类的实例。 它根据输入类型自动选择最佳的解析规则(XML vs HTML): >>> from scrapy.selector import Sele...

Eappo_Geng
昨天
4
0
Windows下Git多账号配置,同一电脑多个ssh-key的管理

Windows下Git多账号配置,同一电脑多个ssh-key的管理   这一篇文章是对上一篇文章《Git-TortoiseGit完整配置流程》的拓展,所以需要对上一篇文章有所了解,当然直接往下看也可以,其中也有...

morpheusWB
昨天
5
0
中秋快乐!!!

HiBlock
昨天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部