字体、图片、万能资源下载整理

一、核心原理

很多网站资源直接用 curl 下载会返回:

403 Forbidden
302 Found
Not Found

原因通常是 CDN / OSS 开启了防盗链,需要浏览器环境里的:

Referer
Origin
User-Agent
Sec-Fetch-*

所以更稳的方法是:

在目标网站页面里打开 F12 → Console,用 fetch() 下载资源。

只要浏览器能正常加载,通常就可以通过 Console 下载。


二、下载字体文件

适用于:

.ttf
.woff
.woff2
.otf

单个字体下载代码

url 换成字体地址:

(async () => {
const url = "这里换成字体URL";
const res = await fetch(url);
const blob = await res.blob();
console.log("status:", res.status);
console.log("size:", blob.size);
if (!res.ok || blob.size < 100) {
console.warn("下载失败,可能是 403 / 404 文本:", res.status, blob.size);
return;
}
const a = document.createElement("a");
a.href = URL.createObjectURL(blob);
a.download = url.split("/").pop().split("?")[0] || "font.ttf";
document.body.appendChild(a);
a.click();
a.remove();
URL.revokeObjectURL(a.href);
})();

示例

(async () => {
const url = "https://omo-oss-file1.thefastfile.com/portal-saas/new2022111121414197270/cms/file/2e9a3316-2288-46d1-bf4f-35e31c5ca6cd.ttf";
const res = await fetch(url);
const blob = await res.blob();
console.log("status:", res.status);
console.log("size:", blob.size);
const a = document.createElement("a");
a.href = URL.createObjectURL(blob);
a.download = "2e9a3316-2288-46d1-bf4f-35e31c5ca6cd.ttf";
document.body.appendChild(a);
a.click();
a.remove();
})();

判断是否成功

几十 KB / 几百 KB / 几 MB = 成功
十几 B / 几十 B = 失败,下载到的是 403 / 404 / 302 文本


三、批量下载多个字体

如果已经知道多个字体文件名,可以一次性全部下载。

示例

(async () => {
const fonts = [
"66e1a992-2b96-4077-8a1a-9d25f957de46.ttf",
"2e9a3316-2288-46d1-bf4f-35e31c5ca6cd.ttf",
"daec0bd2-9981-4e42-a77f-3dba074edaf1.ttf"
];
const base = "https://omo-oss-file1.thefastfile.com/portal-saas/new2022111121414197270/cms/file/";
for (const file of fonts) {
try {
const res = await fetch(base + file);
const blob = await res.blob();
console.log(file, res.status, blob.size);
if (!res.ok || blob.size < 100) {
console.warn("跳过:", file);
continue;
}
const a = document.createElement("a");
a.href = URL.createObjectURL(blob);
a.download = file;
document.body.appendChild(a);
a.click();
a.remove();
await new Promise(r => setTimeout(r, 500));
} catch (e) {
console.error(file, e);
}
}
})();

自动下载当前页面所有字体(推荐)

无需知道字体文件名。

(async () => {
const fonts = performance
.getEntriesByType("resource")
.filter(r => /\.(ttf|woff2?|otf)(\?|$)/i.test(r.name))
.map(r => r.name);
console.table(fonts);
for (const url of fonts) {
const res = await fetch(url);
const blob = await res.blob();
if (!res.ok || blob.size < 100) continue;
const file = decodeURIComponent(
url.split("/").pop().split("?")[0]
);
const a = document.createElement("a");
a.href = URL.createObjectURL(blob);
a.download = file;
document.body.appendChild(a);
a.click();
a.remove();
await new Promise(r => setTimeout(r, 500));
}
})();

三、下载图片资源

适用于:

.png
.jpg
.jpeg
.webp
.gif
.svg

单张图片下载代码

(async () => {
const url = "这里换成图片URL";
const res = await fetch(url);
const blob = await res.blob();
console.log("status:", res.status);
console.log("size:", blob.size);
if (!res.ok || blob.size < 100) {
console.warn("下载失败:", res.status, blob.size);
return;
}
const a = document.createElement("a");
a.href = URL.createObjectURL(blob);
a.download = url.split("/").pop().split("?")[0] || "image.png";
document.body.appendChild(a);
a.click();
a.remove();
URL.revokeObjectURL(a.href);
})();

示例

