直接用aiohttp.clientsession()下载图片会卡住,因未配置连接池限制和超时,易触发服务端限流、本地端口耗尽或dns阻塞,且单个无超时请求会拖垮整个协程队列。

为什么直接用 aiohttp.ClientSession() 下载图片会卡住?
因为默认的 aiohttp.ClientSession() 没配连接池限制,大量并发请求会触发服务端限流、本地端口耗尽或 DNS 解析阻塞。更常见的是,没设 timeout 导致某张图一直挂起,拖垮整个协程队列。
- 必须显式设置
timeout=aiohttp.ClientTimeout(total=30),否则单个失败请求可能无限等待 - 连接池要控制:用
aiohttp.TCPConnector(limit=100, limit_per_host=5)避免对同一域名发起过多连接 - HTTP/1.1 默认复用连接,但某些 CDN(如 Cloudflare)会主动关闭空闲连接,建议加
force_close=False保持复用
如何安全地保存二进制图片并避免文件名冲突?
URL 转文件名不能直接用 url.split('/')[-1] —— 很多图片 URL 不带扩展名(如 https://api.example.com/img?id=123),或含非法字符(?、&、/)。
- 优先从响应头提取:
content_type = resp.headers.get('Content-Type', ''),再映射为.jpg/.png等 - 用
hashlib.md5(url.encode()).hexdigest()[:8]生成稳定短哈希,组合成f"{hash_id}.{ext}" - 写入前加
os.makedirs(os.path.dirname(path), exist_ok=True),避免因目录不存在而报FileNotFoundError
怎么处理 403、404 或重定向导致的下载失败?
aiohttp 默认不自动跟随重定向(allow_redirects=False),而很多图床返回 302 到 CDN 地址;同时,403 常因缺失 User-Agent 被拦截。
- 初始化 session 时设
follow_redirects=True,但注意循环重定向风险,建议配合max_redirects=3 - 所有请求必须带
headers={'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) ...'},否则大量请求会被 403 - 对非 2xx 响应,不要直接
raise_for_status(),而是记录状态码和 URL,留待后续分析
并发数设多少才既快又稳?
没有固定值。它取决于目标服务器抗压能力、本地网络带宽、DNS 解析速度,以及你是否复用 session —— 复用 session 可显著降低 TLS 握手开销。
- 从
limit_per_host=3开始测试,观察平均响应时间和错误率;逐步加到 10–20 再看拐点 - 如果目标是同一个域名(如 all images from
example.com),limit_per_host比全局limit更关键 - 别用
asyncio.gather(*[download(url) for url in urls])—— 这会一次性把几千个 task 扔进事件循环,容易爆内存;改用asyncio.Semaphore控制并发量
真正麻烦的不是写几行 await session.get(),而是得在 timeout、重试、连接复用、磁盘 I/O 缓冲之间反复调参——尤其当你要跑几百个 URL 时,某个没设 limit_per_host 的 connector 就能让整批任务慢十倍。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











