【问题标题】:Having Trouble Getting requests==2.7.0 to Automatically Decompress gzip无法获取请求==2.7.0 以自动解压缩 gzip
【发布时间】:2015-09-08 17:04:44
【问题描述】:

我正在尝试读取我通过请求请求的 gzip 压缩 XML 文件。我读过的所有内容都表明解压缩应该自动发生。

#!/usr/bin/python

from __future__ import unicode_literals
import requests

if __name__ == '__main__':

    url = 'http://rdf.dmoz.org/rdf/content.rdf.u8.gz'

    headers = {
        'Accept-Encoding': "gzip,x-gzip,deflate,sdch,compress",
        'Accept-Content': 'gzip',
        'HTTP-Connection': 'keep-alive',
        'Accept-Language': "en-US,en;q=0.8",
    }

    request_reply = requests.get(url, headers=headers)

    print request_reply.headers

    request_reply.encoding = 'utf-8'
    print request_reply.text[:200]
    print request_reply.content[:200]

我的第一行输出中的标题如下所示:

{'content-length': '260071268', 'accept-ranges': 'bytes', 'keep-alive': 'timeout=5, max=100', 'server': 'Apache', 'connection': 'Keep-Alive', 'date': 'Tue, 08 Sep 2015 16:27:49 GMT', 'content-type': 'application/x-gzip'}

接下来的两行输出似乎是二进制的,我期待的是 XML 文本:

�Iɒ(�����~ؗool���u�rʹ�J���io�   a2R1��ߞ|�<����_��������Ҽҿ=�Z����onnz7�{JO���}h�����6��·��>,aҚ>��hZ6�u��x���?y�_�.y�$�Բ
�Iɒ(�����~ؗool���u�rʹ�J���io�   a2R1��ߞ|�<����_��������Ҽҿ=�Z����onnz7�{JO��}h�����6��·��>,aҚ>��hZ6�u��x���

我认为部分问题是site-packages/requests/packages/urllib3/response.py 无法识别 gzip,除非标头有 'content-encoding': 'gzip'

我可以通过在response.py 中的方法中添加 4 行来获得我想要的结果,如下所示:

    def _init_decoder(self):
        """
        Set-up the _decoder attribute if necessar.
        """
        # Note: content-encoding value should be case-insensitive, per RFC 7230
        # Section 3.2
        content_encoding = self.headers.get('content-encoding', '').lower()
        if self._decoder is None and content_encoding in self.CONTENT_DECODERS:
            self._decoder = _get_decoder(content_encoding)

        # My added code below this comment
            return
        content_type = self.headers.get('content-type', '').lower()
        if self._decoder is None and content_type == 'application/x-gzip':
            self._decoder = _get_decoder('gzip')

但是,有没有更好的方法?

【问题讨论】:

    标签: python python-requests


    【解决方案1】:

    你误会了。只有transport-level compression 是自动处理的,所以由HTTP 服务器应用压缩。

    您已压缩内容。由于这不仅仅适用于 HTTP 传输阶段,requests 也不会删除它。

    requests 通过在发送每个请求时发送Accept-Encoding: gzip, deflate 来与服务器通信它接受压缩响应。然后,服务器可以通过压缩整个响应正文并添加一个Content-Encoding 标头来指示使用的压缩方式来响应。

    您的响应没有 Content-Encoding 标头,在这里再次应用压缩也没有意义。

    大多数时候您希望下载已压缩的存档,例如压缩形式的 DMOZ RDF 数据集,无论如何。毕竟,您请求了压缩存档。解码它不是 requests 库的工作。

    在 Python 3 中,您可以使用 gzip module 将解码作为流处理并流式传输响应:

    import gzip
    import requests
    import shutil
    
    r = requests.get(url, stream=True)
    if r.status_code == 200:
        with open(path, 'wb') as f:
            r.raw.decode_content = True  # just in case transport encoding was applied
            gzip_file = gzip.GzipFile(fileobj=r.raw)
            shutil.copyfileobj(gzip_file, f)
    

    当然,您可以使用 RDF 解析器而不是将解压缩的数据复制到磁盘。

    不幸的是,该模块的 Python 2 实现需要一个可搜索的文件;您可以创建自己的streaming wrapper,或者将_decoder 属性添加到上面的r.raw 对象中。

    【讨论】:

    • 有道理。我返回并更仔细地重新阅读了docs.python-requests.org/en/latest/community/faqEncoded Data? 部分(不要将responsecontent 混淆)。它似乎同意你的看法。感谢您快速而彻底的回复!
    • @Reinderien 仅在 Python 2 中;我明确指出这只适用于 Python 3
    • 糟糕——我错过了那部分。该死。
    猜你喜欢
    • 2019-05-07
    • 1970-01-01
    • 2016-05-26
    • 2012-08-22
    • 2010-11-29
    • 2023-04-10
    • 2011-05-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多