(async () => {
const url = "https://omo-oss-image.thefastimg.com/portal-saas/new2023031513410260958/cms/image/d3336b1a-0414-48be-a2c7-9ba3236a2820.png";
const res = await fetch(url);
const blob = await res.blob();
console.log("status:", res.status);
console.log("size:", blob.size);
const a = document.createElement("a");
a.href = URL.createObjectURL(blob);
a.download = "d3336b1a-0414-48be-a2c7-9ba3236a2820.png";
document.body.appendChild(a);
a.click();
a.remove();
})();

四、批量下载当前页面所有图片

(async () => {
const imgs = [...document.images];
console.log("图片数量:", imgs.length);
for (const img of imgs) {
try {
const url = img.currentSrc || img.src;
if (!url) continue;
const res = await fetch(url);
const blob = await res.blob();
if (!res.ok || blob.size < 100) {
console.warn("跳过失败图片:", res.status, blob.size, url);
continue;
}
const a = document.createElement("a");
a.href = URL.createObjectURL(blob);
a.download = url.split("/").pop().split("?")[0] || "image";
document.body.appendChild(a);
a.click();
a.remove();
console.log("下载成功:", url, blob.size);
await new Promise(r => setTimeout(r, 300));
} catch (e) {
console.warn("下载失败:", img.src, e);
}
}
})();

五、获取页面已加载的字体 / 图片 / 资源地址

查看页面加载过的字体

performance.getEntriesByType("resource")
.filter(r => /\.(ttf|woff2?|otf)(\?|$)/i.test(r.name))
.forEach(r => console.log(r.name));

查看页面加载过的图片

performance.getEntriesByType("resource")
.filter(r => /\.(png|jpe?g|webp|gif|svg)(\?|$)/i.test(r.name))
.forEach(r => console.log(r.name));

查看所有资源

performance.getEntriesByType("resource")
.forEach(r => console.log(r.name));

六、万能资源下载器

支持自动扫描并下载当前页面资源:

图片:png / jpg / jpeg / webp / gif / svg
字体:ttf / woff / woff2 / otf
视频:mp4
音频:mp3
文档:pdf

代码

(async () => {
const exts = /\.(png|jpe?g|webp|gif|svg|ttf|woff2?|otf|mp4|mp3|pdf)(\?|$)/i;
const urls = new Set();
document.querySelectorAll("img, video, audio, source, link, script").forEach(el => {
["src", "href"].forEach(attr => {
const v = el.getAttribute(attr);
if (v) urls.add(new URL(v, location.href).href);
});
});
performance.getEntriesByType("resource").forEach(r => {
if (exts.test(r.name)) urls.add(r.name);
});
const list = [...urls].filter(url => exts.test(url));
console.log("找到资源数量:", list.length);
console.table(list);
for (const url of list) {
try {
const res = await fetch(url);
const blob = await res.blob();
if (!res.ok || blob.size < 100) {
console.warn("跳过失败资源:", res.status, blob.size, url);
continue;
}
const filename = decodeURIComponent(
url.split("/").pop().split("?")[0] || "download"
);
const a = document.createElement("a");
a.href = URL.createObjectURL(blob);
a.download = filename;
document.body.appendChild(a);
a.click();
a.remove();
console.log("下载成功:", filename, blob.size);
await new Promise(r => setTimeout(r, 500));
} catch (e) {
console.warn("下载失败:", url, e);
}
}
})();

七、使用步骤

  1. 打开目标网站

  2. F12

  3. 进入 Console

  4. 粘贴对应代码

  5. 回车执行

  6. 看控制台输出的 statussize

  7. 文件会自动下载到浏览器默认下载目录


八、常见问题

1. 下载下来只有几十字节

说明下载失败,可能是:

403
404
302
AccessDenied
Not Found

查看方法:

cat 文件名

2. curl 为什么不行?

因为 curl 默认没有浏览器环境,可能缺少:

Referer
Origin
User-Agent
Sec-Fetch-*

而在网页 Console 执行 fetch(),请求是在浏览器页面环境中发出的,成功率更高。

3. Network 里看不到图片

可能图片是 CSS 背景图。用这个查看:

performance.getEntriesByType("resource")
.filter(r => /\.(png|jpe?g|webp|gif|svg)(\?|$)/i.test(r.name))
.forEach(r => console.log(r.name));

4. Network 里看不到字体

刷新页面后再看:

F12 → Network → Font → F5刷新

或者执行:

performance.getEntriesByType("resource")
.filter(r => /\.(ttf|woff2?|otf)(\?|$)/i.test(r.name))
.forEach(r => console.log(r.name));

九、注意

请只下载自己有权限使用的网站资源。字体、图片可能有版权限制,商用前需要确认授权。