【问题标题】:How to deal with deflated response by urllib2? [duplicate]如何处理 urllib2 的瘪响应? [复制]
【发布时间】:2010-12-24 06:23:02
【问题描述】:

我目前使用以下代码通过 urllib2 解压缩 gzipped 响应:

opener = urllib2.build_opener()
response = opener.open(req)
data = response.read()
if response.headers.get('content-encoding', '') == 'gzip':
    data = StringIO.StringIO(data)
    gzipper = gzip.GzipFile(fileobj=data)
    html = gzipper.read()

它是否也处理放缩响应,还是我需要编写单独的代码来处理放缩响应?

【问题讨论】:

  • 除非客户端使用 Accept-Encoding: 标头请求,否则 HTTP 服务器不应发送压缩响应。所以你不应该处理任何一个
  • 在这种情况下,我在上面的代码之前添加了 req.add_header('Accept-Encoding', 'gzip,deflate') 。但是,如果我没有指定“Accept-Encoding”标头,有时 urllib2 会从 text/html url 返回二进制数据,并且无法在屏幕上打印。那么,您确定所有 http 服务器都不会发送没有“Accept-Encoding”标头的压缩响应吗?
  • urllib2 自动添加 Accept-Encoding: gzip, 创建默认请求对象时放气,所以这不是服务器的问题(虽然不知道如何关闭它)
  • 如果可能,您应该从Accept-Encoding 中删除deflate。在此处的答案中查看我的 cmets:stackoverflow.com/questions/9170338/…。如果您必须接受deflate,那么您将需要尝试解码可能的编码,zlib 和 raw deflate。

标签: python gzip urllib2 deflate


【解决方案1】:

你可以在urllib3看到代码

class DeflateDecoder(object):

    def __init__(self):
        self._first_try = True
        self._data = binary_type()
        self._obj = zlib.decompressobj()

    def __getattr__(self, name):
        return getattr(self._obj, name)

    def decompress(self, data):
        if not data:
            return data

        if not self._first_try:
            return self._obj.decompress(data)

        self._data += data
        try:
            return self._obj.decompress(data)
        except zlib.error:
            self._first_try = False
            self._obj = zlib.decompressobj(-zlib.MAX_WBITS)
            try:
                return self.decompress(self._data)
            finally:
                self._data = None


class GzipDecoder(object):

    def __init__(self):
        self._obj = zlib.decompressobj(16 + zlib.MAX_WBITS)

    def __getattr__(self, name):
        return getattr(self._obj, name)

    def decompress(self, data):
        if not data:
            return data
        return self._obj.decompress(data)

【讨论】:

    【解决方案2】:

    有一个更好的方法概述在:

    作者解释了如何逐块解压缩,而不是在内存中一次全部解压。当涉及到较大的文件时,这是首选方法。

    还发现这个有用的测试网站:

    【讨论】:

      【解决方案3】:

      你可以试试

      if response.headers.get('content-encoding', '') == 'deflate':
          html = zlib.decompress(response.read())
      

      如果失败,这里有另一种方法,我在requests source code找到了,

      if response.headers.get('content-encoding', '') == 'deflate':
          html = zlib.decompressobj(-zlib.MAX_WBITS).decompress(response.read())
      

      【讨论】:

        【解决方案4】:

        为了回答上述评论,HTTP 规范 (http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.3) 说:

        如果请求中没有 Accept-Encoding 字段,服务器可以假设客户端将接受任何内容编码。在这种情况下,如果“身份”是可用的内容编码之一,那么服务器应该使用“身份”内容编码,除非它有额外的信息表明不同的内容编码对客户端有意义。

        我认为这意味着它应该使用身份。我从未见过不支持的服务器。

        【讨论】:

        • 只有当服务器说“deflate”并提供“zlib”时它才会起作用。 “zlib”!=“放气”。请参阅 Alex Martelli 引用的 SO 线程。
        • 我做了更多的测试,你是对的,它不适用于所有服务器。但是没有“zlib”编码之类的东西,而deflate zlib算法,它只需要一个适当的标头或其他东西
        猜你喜欢
        • 1970-01-01
        • 2014-12-24
        • 2014-07-07
        • 2017-08-23
        • 1970-01-01
        • 1970-01-01
        • 2012-08-18
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多