运行时依赖
安装命令
点击复制技能文档
下载网页为PDF(agent-browser配方)
传统方法在现代网站上会失败:chrome --headless --print-to-pdf 只能捕获初始视口的图像。滚动条以下的内容会渲染为空白矩形。agent-browser pdf 在打开后立即执行,也会出现同样的问题 - 延迟加载的图像还没有解码。通过JS滚动并等待固定时间也是不可靠的 - 你不知道每个图像什么时候实际完成加载。解决方法是使用一个异步脚本,去除延迟加载属性,滚动页面触发基于IntersectionObserver的加载器,并等待每个解码。agent-browser的eval会等待返回的promise解析后才退出,因此后续的pdf命令会看到一个完全加载的DOM。
配方
如果多个测试/agent运行可能共享主机的agent-browser,则使用agent-browser --session <唯一名称> ...隔离每个命令在管道中。单用户一次性捕获可以省略标志并使用默认会话。设置AGENT_BROWSER_HEADED=false环境变量,然后运行,以便技能即使主机的~/.agent-browser/config.json默认为"headed": true,也会以无头模式启动。这避免了在后台工作的agent弹出真实的Chrome窗口。不要使用CLI的--headed false标志 - 在agent-browser 0.26.0中,它会解析但会损坏会话上下文(后续命令会看到一个空文档)。环境变量是支持的路线。要调试运行,可以取消设置变量或传递--headed。
export AGENT_BROWSER_HEADED=false
agent-browser open
agent-browser wait --load networkidle
agent-browser eval "(async () => { const sleep = ms => new Promise(r => setTimeout(r, ms)); ['#onetrust-banner-sdk','#onetrust-consent-sdk','.ot-sdk-container','#ot-sdk-btn-floating','[id=cookie]','[id=consent]','[id*=onetrust]'].forEach(s => document.querySelectorAll(s).forEach(e => e.remove())); document.querySelectorAll('img').forEach(img => { img.removeAttribute('loading'); img.removeAttribute('decoding'); if (img.dataset.src) img.src = img.dataset.src; if (img.dataset.srcset) img.srcset = img.dataset.srcset; }); for (let y = 0; y < document.documentElement.scrollHeight + 2000; y += 400) { window.scrollTo(0, y); await sleep(200); } window.scrollTo(0, document.documentElement.scrollHeight); await sleep(2000); await Promise.all(Array.from(document.images).map(i => i.complete && i.naturalWidth ? null : new Promise(r => { i.addEventListener('load', r, {once:true}); i.addEventListener('error', r, {once:true}); setTimeout(r, 5000); }) )); window.scrollTo(0, 0); await sleep(500); return Array.from(document.images).filter(i => !i.naturalWidth).length; })()"
agent-browser pdf /tmp/page.pdf
agent-browser close
# 验证结果
pdfinfo /tmp/page.pdf | grep -E "Pages|File size"
eval返回未加载图像的数量。预期为0。如果非零,配方没有完全捕获页面 - 在信任PDF之前进行调查。
每个步骤的重要性
wait --load networkidle在eval之前给页面一个机会来附加其IntersectionObservers和其他JS钩子。在观察者附加之前滚动会使触发失败。删除加载属性是结构上的修复。这与percollate内部使用的技巧相同 - 让Chromium渴望获取每个图像的最可靠方法。滚动整个高度以400px的步骤触发任何基于观察者的加载器。一些网站即使在删除加载=lazy属性后仍使用观察者。await Promise.all对每个
保证在eval返回之前解码像素。agent-browser的eval是promise-aware的 - 下一个命令(pdf)不会在此解析之前运行。返回破损图像的数量是你的验证。如果不是0,配方没有完全捕获页面 - 不要信任PDF。
清理管道(可选但推荐)
agent-browser以信件大小保存页面的完整页脚(导航、新闻通讯注册、链接站点地图)。为了获得干净的存档:
# 1. 检查总页数并可视化识别哪些尾随页面是页脚
pdfinfo /tmp/page.pdf | grep Pages
# 使用Read工具查看PDF的最后几页并决定文章在哪里结束。
# 2. 修剪页脚页面。下面的“1-9”仅为示例 - 用实际范围替换pdfinfo + 可视化检查。不要逐字复制。
qpdf /tmp/page.pdf --pages . 1-9 -- /tmp/page-trimmed.pdf
# 3. 压缩(通常会将图像保持完整,减小60-70%)
gs -sDEVICE=pdfwrite -dCompatibilityLevel=1.4 -dPDFSETTINGS=/ebook \
-dNOPAUSE -dQUIET -dBATCH \
-sOutputFile=/path/to/final.pdf /tmp/page-trimmed.pdf
-dPDFSETTINGS=/ebook保持图像在大约原始大小的一半仍然可读。