requests response.iter_content() 下载文件不完整(1024MB而非1.5GB)?

14 投票
3 回答
11968 浏览
提问于 2025-04-18 06:29

你好,我一直在用这段代码从一个网站下载文件,到目前为止,所有小于1GB的文件都下载得很好。但是我发现一个1.5GB的文件下载不完整。

# s is requests session object
r = s.get(fileUrl, headers=headers, stream=True)

start_time = time.time()
with open(local_filename, 'wb') as f:
    count = 1
    block_size = 512
    try:
        total_size = int(r.headers.get('content-length'))
        print 'file total size :',total_size
    except TypeError:
        print 'using dummy length !!!'
        total_size = 10000000

    for chunk in r.iter_content(chunk_size=block_size):

        if chunk:  # filter out keep-alive new chunks

            duration = time.time() - start_time
            progress_size = int(count * block_size)
            if duration == 0:
                duration = 0.1
            speed = int(progress_size / (1024 * duration))
            percent = int(count * block_size * 100 / total_size)
            sys.stdout.write("\r...%d%%, %d MB, %d KB/s, %d seconds passed" %
                            (percent, progress_size / (1024 * 1024), speed, duration))

            f.write(chunk)
            f.flush()
            count += 1

我使用的是最新的requests 2.2.1,Python 2.6.6,CentOS 6.4。这个文件的下载总是停在66.7%处,也就是1024MB,我漏掉了什么吗?输出结果是:

file total size : 1581244542
...67%, 1024 MB, 5687 KB/s, 184 seconds passed

看起来iter_content()返回的生成器认为所有的数据块都已经获取完了,并且没有出现错误。顺便说一下,异常处理的部分没有运行,因为服务器确实在响应头中返回了内容的长度。

3 个回答

0

我觉得你忘记关闭 req 了。

来自请求库的作者说,
“如果你在使用 stream=True 时发现自己只部分读取请求内容(或者根本不读取),你应该在一个 with 语句中发起请求,以确保它总是被关闭。”

http://2.python-requests.org//en/latest/user/advanced/#body-content-workflow

1

如果你在使用Nginx作为文件系统,你可以查看Nginx的配置文件,看看你是否设置了

proxy_max_temp_file_size 3000m;

这一项。

默认情况下,这个大小是1G,也就是说你最多只能使用1024MB

3

请确认一下你能否通过 wget 或者任何普通的浏览器下载这个文件。可能是服务器上有一些限制。根据我看到的情况,你的代码是可以下载大文件的(比1.5GB还要大)。

更新:请尝试反转一下逻辑 - 不要使用

if chunk: # filter out keep-alive new chunks                                                                                                                                                                                                         
    f.write(chunk)                                                                                                                                                                                                                                   
    f.flush()

试试

if not chunk:
   break

f.write(chunk)                                                                                                                                                                                                                                   
f.flush()

撰写回答