旧项目使用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
相关产品推荐
相关产品推荐

