Python requests批量下载文件:多线程提速与失败重试
讲解用requests循环批量下载文件,配合线程池并发提速,自动跳过已存在文件、记录失败清单,适合大批量图片/文档素材下载。
场景痛点
单个文件下载慢,几百个文件排队串行下更慢,等半小时都不一定跑完。批量下载要解决三个问题:并发提速、重复跑不重复下、失败了能记录下来回头补。用Python线程池加一个简单的跳过逻辑,几百个文件几分钟下完,失败清单一目了然。
用到的库
pip install requests beautifulsoup4 lxml
完整代码
# 导入库
import os
import time
import requests
from concurrent.futures import ThreadPoolExecutor, as_completed
def download_one(item):
"""下载单个文件,item是 (url, 保存文件名) 元组"""
url, filename = item
save_dir = "downloads"
os.makedirs(save_dir, exist_ok=True)
save_path = os.path.join(save_dir, filename)
# 已经存在且大于0字节就跳过,断点续传
if os.path.exists(save_path) and os.path.getsize(save_path) > 0:
return ("skip", filename, 0)
try:
with requests.get(url, stream=True, timeout=30) as resp:
resp.raise_for_status()
with open(save_path, "wb") as f:
for chunk in resp.iter_content(8192):
if chunk:
f.write(chunk)
size = os.path.getsize(save_path)
return ("ok", filename, size)
except Exception as e:
return ("fail", filename, str(e))
def main():
# 准备要下载的URL列表,实际项目里可能是从Excel读进来的
tasks = []
for i in range(1, 6):
tasks.append((f"https://httpbin.org/image/png?n={i}", f"pic_{i}.png"))
# 用线程池并发下载,最多同时5个线程
results = {"ok": [], "fail": [], "skip": []}
with ThreadPoolExecutor(max_workers=5) as pool:
futures = [pool.submit(download_one, t) for t in tasks]
for fut in as_completed(futures):
status, name, info = fut.result()
results[status].append((name, info))
print(f"[{status}] {name}")
# 汇总报告
print("=" * 40)
print(f"成功:{len(results['ok'])} 个")
print(f"跳过:{len(results['skip'])} 个")
print(f"失败:{len(results['fail'])} 个")
if results["fail"]:
print("失败清单:")
for name, err in results["fail"]:
print(" -", name, err)
if __name__ == "__main__":
main()
代码讲解
ThreadPoolExecutor(max_workers=5)是Python标准库里的线程池,5个线程同时下载,比单线程快好几倍。IO密集型任务(网络下载)用线程就够,不需要多进程。pool.submit(下载函数, 参数)提交一个任务,返回Future对象;as_completed按完成顺序拿到结果。- 下载前先判断文件是否已存在,存在就跳过,这样脚本中断后再跑能自动续传,不用重头再来。
- 每个任务返回
(状态, 文件名, 信息)三元组,最后统一汇总,成功、跳过、失败分开统计。 - 失败的文件名列出来,方便单独重试,不会因为某一个文件失败拖垮整个批次。
运行结果
第一次运行会看到5个 [ok] 输出,downloads目录下有5张图;第二次运行因为文件已存在,全部变成 [skip]。如果把某个URL改错,对应那条会出现在失败清单里。
注意事项
- 并发数不要开太大,5到10个比较稳妥,开太高容易把对方服务器打爆,也可能触发自己这边的网络限流。
- 文件名要去重并清洗,不同URL可能存到同一个文件名互相覆盖。
- 下载间隔适当加一点
time.sleep(0.5)更礼貌,尤其下载第三方站点时。 - 线程池里不要共享可变全局变量,结果通过返回值传递最安全。

更新时间:2026-09-14 20:50:21
上一篇:Python requests处理Cookie:手动携带与本地保存