请求 Gzip HTTP 下载并写入磁盘

Requests Gzip HTTP download and write to disk

我正在使用请求库和 python 2.7 从 Web api 下载 gzip 文本文件。使用下面的代码,我能够成功发送一个获取请求,并且从 header 判断,接收到 gzip 文件形式的响应。

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

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

供参考,部分回复 header 包括 'Content-Encoding':'gzip'、'Content-Type':'application/download'、'Accept-Encoding,User-Agent'

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

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)

编辑 2016 年 3 月 30 日: 现在我稍微更改了我的代码以使用 gzipstream 库。我尝试使用流来读取响应内容中的全部 Gzipped 文本文件:

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

然后我收到了这个错误: out_file.write(流内容) AttributeError: '_GzipStreamFile' object 没有属性 'close'

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

编辑 4.1.2016 只是想我要澄清一下,这不一定是一个流,这只是我遇到的一个解决方案。我只想每天请求这个 gzip 文件并将其以明文形式保存在本地

您正在请求原始套接字流,该流正在剥离块传输编码但保持内容编码不变。换句话说:你得到的肯定是 gzip 压缩的内容。 Content-Encoding: gzip header 的存在是一个强有力的指标,因为如果 http 客户端删除内容编码,则需要删除它。

消除这种情况的一种方法是在请求中发送一个空的 Accept-Encoding header 以指示不接受任何编码。如果 API 符合 RFC 标准,您应该会收到未压缩的响应。另一种方法是自己解压缩流。我相信这不能由 gzip 和 zlib 模块本地完成。然而,gzipstream 库应该给你一个开始。

所以 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 字节。

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 压缩了。我知道这个事实,但显然描述得不够清楚,因为我保留了 read/writing gzip 字节。

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

我不确定这是最好的还是最符合 pythonic 的方法,但它确实有效。如果有人能告诉我为什么我不能 gzip.open 这个内容(也许我需要使用替代方法,我尝试了 gzipstream 库但无济于事),我将不胜感激任何解释,但我确实认为这个问题得到了回答。

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