You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python使用requests.get下载图片未完全加载致0字节、空白异常问题

Python requests 偶发下载图片得到0字节/空白文件问题修复

问题现象

调用requests.get从网站下载图片时,偶发获取不到有效数据:

  • 部分场景下下载得到的文件大小为0字节,无任何有效内容
  • 部分场景下载流程正常走完,但打开后图片为空白

失败案例日志

Remote URL https://gd3.alicdn.com/imgextra/i3/917765107/O1CN01FUj4ea1nb3SEtYlCB_!!917765107.jpg
filename 1657077308/693904.jpg size  0

正常案例日志

Remote URL https://gd1.alicdn.com/imgextra/i1/917765107/O1CN016sR7UO1nb3SNr1Fo2_!!917765107.jpg
filename 1657077186/735590.jpg size  14032

原有问题代码

初始实现逻辑:

# Getting image from remote url
response = requests.get(remote_url, stream=True)
# Get the content of image
imageResponse = response.raw
len(response.content)

复现空白图片问题的测试代码:

remote_url = "https://img.alicdn.com/imgextra/i3/917765107/O1CN01WwxHa81nb3SLAupPq_!!917765107.jpg"
imageResponse = requests.get(remote_url, stream=True)
print(len(imageResponse.content))

问题根因

注意:问题和图片体积大、加载耗时没有直接关系,核心是代码逻辑存在漏洞

  1. 误用stream=True参数:开启流模式后,requests不会在请求返回时自动拉取完整响应体,直接读取response.raw或在内容未加载完成时访问response.content,只会拿到截断的不完整数据
  2. 缺少反爬适配:阿里系CDN默认校验请求头特征,使用requests默认标识、不带Referer的请求有概率被反爬策略拦截,返回空响应或者验证页面内容,存为图片后就会出现0字节或空白问题
  3. 无响应校验逻辑:遇到网络错误、CDN节点故障返回4xx/5xx响应时,没有判断状态码直接读取内容,拿到的本身就不是图片数据
  4. 无超时、重试机制:遇到网络抖动、CDN节点临时响应慢时请求直接中断,没有重试逻辑就会直接触发下载失败

修复方案

核心调整点

  • 普通尺寸图片(单张10MB以内)不要开启stream=True,默认配置下requests会自动完成全量响应体加载后再返回,不会出现内容截断
  • 请求时携带常规浏览器UA和对应站点的Referer头,避免被CDN反爬拦截
  • 配置合理的超时时间,避免请求无限挂起,一般连接超时设3秒、读取超时设10-30秒即可覆盖绝大多数场景
  • 增加自动重试逻辑,针对CDN临时错误、网络波动场景自动重试2-3次,大幅降低偶发失败概率
  • 响应内容校验:先判断状态码是否为200,再校验内容长度是否非0、响应头的Content-Type是否为图片类型,确认是有效图片数据后再写入文件

可直接复用的实现代码

import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry

def download_image(remote_url: str, save_path: str, max_retry: int = 3) -> bool:
    # 初始化请求会话,配置重试策略
    session = requests.Session()
    retry_config = Retry(
        total=max_retry,
        backoff_factor=1,  # 重试间隔按1/2/4秒递增,避免频繁请求触发拦截
        allowed_methods=["GET"],
        status_forcelist=[429, 500, 502, 503, 504]  # 仅对服务端临时错误触发重试
    )
    session.mount("https://", HTTPAdapter(max_retries=retry_config))
    session.mount("http://", HTTPAdapter(max_retries=retry_config))

    try:
        response = session.get(
            remote_url,
            timeout=(3, 20),  # 连接超时3s,读取超时20s
            headers={
                # 模拟常规浏览器请求头,绕过基础反爬
                "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
                "Referer": "https://www.taobao.com/"
            }
        )
        # 状态码校验,非200响应直接抛错
        response.raise_for_status()
        # 空内容校验
        img_content = response.content
        if len(img_content) == 0:
            raise ValueError("Empty response content")
        # 响应类型校验,避免把错误页HTML存成图片
        content_type = response.headers.get("Content-Type", "")
        if not content_type.startswith("image/"):
            raise ValueError(f"Invalid content type: {content_type}, not image")
        
        # 二进制写入本地文件
        with open(save_path, "wb") as f:
            f.write(img_content)
        return True
    except Exception as e:
        print(f"Download image {remote_url} failed: {str(e)}")
        return False
    finally:
        session.close()

超大图下载补充说明

如果需要下载单张几十MB以上的超大图必须开stream=True,不要直接读response.content,需要按固定块大小逐块读取写入文件,下载完成后对比本地文件大小和响应头Content-Length字段值,两者一致才判定为下载成功,否则触发重试。


内容的提问来源于stack exchange,提问作者Sohaib Anwaar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 13:09:17