无法获取 requests==2.7.0 以自动解压缩 gzip
Having Trouble Getting requests==2.7.0 to Automatically Decompress 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]
我输出的第一行中的 header 如下所示:
{'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 text:
�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,除非 header 有 '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')
但是,有没有更好的方法呢?
你误会了。只有 transport-level compression 会自动处理,因此 HTTP 服务器会应用压缩。
您已经压缩了内容。由于这不仅仅适用于 HTTP 传输阶段,requests
也不会删除它。
requests
通过在发送每个请求时发送 Accept-Encoding: gzip, deflate
来与服务器通信它接受压缩响应。然后服务器可以通过压缩整个响应 body 并添加一个 Content-Encoding
header 来指示所使用的压缩来响应。
您的回复没有 Content-Encoding header,在这里再次应用压缩也没有意义。
大多数时候您想要下载一个已经压缩的存档,例如压缩格式的 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 解析器而不是将解压缩的数据复制到磁盘。
不幸的是,模块的 Python2 实现需要一个可查找的文件;您可以创建自己的 streaming wrapper,或者将 _decoder
属性添加到上面的 r.raw
object。
我正在尝试读取通过请求请求的压缩 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]
我输出的第一行中的 header 如下所示:
{'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 text:
�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,除非 header 有 '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')
但是,有没有更好的方法呢?
你误会了。只有 transport-level compression 会自动处理,因此 HTTP 服务器会应用压缩。
您已经压缩了内容。由于这不仅仅适用于 HTTP 传输阶段,requests
也不会删除它。
requests
通过在发送每个请求时发送 Accept-Encoding: gzip, deflate
来与服务器通信它接受压缩响应。然后服务器可以通过压缩整个响应 body 并添加一个 Content-Encoding
header 来指示所使用的压缩来响应。
您的回复没有 Content-Encoding header,在这里再次应用压缩也没有意义。
大多数时候您想要下载一个已经压缩的存档,例如压缩格式的 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 解析器而不是将解压缩的数据复制到磁盘。
不幸的是,模块的 Python2 实现需要一个可查找的文件;您可以创建自己的 streaming wrapper,或者将 _decoder
属性添加到上面的 r.raw
object。