用requests.get()获取二进制图片必须用.content而非.text或.decode(),以wb模式写入文件,并校验status_code、Content-Type及JPG文件头\xff\xd8。

用 requests.get() 获取二进制流后直接写入文件
核心就是别用 .text 或 .json(),必须用 .content——它返回原始 bytes,和 JPG 文件格式完全匹配。
常见错误是误用 response.text,结果写出来的是乱码或空文件;还有的人在写入前加了 .decode(),这会直接破坏二进制结构。
- 确保请求头里没强制要求 JSON 或 HTML:
headers={'Accept': 'image/jpeg'}可选,但不是必须 - 检查
response.status_code == 200,且response.headers.get('content-type')包含image/jpeg或image/jpg - 用
open(..., 'wb')模式打开文件,必须是wb,不是w或ab
import requests
url = "https://example.com/photo.jpg"
res = requests.get(url)
if res.status_code == 200:
with open("output.jpg", "wb") as f:
f.write(res.content)
遇到 UnicodeDecodeError 或文件打不开怎么办
这基本等于你把 bytes 当成字符串处理了。比如写了 f.write(res.text),或者用 str(res.content) 再写入——JPG 不是文本,不能编码解码。
另一个隐蔽坑:某些网站返回的是重定向后的响应,但 requests 默认跟随重定向,res.content 看似正常,实际是 HTML(比如登录页、反爬提示页),写出来是 JPG 后缀但内容是 HTML,双击打不开。
立即学习“Python免费学习笔记(深入)”;
- 加
allow_redirects=False检查是否被重定向:requests.get(url, allow_redirects=False) - 用
file命令(Linux/macOS)或xxd -l 16 output.jpg查看文件头:合法 JPG 应以ff d8 ff开头 - 如果服务器返回压缩内容(
content-encoding: gzip),requests默认自动解压,.content仍是原始 JPG 二进制,不用额外处理
不依赖 requests:用 urllib.request 直接读取并保存
有些环境禁用第三方库,urllib 是标准库替代方案。注意它不自动处理重定向和编码,行为更“裸”,反而容易排查问题。
-
urlopen()返回的对象有.read()方法,结果也是bytes - 同样必须用
open(..., 'wb'),不能用text模式 - 若 URL 含中文或特殊字符,先用
urllib.parse.quote()编码
from urllib.request import urlopen
url = "https://example.com/photo.jpg"
with urlopen(url) as res:
data = res.read()
with open("output.jpg", "wb") as f:
f.write(data)
保存前想校验是否真是 JPG 文件
光看后缀没用,尤其面对反爬返回的假 JPG。最轻量的方式是检查文件头(magic bytes)。
不需要引入 PIL 或 OpenCV,几行代码就能筛掉大部分伪装响应。
- JPG 文件开头 2 字节固定为
b'\xff\xd8',结尾通常以b'\xff\xd9'结束(非绝对,但开头必对) - 用
res.content[:2] == b'\xff\xd8'快速判断,不匹配就跳过保存 - 如果
len(res.content) ,基本可判定为空响应或错误页,直接丢弃
复杂点在于有些 CDN 会返回带额外 header 的 JPG(如 EXIF 数据丰富),但开头字节不变——所以只校验开头足够可靠。真正要解析图像元数据或缩略图,才需要 Pillow 的 Image.open(),那属于后续处理,不是保存环节该操心的。


















