可用requests流式下载配合tqdm实现带进度条的下载,需设stream=True、读取Content-Length、分块迭代写入;未返回长度时total设为None,超时和状态码检查可避免卡顿。

直接用 requests 流式下载 + tqdm 就能实现,不需要自己算百分比或监听事件。
为什么不能直接用 requests.get(url).content?
因为这种方式会把整个响应体一次性加载进内存,文件大时容易 OOM,且无法获取实时下载量来更新进度条。
必须启用流式响应,并手动分块读取:
- 设置
stream=True参数 - 从
r.headers.get("content-length")获取总大小(注意:有些服务不返回该头,需降级处理) - 用
r.iter_content(chunk_size=8192)分块读取,每读一块就更新一次进度条
tqdm 初始化时如何正确传入 total?
如果服务器返回了 Content-Length,就直接用它;否则设为 None,tqdm 会显示「未知剩余时间」的动态进度条(带速率估算)。
立即学习“Python免费学习笔记(深入)”;
示例关键逻辑:
import requests
from tqdm import tqdm
r = requests.get(url, stream=True)
total = int(r.headers.get("content-length", 0))
with open("out.zip", "wb") as f:
for chunk in tqdm(r.iter_content(chunk_size=8192), total=total//8192 if total else None):
if chunk:
f.write(chunk)
注意:total 单位要和 chunk_size 对齐,否则进度条不准;除不尽时 tqdm 会自动向下取整,影响不大。
遇到重定向或认证失败时进度条卡住怎么办?
常见现象是 tqdm 显示 0% 并长时间不动——本质是 requests 在底层阻塞等待响应,但没抛异常。
- 务必加
timeout=(3, 30):第一个数字是连接超时,第二个是读取超时 - 检查
r.status_code是否为 200 或 3xx;3xx 重定向默认会被requests自动跟随,但某些场景需手动处理 - 若需认证,确保
auth或headers={"Authorization": ...}已正确传入,否则可能返回 401 且content-length为 0,导致tqdm总长为 0
真正难处理的是没有 Content-Length 且无法预估大小的流(比如动态生成的 CSV),这时只能靠速率(rate)和已写入字节数做粗略提示,别强求百分比。


















