请求Gzip HTTP下载并写入磁盘

时间:2016-03-29 18:36:19

标签: python-2.7 http gzip python-requests zlib

我正在使用请求库和python 2.7从web api下载gzip压缩文本文件。使用下面的代码,我能够成功发送一个get请求,并从头部判断,接收gzip文件形成的响应。

我知道Requests会自动解压缩这些文件,如果它从头部检测到响应是gzip压缩的话。我希望以文件流的形式进行下载,并将内容写入磁盘以供存储和将来分析。

当我在工作目录中打开生成的文件但是我得到这样的字符: - }}¶-Q@Ï'õ

作为参考,一些响应标题包括'Content-Encoding':'gzip','Content-Type':'application / download','Accept-Encoding,User-Agent'

用二进制文写错了吗?我没有正确编码文本(即可能是ASCII vs utf-8)?响应头中没有明显的字符编码。

try:
    response = requests.get(url, paramDict, stream=True)
except Exception as e:
    print(e)

with open(outName, 'wb') as out_file:
    for chunk in response.iter_content(chunk_size=1024):
        out_file.write(chunk)

编辑3.30.2016 :     现在我已经改变了我的代码以利用gzipstream库。我尝试使用该流来读取我的响应内容中的整个Gzip文本文件:

with open(outName, 'wb') as out_file, GzipStreamFile(response.content) as fileStream:
    streamContent = fileStream.read()
    out_file.write(streamContent)

然后我收到了这个错误: out_file.write(streamContent) AttributeError:'_ _ GzipStreamFile'对象没有属性'close'

输出是一个空文本文件,文件名符合预期。我是否需要在with块之外初始化我的streamContent变量,以便它不会自动尝试在块的末尾调用close方法?

编辑4.1.2016 我想澄清一点,这不一定是一个流,这只是我遇到的一个解决方案。我只想每天请求这个gzip压缩文件,并以明文本地保存

3 个答案:

答案 0 :(得分:3)

因此,stream=Trueiter_content的组合是造成问题的原因。您可能想要做的是类似于此(保持流式传输行为):

try:
    response = requests.get(url, params=paramDict, stream=True)
except Exception as e:
    print(e)

raw = response.raw
with open(outName, 'wb') as out_file
    while True:
        chunk = raw.read(1024, decode_content=True)
        if not chunk:
            break
        out_file.write(chunk)

请注意,您仍然希望使用字节,因为您尚未确定内容的字符编码,因此您仍然拥有字节,但您不再处理gzip压缩字节。

答案 1 :(得分:3)

try:
    response = requests.get(url, paramDict)
except Exception as e:
    print(e)

data = zlib.decompress(response.content, zlib.MAX_WBITS|32)

with open('outFileName.txt','w') as outFile:
    outFile.write(data)

以下是我编写的代码,最终正在运行。正如sigmavirus所说:该文件是以gzip开头的。我知道这个事实,但是我没有清楚地描述它,因为我一直在读取/写入gzip压缩字节。

使用zlib模块,我能够将响应的内容一次性解压缩到数据变量中;然后我将包含解压缩数据的变量写入文件。

我不确定这是否是最佳或最pythonic方式,但它确实有效。如果有人可以告诉我为什么我不能gzip.open这个内容(也许我需要使用替代方法,我试过gzipstream库无济于事),我会感谢任何解释,但我确实认为这个问题得到了解答。

感谢所有帮助过我的人,即使你没有解决方案,也帮助我鼓励我坚持下去!

答案 2 :(得分:0)

您正在请求剥离块传输编码但保留内容编码完整的原始套接字流。换句话说:你所拥有的内容肯定是gzipped内容。 Content-Encoding: gzip标头的存在是一个强有力的指标,因为http客户端在删除内容编码时需要将其删除。

消除此问题的一种方法是在请求中发送一个空的Accept-Encoding标头,表明没有可接受的编码。如果API符合RFC,则应收到未压缩的响应。另一种方法是自己解压缩流。我相信这不能通过gzip和zlib模块本地完成。但是,gzipstream lib应该给你一个开始。