requests.get()默认无超时且不校验下载完整性,易卡死或静默失败;应设timeout、HEAD预检、stream分块读取、异常捕获;并发用ThreadPoolExecutor而非asyncio;文件名需清洗+哈希防重;注意请求头与重定向陷阱。

requests.get() 下载单个文件时为啥总卡住或超时
默认 requests.get() 没设超时,遇到网络抖动或服务器响应慢就会一直挂起。更麻烦的是,它默认不校验 Content-Length 和实际接收字节数是否一致,下载中途断了你也未必知道。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 必须加
timeout=(3, 10):第一个数是连接超时(秒),第二个是读取超时(秒),别只写一个数字 - 下载前先 HEAD 请求检查
Content-Length和Content-Type,跳过非图片/静态资源(比如text/html) - 用
stream=True+ 分块读取,避免大文件吃光内存:with open(path, 'wb') as f: for chunk in r.iter_content(chunk_size=8192): f.write(chunk) - 记得捕获
requests.exceptions.Timeout、requests.exceptions.ConnectionError,别让一个失败拖垮整个批量任务
并发下载用 threading 还是 asyncio?requests 本身不支持异步
requests 是同步阻塞库,硬塞进 asyncio.gather() 不会变快,反而可能出错;用 threading 能提效,但线程数太多(>20)容易触发目标站反爬或本地端口耗尽。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 优先用
concurrent.futures.ThreadPoolExecutor控制并发数,设max_workers=5~10更稳妥 - 别用
requests.Session()跨线程复用——它不是线程安全的;每个线程自己建新Session,或改用httpx(支持 sync/async 且 Session 可共享) - 如果真要异步,换
httpx.AsyncClient+asyncio.gather(),但得确保所有依赖也支持 async(比如保存文件要用anyio.Path().write_bytes(),不能直接 open)
批量下载图片时文件名重复、路径非法、MIME 类型错乱
从 URL 提取文件名(比如 url.split('/')[-1])极不可靠:可能没后缀、含查询参数、含中文、甚至路径里有 ../。更糟的是,有些图床返回 Content-Type: image/jpeg,但实际是 WebP;有些返回 application/octet-stream 却是 PNG。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 用
urllib.parse.unquote()解码 URL,再用os.path.basename()提取,最后用re.sub(r'[^a-zA-Z0-9._-]', '_', name)清洗非法字符 - 别信 URL 后缀和响应头的
Content-Type,用python-magic或imghdr.what()检查真实类型(注意imghdr已废弃,推荐magic.from_buffer()) - 生成文件名时统一加哈希前缀(如
f"{hash(url)[:8]}_{clean_name}"),彻底避开重名问题 - 保存前确保目录存在:
os.makedirs(os.path.dirname(path), exist_ok=True)
下载高清图时被 302 重定向到低清地址或登录页
很多图床(如 Pixiv、Unsplash)对未带 Referer / User-Agent 的请求降级返回缩略图,或者直接 302 到登录页;还有的通过 JS 动态加载真实 URL,requests 根本拿不到。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 手动加请求头:
headers={'User-Agent': 'Mozilla/5.0', 'Referer': 'https://example.com/'},Referer 必须和来源页一致 - 检查响应状态码:
r.status_code == 302且'login' in r.headers.get('Location', '')就说明需要鉴权,别盲目跟重定向 - 遇到
Content-Type: text/html却预期是图片时,先打印r.text[:200]看是不是 HTML 登录框或 JS 脚本 - 真要处理 JS 渲染页面,别硬刚 requests —— 换
selenium或playwright,但那是另一层开销了
真正难的不是并发数调多大,而是每个请求都得单独判断响应是否“可信”:状态码、头字段、字节流特征、甚至响应体结构。漏掉一种情况,批量任务就静默污染一堆无效文件。










