多线程下载图片提速关键在url可靠性、content-type校验与线程安全写入:需检查status_code==200且'image/' in headers['content-type'],用唯一文件名(如md5(url)[:8]+扩展名),避免共享文件句柄,线程数建议10~16并复用session连接池。

多线程下载图片确实能显著提速,但直接套用通用多线程模板容易出错——关键不在“开几个线程”,而在于图片 URL 的可靠性、响应体格式判断、以及并发写入时的文件系统竞争。
requests.get() 下载图片时为什么返回空或乱码?
常见错误是没检查 response.status_code 或忽略 Content-Type 头。有些图片链接实际返回 302 重定向、403 权限拒绝,甚至 HTML 错误页(比如反爬拦截页),但 response.content 仍非空,直接写入就会生成损坏文件。
- 务必在写入前加判断:
if response.status_code == 200 and 'image/' in response.headers.get('Content-Type', '') - 对
status_code != 200的响应,建议记录 URL 和状态码,而不是静默跳过 - 部分 CDN 图片会校验
Referer或User-Agent,不带这些 header 可能返回 403
用 ThreadPoolExecutor 下载图片时如何避免文件覆盖或写入错位?
每个线程独立写文件是最安全的做法:不要让多个线程往同一个文件句柄写,也不要依赖 seek() 定位——图片是完整二进制 blob,不是可分块的大文件,Range 请求在这里不适用。
- 为每张图片生成唯一文件名,例如用
hashlib.md5(url.encode()).hexdigest()[:8]+ 扩展名 - 扩展名不能只靠 URL 后缀,应从
response.headers.get('Content-Type')推断:'image/jpeg'→.jpg,'image/webp'→.webp - 写入时用
open(path, 'wb'),不要用a+或r+b模式
线程数设成多少才合适?
不是越多越好。实际吞吐受目标服务器并发限制、本地 DNS 解析速度、TCP 连接池复用效率共同影响。盲目设 max_workers=50 往往导致大量超时或连接被重置。
- 起始建议设为
10~16;若大量请求卡在Connecting状态,说明 DNS 或 TCP 握手成瓶颈 - 配合
requests.adapters.HTTPAdapter(pool_connections=20, pool_maxsize=20)提升连接复用率 - 加
time.sleep(0.05)在提交任务间隙,可缓解瞬时 DNS 查询压力(尤其批量子域名图片)
真正卡住下载速度的,往往不是线程数,而是没处理好重定向链、没复用 session、或者把 jpg 当 png 写入导致后续解析失败——这些细节比并发数更影响最终成功率。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











