【工具推荐】开发一个网页快照工具:从需求到落地的完整复盘
本文记录我独立完成 SnapPage 这个项目的全过程包括需求分析、技术选型、踩坑记录和产品思考。项目为非开源的私人作品仅供学习交流。一、为什么要做这个工具平时上网收藏了不少文章和网页但时间久了问题接踵而至收藏的链接变成了 404网页改版后内容面目全非想保存的资料用浏览器Ctrl S存下来排版全毁、图片丢失看到有价值的长文广告和干扰元素太多阅读体验极差市面上也不是没有解决方案但要么是付费的要么需要注册账号要么会把你的数据上传到云端。我只是想简单地把当前这个页面保存下来为什么要这么复杂于是决定自己动手做一个无需注册、无需登录、用完即走的网页快照工具。二、功能设计四个核心场景在动手写代码之前先梳理清楚用户真正需要什么。我总结了四类最常见的保存网页需求场景一整页截图很多人需要把网页完整截下来可能是为了存档可能是为了分享。系统自带的截图工具只能截一屏遇到长网页就无能为力了。所以第一个功能就是全页截图而且要支持不同设备的视口尺寸桌面端1920x1080平板端768x1024手机端375x812截图后还要能直接复制到剪贴板方便粘贴到微信、文档或者邮件里。场景二导出 PDF截图适合分享但不适合打印和归档。有些表格、文档类的网页存成 PDF 才是最合适的。这里有个细节很容易忽略不同网页的宽度差异很大。如果用固定 A4 尺寸很多宽表格会被截断。所以我在生成 PDF 之前会先测量页面的实际宽高如果太宽就自动切换横版甚至使用自定义纸张尺寸确保内容不被裁剪。场景三HTML 离线存档截图和 PDF 都是静态的如果我想保留网页的原始交互和样式就需要存成 HTML。但直接保存原始 HTML 有个问题里面的 CSS、图片链接都是相对路径或者外网地址断网后就打不开了。解决方式是在 HTML 头部注入一个base href标签指向原始网址这样即使离线打开浏览器也能正确解析资源路径。场景四阅读模式提取现在的网页设计越来越复杂广告、弹窗、侧边栏、相关推荐……真正想看的正文内容反而被淹没。我引入了 Mozilla 的 Readability 算法自动识别文章正文去掉干扰元素输出一个清爽的阅读视图。更进一步提取出的内容可以直接导出为 Markdown方便导入到 Obsidian、Notion 等笔记软件中。三、技术选型与架构设计3.1 为什么用 Playwright Chromium网页快照的核心是在服务端打开一个浏览器访问目标网址然后做各种操作。我对比了几种方案PuppeteerGoogle 出品但社区活跃度近年有所下降PlaywrightMicrosoft 出品支持多浏览器API 设计更现代社区更活跃外部服务如 Browserless.io需要付费 Token不符合零成本的初心最终选择了Playwright sparticuz/chromium。Playwright 负责浏览器自动化sparticuz/chromium 提供适合 Serverless 环境的 Chromium 二进制包。本地开发时自动检测系统已安装的 Chrome/Edge部署到线上时自动切换为打包好的 Linux 版本。3.2 为什么坚持无状态设计这个项目从设计之初就定下了几个不不建数据库— 不需要 SQLite、Postgres也不需要 ORM不存文件— 不需要 S3、对象存储生成的结果直接返回给浏览器不存用户数据— URL 不记录、结果不缓存、行为不追踪这样做有几个好处架构极简部署和维护成本极低隐私安全用户不用担心自己的浏览记录被保存符合 Serverless 理念每个请求独立处理水平扩展无压力3.3 部署平台的选择一开始考虑过 Cloudflare Pages但很快被否定了。因为 Playwright 需要在 Node.js 环境里运行浏览器二进制文件而 Cloudflare Workers 运行在 V8 隔离环境中不支持执行本地二进制文件。所以最终选择了Vercel。它的 Serverless Function 支持 Node.js 运行时而且有充足的超时时间配置Pro 版支持到 60 秒对于网页渲染和截图来说足够用了。四、开发过程中踩过的坑坑一Chromium 冷启动延迟Serverless 的特点是按需启动函数冷启动时 Chromium 需要从头初始化第一次请求可能要等 5-10 秒体验很差。解决方案是做了一个warmup 机制页面加载时前端偷偷发一个/api/warmup请求让 Serverless Function 提前把浏览器启动起来。等用户真正输入 URL 点击生成时浏览器已经准备好了响应速度提升非常明显。坑二PDF 尺寸自适应一开始 PDF 直接用固定 A4 尺寸结果很多宽表格被截断用户体验很差。后来改为先测量后生成的流程先用 Playwright 打开页面获取scrollWidth和scrollHeight如果宽度超过 A4 的 1.2 倍自动切换为横版如果横版还不够使用自定义纸张尺寸Chrome 最大支持 200 英寸正常页面则保持标准 A4坑三部分网站在服务端被阻断在提取页面元信息title、description、favicon时发现有些网站比如 Google在 Node.js 的网络层会直接返回阻断页面拿不到正确的 meta 标签。解决方案是做了一个 fallback先用轻量级的 HTTP 请求尝试获取如果失败再用 Playwright 的独立网络栈重新获取。Playwright 的浏览器网络栈和用户真实浏览器的请求特征更接近大部分阻断都能绕过。坑四jsdom 的 ESM 兼容问题项目早期用 jsdom 做 DOM 解析但 jsdom v27 开始改为纯 ESM 模块和 Next.js 的 CJS 构建流程冲突编译直接报错。最后换成了linkedom它更轻量、兼容 CJS而且性能更好。配合正则表达式做辅助提取完全替代了 jsdom 的职责。五、产品层面的思考5.1 为什么不做用户系统很多人建议我加上注册登录、历史记录、收藏夹这些功能。但我始终觉得工具的价值在于解决当下的问题而不是捆绑用户。加了用户系统就要维护数据库、处理密码安全、做权限管理整个项目的复杂度会指数级上升。更关键的是用户的使用链路会变长打开网站 → 注册 → 登录 → 验证邮箱 → 才能使用。很多人在前两步就流失了。打开就用和注册后用体验差距是巨大的。5.2 双语支持的取舍项目支持中英文双语切换所有 UI 文案、70 条励志名言、法律免责声明都完整翻译。这个决策源于一个简单的事实工具类产品的用户可能来自任何地方语言不应该成为门槛。但翻译质量也是个大工程很多技术术语在不同语境下的译法需要反复斟酌。比如 Snapshot 到底该叫快照还是截图最后根据使用场景做了区分功能层面叫快照图片输出时叫截图。5.3 法律免责声明的必要性这是一个容易被忽视但非常重要的点。工具本身是中性的但用户可能用它下载受版权保护的内容。如果不做免责声明运营者可能承担连带责任。我在页面底部加了一个免责声明弹窗明确了几点本工具为纯技术服务不存储任何数据用户需自行承担使用合规责任工具运营者不承担任何连带责任虽然看起来是自我保护但对自己和用户都是负责的表现。六、一些数据与反思项目从构思到 MVP 完成断断续续花了大约三周时间。其中写代码只占了一半另一半时间在纠结产品细节按钮该放在哪里、进度条用什么颜色、错误提示怎么写才不让用户焦虑。目前支持的功能已经覆盖了大多数保存网页的场景但还有一些想法没来得及实现暗色/亮色主题切换目前只有深色主题虽然我自己很喜欢但确实不是所有人的偏好本地历史记录用 localStorage 保存最近使用过的 URL方便二次访问批量生成一次性粘贴多个 URL逐个生成快照这些都不涉及架构大改后续有时间会慢慢加上。七、写在最后做这个项目最大的收获不是技术层面的而是对工具类产品的理解最好的工具应该是隐形的用户不应该感受到它的存在只应该感受到问题被解决了。当你粘贴一个网址、点击按钮、几秒钟后拿到想要的结果整个过程应该是自然且无痛的。任何多余的步骤、任何需要学习成本的设计都是对这个理念的背离。如果你也在做类似的项目或者有更好的想法欢迎一起交流。技术的乐趣从来不只是写代码而是做出有人愿意用的东西。SnapPage — Paste a URL, get a snapshot关于项目SnapPage 为个人独立开发的非开源项目仅供学习交流使用。文中提到的技术方案和踩坑记录希望能对正在做类似项目的同学有所帮助。