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

How to resume file download in Python 3.5?

我正在使用 python 3.5 请求模块使用以下代码下载文件,如何使此代码 "auto-resume" 从部分下载的文件下载。

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 模块来实现。

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

关键是Range个请求。要获取从字节 12345 开始的部分资源,您可以添加此 header:

Range: bytes=12345-

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


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

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

您可能还想 pre-validate 服务器处理范围。您可以通过查看初始响应中的 header 来执行此操作,或者通过执行 HEAD 来检查以下内容:

Accept-Ranges: bytes

如果 header 完全缺失,或者有 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 就是您要开始的地方。