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

旧项目使用urllib下载图片时出现文件损坏问题的技术问询

解决urllib下载图片时得到HTML文件的问题

我之前也踩过这个坑!用urllib直接下载图片时,经常会碰到服务器返回HTML而非预期图片的情况——就像你提到的那个AllSaints链接,下载后打开报错Error interpreting JPEG image file (Not a JPEG file: starts with 0x3c 0x21),本质就是服务器返回了HTML文件(开头的0x3c 0x21对应<!,是HTML文档的起始标记)。下面分享几个实用的解决方法:

1. 先检查响应头的Content-Type

这是最直接的判断方式,图片的Content-Type应该是image/jpeg、image/png这类以image/开头的类型,而HTML是text/html。另外,很多网站会拦截不带浏览器标识的请求,所以一定要给请求加User-Agent头模拟浏览器:

import urllib.request

image_url = "https://images.allsaints.com/products/900/WO053N/2824/WO053N-2824-1.jpg"
# 构造带UA的请求
req = urllib.request.Request(
    image_url,
    headers={"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36"}
)

with urllib.request.urlopen(req) as response:
    content_type = response.getheader("Content-Type")
    # 判断是否为图片类型
    if content_type and content_type.startswith("image/"):
        # 保存图片
        with open("valid_image.jpg", "wb") as f:
            f.write(response.read())
        print("图片下载成功")
    else:
        print(f"非图片资源,Content-Type: {content_type}")
        # 可以选择读取内容查看是啥(比如反爬验证页面)
        html_content = response.read().decode("utf-8")
        print("返回内容片段:", html_content[:200])

2. 用「魔术字节」验证文件有效性

有时候服务器可能返回错误的Content-Type,这时候可以通过文件的**魔术字节(Magic Bytes)**来验证——每种文件格式都有固定的起始字节序列:

  • JPEG: 0xFF 0xD8
  • PNG: 0x89 0x50 0x4E 0x47 0x0D 0x0A 0x1A 0x0A
  • GIF: 0x47 0x49 0x46 0x38 0x37 0x61 或 0x47 0x49 0x46 0x38 0x39 0x61

可以写个小工具函数来验证:

def is_valid_image(file_path):
    # 定义常见图片的魔术字节
    image_magic_bytes = {
        b"\xFF\xD8": "JPEG",
        b"\x89\x50\x4E\x47\x0D\x0A\x1A\x0A": "PNG",
        b"\x47\x49\x46\x38\x37\x61": "GIF",
        b"\x47\x49\x46\x38\x39\x61": "GIF"
    }
    with open(file_path, "rb") as f:
        # 读取前8个字节足够覆盖所有常见图片的起始标识
        file_header = f.read(8)
        for magic_byte, _ in image_magic_bytes.items():
            if file_header.startswith(magic_byte):
                return True
    return False

# 下载后验证
if not is_valid_image("valid_image.jpg"):
    print("下载的文件不是有效图片,可能是HTML或其他格式")
    # 可以删除无效文件
    import os
    os.remove("valid_image.jpg")

3. 检查重定向情况

urllib默认会自动处理重定向,但有时候服务器会把图片请求重定向到HTML页面(比如反爬验证)。可以通过geturl()方法查看最终请求的URL:

with urllib.request.urlopen(req) as response:
    final_url = response.geturl()
    if final_url != image_url:
        print(f"请求发生重定向,最终URL: {final_url}")
        # 如果最终URL不是图片地址,直接放弃下载

总结

把这几个步骤结合起来:

  • 先加合法的请求头(尤其是User-Agent)避免被服务器拦截
  • 下载前检查Content-Type过滤非图片响应
  • 下载后用魔术字节二次验证文件有效性

基本就能解决下载到HTML伪图片的问题了!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 08:28:13