很多网站资源直接用 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);
}
}
})();
打开目标网站
按 F12
进入 Console
粘贴对应代码
回车执行
看控制台输出的 status 和 size
文件会自动下载到浏览器默认下载目录
说明下载失败,可能是:
403
404
302
AccessDenied
Not Found
查看方法:
cat 文件名
因为 curl 默认没有浏览器环境,可能缺少:
Referer
Origin
User-Agent
Sec-Fetch-*
而在网页 Console 执行 fetch(),请求是在浏览器页面环境中发出的,成功率更高。
可能图片是 CSS 背景图。用这个查看:
performance.getEntriesByType("resource")
.filter(r => /\.(png|jpe?g|webp|gif|svg)(\?|$)/i.test(r.name))
.forEach(r => console.log(r.name));
刷新页面后再看:
F12 → Network → Font → F5刷新
或者执行:
performance.getEntriesByType("resource")
.filter(r => /\.(ttf|woff2?|otf)(\?|$)/i.test(r.name))
.forEach(r => console.log(r.name));
请只下载自己有权限使用的网站资源。字体、图片可能有版权限制,商用前需要确认授权。