ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

ponytail:用书签工具一键提取网页图片并整理导出

ponytail:用书签工具一键提取网页图片并整理导出 “ponytail”这个项目名听起来像一个很简单的小玩意实际上也确实很小。它是我在连续第三个月被“帮我把这个页面里的图片整理成表格”这种需求轰炸之后写的一个浏览器书签小工具只要点一下收藏栏里的按钮就能把当前网页里的图片地址、图片尺寸、ALT 信息全部提取出来去重、排序、然后一次性复制成 Markdown 或者 JSON。如果你也经常需要从网页里批量收集图片素材、整理竞品页面里的资源清单、或者做设计灵感归档那这个工具的很多设计思路和取舍应该能帮你省下不少时间。1. 一点背景为什么是 ponytail 而不是一个复杂工具1.1 最先被戳中的痛点先说痛点。做前端或者内容运营的同学应该都有过这种经历看到一个参考页面想把它上面的 banner 图、产品图、ICON 全部保存下来。常规操作是什么打开浏览器开发者工具切到 Network 面板按图片类型过滤然后在几十条请求里把 URL 一个一个复制出来。碰到懒加载页面还要把滚动条滚到底截图里的图标和背景图混在一起根本分不清哪张是哪张。运气好十分钟搞定运气不好一下午就没了。更尴尬的是这种需求没有什么技术难度就是纯体力活但真的会让你怀疑人生。在我印象里最夸张的一次是一个活动页里有四十多张图片包含轮播图、背景纹理、角落装饰和社交图标。运营同事给我的需求是“把这些图列一个带名字、带尺寸的清单我拿去跟供应商对素材”。我当时用开发者工具手点了将近一个小时复制到 Excel 之后发现还有七八张是重复的只是路径大小写不一样。那一刻我就在想这种活必须让脚本去干而且要干得比人靠谱。1.2 “马尾辫”这个名字的由来为什么叫 ponytail其实没什么高深的含义。前端页面里的图片资源散落在很多标签里有的是img有的是picturesource有的是元素的 background-image还有的是懒加载插件塞进>(function () { use strict; const results new Map(); function addImg(src, width, height, alt) { if (!src || src.startsWith(data:) || src.startsWith(blob:)) return; const abs new URL(src, location.href).href; if (!results.has(abs)) { results.set(abs, { src: abs, width: width || 0, height: height || 0, alt: alt || }); } } // 1. 处理普通 img兼容懒加载属性 document.querySelectorAll(img).forEach(img { const src img.currentSrc || img.src || img.getAttribute(data-src) || img.getAttribute(data-lazy-src) || img.getAttribute(data-original); addImg(src, img.naturalWidth, img.naturalHeight, img.alt); }); // 2. 处理 picture 下的 source document.querySelectorAll(picture source).forEach(source { if (!source.srcset) return; const first source.srcset.split(,)[0].trim().split( )[0]; addImg(first); }); // 3. 处理 background-image document.querySelectorAll(*).forEach(el { const bg getComputedStyle(el).backgroundImage; if (!bg || bg none) return; const match bg.match(/url\([]?([^)])[]?\)/); if (match) addImg(match[1]); }); // 4. 按像素面积倒序排序 const list [...results.values()].sort((a, b) { return ((b.width || 0) * (b.height || 0)) - ((a.width || 0) * (a.height || 0)); }); // 5. 输出到新窗口 const win window.open(, _blank, width900,height600); if (!win) { alert(浏览器拦截了弹窗请允许当前站点弹出窗口后重试。); return; } const heads list.map(item trtdimg src${item.src} width80/td td${item.width}×${item.height}/td tda href${item.src} target_blank${item.src}/a/td/tr ).join(); win.document.write(htmlheadtitleponytail/title meta charsetutf-8/headbody table border1${heads}/table/body/html); win.document.close(); })();上面代码里最值得说的是两个细节第一个是addImg函数里对data:和blob:开头的地址直接过滤。这类图片要么是内联的 base64要么是临时对象 URL它们既不方便复制也不方便转存收集出来没意义。第二个是背景图查询用的getComputedStyle它能拿到元素最终计算出来的背景图不会漏掉写在样式表里的图但代价是要遍历所有元素页面很大的时候会稍稍有点卡。这些都是用了几次之后踩到坑才慢慢调整出来的。4. 在真实项目里怎么用它跑通需求4.1 场景运营要竞品页的图列表先说一个我实际经历过的场景。运营同事拿到一个活动页链接要求“把里面的素材图整理成一个表格列清楚每张图是什么、多大、对应页面哪个位置”。以前这个是设计师或者前端来做一张一张截图标注非常拖沓。我用 ponytail 帮助她在几秒内打开结果窗口然后用“只看宽高不小于 200px 的图”来过滤掉图标和装饰点再把结果复制成 Markdown粘贴进文档里。她唯一需要多做的是图一多的时候还要根据文件名和尺寸去判断“哪张图对应页面里的哪个位置”。我会把 ALT 和文件名一起导出ALT 往往能从代码层面反应该图在页面里的作用比如 “banner-main” 就是主视觉“icon-arrow” 就是箭头图标。这样一来需求交接就变得非常顺利她拿到清单后稍微改一下备注就能直接发出去。这里有一个非常重要的经验不要一开始就把所有图片不分青红皂白地全导出来。你先用筛选条件把大图拎出来再看一眼缩略图和文件名基本就能抓住页面主要视觉。小图标、背景纹理、重复装饰图属于噪音留在结果里只会干扰阅读。在结果窗口里加“隐藏小于 200px 的图”这个默认开关其实就是基于这个实战经验做的。4.2 场景前端要快速挑选素材另一个场景是前端开发。之前做官网改版我需要把一个旧页面里的 30 多张图片资源全部迁移到新的图片服务上。常规做法是看代码一个个找 URL再逐个下载上传改完路径还要测试新环境下的加载效果。很繁琐对吧有了 ponytail 之后我先在旧页面点一下按钮导出 JSON然后写一条简单的 node 脚本把这些 URL 批量下载到本地再调用图床接口传上去。整个过程只花几分钟。这里面有个隐藏技巧导出的 JSON 里保留了图片的原始像素尺寸。传到新 CDN 之后如果 CDN 支持裁剪参数你还可以按尺寸自动生成适配不同屏幕的宽高。比如一张原始 1920×1080 的 banner 图用 JSON 里的尺寸信息就能精准确定是否要做移动端裁剪。这比人工打开每张图片看尺寸要准确得多。如果你不想写 node 脚本直接在结果窗口里点“下载全部”让浏览器以附件方式逐个下载也能应急。要注意的是批量下载多个文件会触发浏览器的“允许下载多个文件”提示我建议在弹窗里保持允许状态一次性下载完然后再恢复默认设置避免误触安全提醒。4.3 场景设计师做灵感整理设计师用 ponytail 的场景相对轻松一些。比如在 Dribbble、Behance、Pinterest 或者各种灵感站点上看到一组推荐想把这些图收进自己的素材库如果一张张右键另存为要重复二十多次截图又会被平台水印干扰。点一下书签把所有大图都提取出来然后按尺寸倒序排列就能看到这个页面的视觉主体都是哪些再复制到自己的采集文档里统一加水印或者改名。不过这里必须提个醒灵感站点的图片很多有版权只应该用于个人学习与收藏不该直接拿来商用。ponytail 只是你的素材收集工具它不能替你做版权判断。我也会在 README 里特意加了一句强调不要拿这个工具去批量抓取别人的商业素材库遵守目标站点的条款是使用者自己的责任。这是工具和人的界限我个人觉得既然做工具就得把边界写清楚。4.4 结果不好看怎么办有时候你会发现导出的 Markdown 里文件名的可读性很差都是一长串 CDN 上的随机字符。这种情况下建议先别急着拷贝到结果窗口左上角的过滤框输入关键词比如输入 “banner” 可以只留下文件名里带 banner 的图。如果你的需求是要整理“哪些图属于模块一”按命名关键词筛选是最快的路径。由于 CDN 上的链接通常保留了原始上传时的文件名虽然没有中文但大多数时候含语义grep 一下总比人肉看强。如果页面里的图片大量是 WebP 或 AVIF 格式而你的文档系统不支持预览之前复制 Markdown 的方式就不太理想。这时候可以先导出 JSON然后用一个简单的批量格式转换脚本把地址按实际需要替换成.jpg等格式。前提是源服务器支持格式回退或者你的 CDN 有转换能力。这类变动已经超出 ponytail 的能力范围但因为它导出的是结构化数据后续加工就变得很容易。5. 踩坑记录ponytail 在真实浏览器里的那些坎5.1 常见问题和速查表用了这几年我在不同浏览器、不同站点的环境中踩过不少坑。我把它们整理成一个速查表方便你现查现用问题现象常见原因处理办法点击书签没反应书签代码被浏览器拦掉了或者粘贴时断行重新复制javascript:代码确认无换行结果窗口被弹窗拦截浏览器安全策略默认拦截非用户点击弹窗点击书签时不要离开页面允许一次弹窗图片显示为 hang图片所在域名存在防盗链给结果窗口里的 img 增加referrerpolicyno-referrer抓不到懒加载图片图片没有加载进 DOM脚本只能读已加载的元素先把页面滚动到底再点书签抓不到 iframe 里的图脚本只在顶层 document 执行在控制台切换到对应 iframe 上下文后重新运行图标、分割线混进来小尺寸图片没有被过滤打开“隐藏小于 200px 的图”同一个链接出现多次有不同 query 参数或大小写差异先按 URL 去重再按闭环比对复制按钮报错低版本浏览器不支持 Async Clipboard API回退到document.execCommand(copy)这张表是我最常发给同事看的文档。绝大多数问题都不是 bug而是浏览器安全策略或者使用姿势不对。所以遇到异常先不要慌按表里的顺序从头检查一遍八成能解决。5.2 从“识别不到图”到“把防盗链图显示出来”最让人头疼的问题是“图片列表出来了但缩略图全显示不了”。一开始我以为是 URL 抓错了后来发现是防盗链策略很多 CDN 会检查 HTTP Referer 头只允许来源域名匹配的请求而新窗口里的缩略图请求的 Referer 是空白的所以图片服务器直接拒绝响应。解决办法不复杂在缩略图的img标签上加上referrerpolicyno-referrer让浏览器在请求这张图时不携带 Referer。这样做能绕开一部分防盗链但不能绕开需要登录鉴权的图片那种图你抓到的只是登录页地址没什么用。如果是正常可以访问但就是不显示还有一个隐藏原因getComputedStyle(el).backgroundImage返回的 URL 可能是个相对路径类似url(/assets/bg.png)如果直接用这个字符串发起请求会请求到当前脚本所在的新窗口的地址下而不是原页面地址下。这就是为什么在收集阶段一定要用new URL(src, location.href)做一次标准化。这一步不做后面所有相对路径的图都会失效。5.3 关于安全边界的一点心里话做这个工具的过程中我也一直在思考它的安全边界。ponytail 本质上是一个在用户当前页面上下文中运行的脚本它拥有当前页面的 DOM 访问权限和你在控制台里手动执行代码的权限是一样的不会比那更高。它不读取 Cookie不发起跨域请求不做 localStorage除了弹出结果窗口外改写不了任何外部资源。所以从权限角度讲它没有被放大。但反过来讲如果你在一个不信任的页面上点击书签脚本会暴露那个页面内所有图片的 URL这也意味着这个页面本身就可能被其他恶意脚本入侵。因此我建议不要在完全不熟悉的敏感环境里随意使用任何书签工具尤其是涉及登录态管理的页面。书签脚本是一种强大的自助查看工具但不是加密沙箱。安全意识必须跟上工具只是一个帮助你把头发扎起来的发圈不会主动保护你不受周围环境影响。6. 一些个人经验以及往后的扩展想法分享几个我用下来觉得最值得记住的经验。第一个经验如果采集的结果量很大先复制 JSON再用脚本按文件名归类不要急着在浏览器窗口里试图手动整理。遇到几百张图片的场景人的耐心是撑不过十分钟的脚本反而能精确完成。第二个经验把书签代码存在自己的私人仓库或者笔记里换电脑时第一时间恢复不然临时找代码真的很痛苦。第三个经验如果团队里有多人需要这个工具你可以把 ponytail 的 HTML 安装页部署到一个内网静态站点上同事打开后点一下“安装”就能自动创建书签省掉复制粘贴长代码的麻烦。后续我其实还想给它加两个能力。一个是把结果按“页面内可见区域”分组比如首屏图、滚动屏图、底部模块图这样运营整理页面结构时能更直观。另一个是通过 Web Share API 把结果直接发送到手机端或者分享到团队聊天工具里目前实现还没成熟因为在浏览器新窗口里调 Web Share API 的兼容性还有坑。但想法很有意思分享素材清单这件事比复制粘贴要自然很多。如果你也希望自己页面里的图片资源不再是一堆难看的乱发不妨找个周末写一个十几行的书签或者直接用我这套思路改一版适合自己的。工具本身不是重点重点是你在整理信息时能不能摸到自己的节奏。我个人在实际项目里越来越依赖这种“轻量脚本 结构化输出”的组合因为它把重复劳动变成了两次点击而这正是我们做技术的人最值得花时间去优化的地方。
返回列表