如何在Python 3.5中恢复文件下载?

时间:2018-08-12 20:10:02

标签: python python-3.x python-requests python-3.6 python-3.5

我正在使用python 3.5请求模块使用以下代码下载文件,如何使此代码“自动恢复”部分下载文件的下载。

response = requests.get(url, stream=True)

total_size = int(response.headers.get('content-length'))  

with open(file_path + file_name, "wb") as file:
    for data in tqdm(iterable = response.iter_content(chunk_size = 1024), total = total_size//1024, unit = 'KB'):
        file.write(data)

如果可能的话,我宁愿只使用requests模块来实现这一目标。

1 个答案:

答案 0 :(得分:1)

我不认为requests内置此功能-但您可以很容易地手动完成此操作(只要服务器支持)。

关键是Range个请求。要获取从字节12345开始的部分资源,请添加以下标头:

Range: bytes=12345-

然后您可以将结果附加到文件中。


理想情况下,您应该验证返回的是206 Partial Content而不是200,并且标头中包含所需的范围:

Content-Range: bytes 12345-123456/123456
Content-Length: 111112

您可能还需要预先验证服务器可以处理范围。您可以通过查看初始响应中的标题或执行HEAD来检查此内容来做到这一点:

Accept-Ranges: bytes

如果标头完全丢失,或者标头包含none,或者包含不包含bytes的值列表,则服务器不支持恢复。

也可以检查Content-Length来验证您是否在中断之前还没有完成整个文件。


因此,代码看起来像这样:

def fetch_or_resume(url, filename):
    with open(filename, 'ab') as f:
        headers = {}
        pos = f.tell()
        if pos:
            headers['Range'] = f'bytes={pos}-'
        response = requests.get(url, headers=headers, stream=True)
        if pos:
            validate_as_paranoid_as_you_want_to_be_(pos, response)
        total_size = int(response.headers.get('content-length'))  
        for data in tqdm(iterable = response.iter_content(chunk_size = 1024), total = total_size//1024, unit = 'KB'):
            file.write(data)

编写下载管理器类型的软件的人经常遇到的一个错误就是试图跟踪先前请求中已读取的内容。不要这样做,只是使用文件本身来告诉您您有多少。毕竟,如果您读取23456个字节,但只刷新了12345个文件,则该12345是您要开始的位置。