在线工具
Facebook 素材库下载
把 Facebook Ad Library 广告素材库里的图片和视频一次性抓出来,打包成 ZIP 下载。免费,无需注册。
Facebook 广告素材库(Ad Library)里能看到所有正在投放的广告创意,是做竞品研究最直接的资料来源, 但官方只能一张一张右键另存,几十条广告翻下来非常费时。 这个工具把这一步批量化:在广告库页面点一下书签,素材直链自动收集好, 回到本页粘贴、勾选,一次性打包下载。
⚖️ 使用前请知悉
素材版权归各自广告主所有。本工具只是把公开广告库里你已经能看到的内容批量保存下来, 仅供学习与竞品创意研究参考,请勿直接商用或二次投放。
本站为独立第三方服务平台,与 Meta Platforms, Inc. 及 Facebook 无任何隶属、赞助或授权关系。
素材版权归各自广告主所有。本工具只是把公开广告库里你已经能看到的内容批量保存下来, 仅供学习与竞品创意研究参考,请勿直接商用或二次投放。
本站为独立第三方服务平台,与 Meta Platforms, Inc. 及 Facebook 无任何隶属、赞助或授权关系。
怎么用
装一次书签
把下面这个按钮拖到浏览器书签栏。只需装一次,之后一直能用。
去广告库抓
打开广告库搜到想要的主页,先往下滚几屏把广告加载出来,再点书签栏那个按钮。
回来粘贴
链接会自动复制到剪贴板,回到本页粘进下面的框,预览、勾选、打包下载。
📥 抓取 FB 素材
← 拖我到书签栏(直接点没用)
拖不了 / 点了没反应?用控制台运行(Firefox 建议直接用这条)
Facebook 页面的 CSP 策略在 Firefox 上会拦掉书签脚本,Chrome 大多放行。被拦了就走这条:
在广告库页面按 F12
打开控制台,粘贴下面的代码回车。
Chrome 首次粘贴会拦一下,按提示在控制台里手动输入 allow pasting 再粘即可。
/**
* Facebook 广告库素材采集脚本。
*
* 用法有两条路(页面上平级展示):
* 1. 拖到书签栏,在广告库页面点一下;
* 2. 复制全文,在广告库页面 F12 → Console 粘贴回车。
*
* 这份是唯一的源码,不做压缩、不进构建。Blade 里用 rawurlencode() 直接拼成
* javascript: URI —— 编码后换行会被保留,浏览器照跑,所以没必要 minify,
* 也就不会出现「压缩版和源码漂移」的问题。见 resources/views/tools/fb-ads.blade.php
*
* ⚠️ 这个脚本只读它所在页面已经渲染出来的 DOM,不发任何请求、不碰任何接口、
* 不读 cookie。它做的事等价于你自己把每张图右键另存,只是省掉手工。
* 不要往里加任何「主动抓取」的逻辑。
*/
(function () {
'use strict';
var HOSTS = ['.fbcdn.net', '.cdninstagram.com'];
/* 头像和 UI 图标的过滤阈值。广告库里主页头像是 40–60px,素材图普遍 500px 以上,
这条线分得很干净。用渲染尺寸而不是 URL 路径特征 —— 路径段(t39.30808-1 之类)
Facebook 说改就改,图片多大是改不掉的。 */
var MIN_PX = 200;
/* key -> {url, score},同一素材的多个尺寸变体只留最大的那个 */
var found = Object.create(null);
function onCdn(url) {
try {
var h = new URL(url, location.href).hostname.toLowerCase();
for (var i = 0; i < HOSTS.length; i++) {
if (h.endsWith(HOSTS[i])) return true;
}
} catch (e) {}
return false;
}
/**
* 同一张素材会以多种尺寸出现(srcset、缩略图、灯箱大图)。
* fbcdn 路径里那串 `数字_数字_数字_n.jpg` 是素材本身的标识,尺寸变体之间是一样的,
* 拿它当去重键就能把变体折叠到一起。取不到就退回整条 URL(宁可多留也不错杀)。
*/
function assetKey(url) {
try {
var path = new URL(url, location.href).pathname;
var m = path.match(/(\d{6,}_\d{6,}_\d{6,})/);
if (m) return m[1];
} catch (e) {}
return url;
}
function offer(url, score) {
if (!url || !onCdn(url)) return;
if (/\.svg(\?|$)/i.test(url)) return; // 图标,不是素材
var k = assetKey(url);
if (!found[k] || score > found[k].score) {
found[k] = { url: url, score: score || 0 };
}
}
/* srcset: "url 640w, url 1280w" 或 "url 1x, url 2x"。
w 直接当分数;x 粗略折算成 1000 的倍数,只用来比大小,不需要准。 */
function fromSrcset(ss) {
return String(ss).split(',').map(function (part) {
var bits = part.trim().split(/\s+/);
var d = bits[1] || '';
var score = 0;
if (/w$/.test(d)) score = parseInt(d, 10) || 0;
else if (/x$/.test(d)) score = (parseFloat(d) || 1) * 1000;
return { url: bits[0], score: score };
});
}
/* ── 第一遍:扫 DOM 里的 img / video ───────────────────────── */
Array.prototype.forEach.call(document.querySelectorAll('img'), function (img) {
var w = img.naturalWidth || img.width || 0;
var h = img.naturalHeight || img.height || 0;
if (w < MIN_PX || h < MIN_PX) return;
offer(img.currentSrc || img.src, w);
if (img.srcset) {
fromSrcset(img.srcset).forEach(function (c) { offer(c.url, c.score); });
}
});
Array.prototype.forEach.call(document.querySelectorAll('video'), function (v) {
/* 封面基本总能拿到 */
offer(v.poster, MIN_PX);
/* ⚠️ 广告库的视频走 MSE,v.src 绝大多数情况是 blob:,下不了。
真直链在下面第二遍从页面内嵌 JSON 里捞。 */
if (v.src && v.src.indexOf('blob:') !== 0) offer(v.src, 9999);
Array.prototype.forEach.call(v.querySelectorAll('source'), function (s) {
if (s.src && s.src.indexOf('blob:') !== 0) offer(s.src, 9999);
});
});
/* ── 第二遍:从页面自带的 JSON 里捞视频直链 ──────────────────
Facebook 把 video_hd_url / video_sd_url 直接嵌在页面的 JSON 负载里。
这仍然只是读当前页面已有的内容,没有发任何请求。
⚠️ 这是全脚本最脆的一环,Facebook 一改数据结构就失效 —— 失效时视频会退化成
只有封面,页面 FAQ 里对此有说明,不要假装它一定能拿到。 */
var VIDEO_KEY = /"(?:video_hd_url|video_sd_url|playable_url(?:_quality_hd)?)"\s*:\s*"([^"]+)"/g;
Array.prototype.forEach.call(
document.querySelectorAll('script[type="application/json"]'),
function (s) {
var text = s.textContent || '';
var m;
VIDEO_KEY.lastIndex = 0;
while ((m = VIDEO_KEY.exec(text)) !== null) {
/* JSON 里的 URL 是转义过的(\/ 和 % 之类),解一次 */
var url = m[1].replace(/\\\//g, '/');
try { url = JSON.parse('"' + m[1] + '"'); } catch (e) {}
offer(url, 9999);
}
}
);
/* ── 输出 ──────────────────────────────────────────────── */
var urls = Object.keys(found).map(function (k) { return found[k].url; });
if (urls.length === 0) {
alert(
'没有找到素材。\n\n' +
'可能的原因:\n' +
'· 页面还没加载完 —— 先往下滚几屏,广告是懒加载的,没滚到的抓不到\n' +
'· 当前不在 Facebook 广告库的搜索结果页\n' +
'· Facebook 改版了,脚本需要更新'
);
return;
}
/* 首行带上当前广告库页面的地址。工具页会把它单独拆出来提交,
用于站点侧的合规审核(谁在搜什么素材)—— 工具页上对此有明示。
只带地址本身,不带 cookie、不带任何账号信息。 */
var text = '#source=' + location.href + '\n' + urls.join('\n');
var done = '已抓到 ' + urls.length + ' 个素材,链接已复制到剪贴板。\n\n回到工具页粘贴即可。';
function fallback() {
/* 剪贴板被拒(常见于控制台粘贴运行,没有用户手势)——
弹个框让用户自己 Ctrl+A / Ctrl+C,别让他白抓一趟 */
window.prompt('已抓到 ' + urls.length + ' 个素材。按 Ctrl+A 全选、Ctrl+C 复制:', text);
}
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(text).then(function () { alert(done); }, fallback);
} else {
fallback();
}
})();
常见问题
为什么要装书签,不能直接输入主页链接自动抓?
因为 Facebook 对服务器发来的请求有反爬校验,直接从我们的服务器请求广告库会被拒。
要绕过它就得去伪装成真人浏览器 —— 我们不做这种事。
书签脚本跑在你自己的浏览器、你自己的登录会话里,读的是你眼前已经加载出来的页面内容, 本质上等同于你自己把每张图右键另存,只是把这个动作批量化了。这条路更慢一点,但是干净的。
书签脚本跑在你自己的浏览器、你自己的登录会话里,读的是你眼前已经加载出来的页面内容, 本质上等同于你自己把每张图右键另存,只是把这个动作批量化了。这条路更慢一点,但是干净的。
会不会导致我的账号被封?
脚本不发送任何请求,不调接口、不读 cookie、不模拟点击,只读取当前页面里已经渲染出来的图片地址。
从 Facebook 的角度看,你就是打开广告库看了几屏而已,和平时浏览没有区别。
为什么视频只下到了封面图?
广告库的视频用的是流式播放(MSE),播放器里拿到的是临时的内存地址,不是可下载的文件链接。
脚本会尽量从页面自带的数据里找视频真链,但 Facebook 改版后这部分随时可能失效
—— 那种情况下视频就只剩封面图。图片素材不受影响。
抓不到 / 抓到的数量比看到的少?
广告库是滚动懒加载的,只有已经滚动到、真正渲染出来的广告才抓得到。
想要更多就多往下滚几屏再点书签。
如果一个都抓不到,脚本会直接弹窗告诉你,而不是悄悄返回空 —— 那通常意味着页面还没加载完, 或者 Facebook 改版了、脚本需要更新。
如果一个都抓不到,脚本会直接弹窗告诉你,而不是悄悄返回空 —— 那通常意味着页面还没加载完, 或者 Facebook 改版了、脚本需要更新。
提示「链接已过期」怎么办?
fbcdn 的素材直链带有时效签名,隔太久(通常是几小时到一天)就会失效。
回到广告库页面重新点一次书签,拿一批新的链接即可。
下载到的素材可以直接拿去投放吗?
不建议,也不合规。广告素材的著作权属于原广告主,直接搬运投放既可能侵权,
也很容易被平台判定为重复素材而影响审核。
这个工具的定位是竞品创意研究 —— 看别人怎么做钩子、怎么排版、什么调性有效,
然后做自己的东西。
也在找别的工具?试试
2FA 验证码在线生成
—— 粘贴密钥即可获取两步验证码,同样免费、无需注册。