import os
import shutil
from urllib.request import ProxyHandler, build_opener

proxy = 'http://proxy.example.net:8080'
opener = build_opener(ProxyHandler({
    'http': proxy,
    'https': proxy,
}))

temporary = 'archive.zip.part'
destination = 'archive.zip'

with opener.open('https://downloads.example.net/archive.zip',
                 timeout=20) as response:
    with open(temporary, 'wb') as output:
        shutil.copyfileobj(response, output)

os.replace(temporary, destination)

请将 URL 和文件名替换为应用自己的值。对于允许的、无需代理认证的公共文件下载,HTTP 代理列表可以为代理 URL 提供候选端点。这个专用的 urllib 打开器通过 HTTP 代理访问 HTTPS 目标,并使用常规的证书校验。它不会安装全局打开器;如需认证,则要采用其支持的相关配置。

copyfileobj 按块复制。退出文件上下文会关闭文件,并在 os.replace 安装最终文件名之前刷新已缓冲的写入。

如果请求或复制抛出异常,重命名会被跳过。按照清理策略,可能留下部分文件;在这种情况下,该流程不会改动已有的最终文件。成功时,替换操作可以覆盖该最终文件,因此请有意选择相应策略。

并发任务应使用唯一的临时文件名。各自独立的打开器对象并不能保护共用同一 .part 路径的任务。

20 秒的设置限制的是受支持的套接字操作,而不是总下载时间。整个任务的截止期限需要在应用中另行处理。传输完成也与校验已下载的文件是分开的。

相关文章