直接用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 被拦截。
SkillSub Pro - Python 题解与代码注释双功能技能功能概述SkillSub Pro - Python 题解与代码注释双功能技能是一项面向实际任务的技能,主要用于SkillSub Pro 是一个 Python 题解生成与代码注释的 双功能合体技能 ,专为学生、算法学习者和开发者设计;✅ 一个技能,两种用途 :;核心要点📝 题解模式 :输入题目/题号,自动生成完整 Python 题解(含详细注释、解题思路、复杂度分析);💬 注释模式 :输入 Python 代码,自动添加详细中。它将相关步骤、
- 初始化 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 握手开销。
立即学习“Python免费学习笔记(深入)”;
- 从
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 就能让整批任务慢十倍。

















