其他
需要从网页截取指定区域并隔离日常浏览器登录态时,用专用…
把 Reddit 帖子、推文、文章段落、图表等网页特定区域,通过专用 headed Chrome 和 DOM 定位裁剪成无干扰插图。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 35/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 55/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 38/100 ×0.15
适用场景
需要从网页截取指定区域并隔离日常浏览器登特定
解决思路
- 使用 agent-browser 的专用 headed Chrome 与持久化 profile;不要要求用户日常 Chrome 开启远程调试。
- 定义专用持久化 profile 约定:PROFILE_DIR="${AGENT_BROWSER_PROFILE:-$HOME/.agent-browser-chrome}";NAMESPACE="${NAMESPACE:-browser-screenshot}";SESSION="${SESSION:-focused-capture}"。
- 定义 ab() 函数:agent-browser --namespace "$NAMESPACE" --session "$SESSION" --headed --profile "$PROFILE_DIR" "$@";所有浏览器命令都通过 ab 执行。
- 不要使用 --auto-connect、通用 CDP discovery 或用户日常 Chrome profile;专用 profile 可跨任务保留 cookies 与登录态,同时不影响用户正常 Chrome。
- 为任务选择描述性的 SESSION;不要并发对同一 profile 运行多个任务,按顺序复用以避免 profile-lock 冲突。
- 如果目标站点需要登录,用 ab 打开它,暂停让用户在专用 headed 窗口完成登录/验证,然后用相同 profile 与 session 继续。
- 如果专用 profile 已在运行:第二次用相同 profile 启动 Chrome 可能在创建 DevTools endpoint 前退出;不要回退到任意已打开 Chrome。
- 应复用该 profile 已知的 Agent Browser session,或仅显式 attach 到命令行包含精确 --user-data-dir=$PROFILE_DIR 值的 Chrome 进程。
- macOS 上用以下命令识别专用进程与本地 CDP 端口:PROFILE_PID="$(ps -axo pid=,command= | awk -v profile="--user-data-dir=$PROFILE_DIR" 'index($0, profile) && index($0, "--remote-debugging-port=") && $0 !~ /Helper/ {print $1; exit}')";CDP_PORT="$(lsof -nP -a -p "$PROFILE_PID" -iTCP -sTCP:LISTEN | awk 'NR > 1 && $9 ~ /^127\.0\.0\.1:[0-9]+$/ {split($9, parts, ":"); print parts[2]; exit}')"。
- attach 时定义 ab():agent-browser --namespace "$NAMESPACE" --session "$SESSION" --cdp "$CDP_PORT" "$@"。
- attach 前要求 PROFILE_PID 与 CDP_PORT 非空且无歧义;若无法验证,请用户关闭专用自动化窗口后重试;不要关闭本任务只是 attach 的浏览器。
- 按完整流水线执行:研究最佳截图页面(web search、fetch);在浏览器导航到正确页面;定位目标元素/区域;只截取该区域的聚焦裁剪截图。
- 硬性规则:绝不把未裁剪的全视口或全页截图作为最终结果;全截图噪声太多(导航栏、侧栏、广告、无关内容);每个截图都必须裁剪到聚焦区域。
- 浏览器只用于捕获,不用于浏览;打开 Chrome 前,用文本工具(WebSearch、WebFetch)找候选页面、读内容、判断是否值得截图。
- 研究优先流程:用 WebSearch 找主题候选页面。
- 用 WebFetch 读取每个候选页面文本内容,检查是否有需要的信息/视觉。
- 评估:该页是否值得截图?是否有清晰聚焦区域可作为插图?
- 只有完成上述评估后,才打开浏览器捕获截图;这能节省大量时间。
- 平台需要登录时改用浏览器优先:Reddit、LinkedIn、X/Twitter 等常把内容放在登录墙后;直接用专用 profile 复用已保存登录态。
- 用户指定平台且有明确搜索需求时跳过 WebSearch/WebFetch,直接在 Chrome 进入平台搜索。
- WebFetch 返回被阻止/不完整内容时(403、CAPTCHA 页面、被剥离内容)切换到 Chrome。
- 浏览器优先时,Chrome 浏览替代 WebSearch:导航到平台搜索页,浏览结果,在决定截图前目视评估页面。
- 页面选择策略:新模型/功能发布(< 6 个月)→ 官方博客公告;用 WebSearch `"<model name>" site:<vendor-domain> blog`。
- 已建立产品(> 6 个月)→ 产品 landing page 或 docs overview;用 WebSearch `"<model name>" official page`。
- 开源模型 → HuggingFace model card 或 GitHub repo;直接 URL huggingface.co/<org>/<model>。
- API 服务 → API 文档页;用 WebSearch `"<service name>" API docs`。
- 该表不穷尽;对任何主题类型都应用 research-first 策略,找最权威、视觉最干净的来源页。
- 好截图源核心:少即是多,聚焦内容而不是页面 chrome。
- 好来源包含聚焦、自包含的信息——一段文字、关键引用、数据表、图;不应是充满按钮、导航、侧栏、交互元素的繁忙页面。
- 优先:博客文章中有清晰标题和 1-2 段文字的一节;单个图表/图;带名称和描述的 model card header;引用或关键发现。
- 避免:带 CTA 和导航的完整 landing page;多面板 dashboard;以 UI 控件(按钮、下拉、表单)为主而非可读内容的页面。
- 官方博客文章理想:有 hero image、突出标题、为分享设计的简洁描述。
- 产品 landing page 可用,但只裁剪 hero 区域,忽略其余。
- HuggingFace model cards 对开源模型可靠:布局一致,模型名+描述总在顶部。
- API docs 可作 fallback:展示产品名和关键规格。
- 经验法则:如果计划捕获区域中交互 UI 元素(按钮、链接、导航项)比可读文字内容多,就是坏裁剪;找更内容丰富区域或换页。
- 打开浏览器前用 WebFetch(轻量 HEAD/GET)验证 URL,避免 404 或重定向浪费时间。
- WebFetch <candidate-url>:检查状态码、标题、内容片段;若 404 或重定向到无关页面,尝试下一个候选。
- 区域选择策略:思考文章读者需要在这个截图里看到什么。
- 在线阵容中介绍模型:捕获模型名+关键 tagline/description;目标为博客 hero 区域或 HF model card header。
- 比较能力:捕获功能亮点或规格表;目标为展示 specs/features 的博客小节。
- 讨论具体功能:捕获功能描述;目标为相关小节标题+1-2 段。
- 展示产品/服务:捕获品牌标识+价值主张;目标为 landing page hero(标题+副标题+视觉)。
- 截图应让读者想「啊,这就是这个模型/产品」,而不是「我在看什么?」。
- 导航前总是先列 tabs:ab tab list;检查页面是否已在专用 session 打开;若已有正确登录与页面状态,复用现有 tab。
- 输入为直接 URL:ab open <url>。
- 输入为搜索查询:ab open https://www.google.com/search?q=<encoded-query>,找到并点击最佳结果。
- 输入为平台+主题:构造平台搜索 URL(见下),定位目标内容。
- 输入为模糊描述:Google 搜索,评估结果,导航到最佳匹配。
- 平台搜索 URL:Reddit https://www.reddit.com/search/?q=<query>。
- X / Twitter https://x.com/search?q=<query>。
- LinkedIn https://www.linkedin.com/search/results/content/?keywords=<query>。
- Hacker News https://hn.algolia.com/?q=<query>。
- GitHub https://github.com/search?q=<query>。
- YouTube https://www.youtube.com/results?search_query=<query>。
- 导航后等待内容稳定:ab wait --load networkidle。
- 注意:Reddit、X、LinkedIn 等站点永远到不了 networkidle;如果 open 输出已显示页面标题,跳过等待;可用 wait 2000 作为安全替代。
- 定位步骤最关键;目标是找到精确包裹待捕获内容的 CSS selector。
- 主方法:拍 annotated 截图理解布局:ab screenshot --annotate。
- 拍 snapshot 查看可访问性树:ab snapshot -i。
- 识别目标容器元素:语义 HTML 容器 <article>、<main>、<section>;平台特定组件;data attributes [data-testid=...]、[data-id=...]。
- 用 get box 验证元素有合理 bounding box:ab get box '<selector>';返回 { x, y, width, height };检查 width > 100px 且 < viewport width,height > 50px;如果 box 是整个页面,selector 太宽,需细化。
- selector 难找时用 eval 探索 DOM:ab eval 'document.querySelector("article")?.getBoundingClientRect()'。
- 平台选择器:Reddit 帖子 shreddit-post、[data-testid=post-container]。
- X / Twitter 推文 article[data-testid=tweet]。
- LinkedIn feed post .feed-shared-update-v2。
- Hacker News story + comments #hnmain .fatitem。
- GitHub repo card [data-hpc]、.repository-content。
- YouTube video player area #player-container-outer。
- Generic article main content article、main、[role=main]、.post-content、.article-body。
- 这些 selector 可能随时间变化;使用前总是用 get box 验证。
- 多个匹配元素时:计数 ab get count 'article[data-testid=tweet]'。
- 使用 :nth-child 或 :first-of-type,或更具体的 selector。
- 或用 eval 按文本内容找正确元素:ab eval --stdin <<'EOF' const posts = document.querySelectorAll('article[data-testid=tweet]'); for (let i = 0; i < posts.length; i++) { const text = posts[i].textContent.substring(0, 80); console.log(i, text); } EOF。
- 然后用 :nth-of-type(N) 或唯一父 selector 定位特定元素。
- 捕获方法 A(目标适合 viewport 时优先):滚动目标进入视图 ab scrollintoview '<selector>'。
- 等待 ab wait 500。
- 截取 viewport 截图 ab screenshot /tmp/browser-screenshot-raw.png。
- 然后用 bounding box 裁剪。
- 捕获方法 B(任何尺寸目标):截取全页截图 ab screenshot --full /tmp/browser-screenshot-full.png。
- 获取目标元素 bounding box:ab get box '<selector>';输出如 { x: 200, y: 450, width: 680, height: 520 }。
- 然后裁剪。
- 裁剪用 ImageMagick(IMv7 用 magick,convert 已废弃)裁剪到目标区域;加 padding 留呼吸空间。
- Retina 处理:macOS Retina 截图以 2x 分辨率捕获;1728x940 viewport 产生 3456x1880 图像;必须考虑缩放系数。
- 检测缩放系数:比较 viewport 尺寸与实际图像尺寸:magick identify /tmp/screenshot.png;3456x1880 表示 1728x940 viewport 上是 2x。
- 裁剪前将 get box 坐标乘以缩放系数:SCALE=2;X=$((200 * SCALE));Y=$((450 * SCALE));W=$((680 * SCALE));H=$((520 * SCALE));PADDING=$((16 * SCALE))。
- 裁剪命令:magick /tmp/browser-screenshot-full.png -crop $((W + PADDING*2))x$((H + PADDING*2))+$((X - PADDING))+$((Y - PADDING)) +repage <output-path>.png。
- 重要:get box 返回浮点数;传给 ImageMagick 前四舍五入为整数。
- Padding:用 12–20px(viewport px);若目标有明显视觉边界(card、bordered box)增到约 30px;用户要 tight crop 时用 0。
- 输出路径:用户指定则使用;否则保存为当前目录下描述性名称,如 reddit-post-screenshot.png、tweet-screenshot.png。
- 裁剪后读取输出图像目视检查内容是否正确。
- 若裁剪错误(漏内容、空白太多、错元素),调整 selector 或 bounding box 后重试。
- fallback 视觉高亮确认:DOM 定位不确定时——selector 可能错、多个候选、目标模糊——用 JS 注入高亮在裁剪前目视确认。
- 注入 candidate 元素高亮边框:ab eval --stdin <<'EOF' (function() { const el = document.querySelector('<selector>'); if (!el) { console.log('NOT_FOUND'); return; } el.style.outline = '4px solid red'; el.style.outlineOffset = '2px'; el.scrollIntoView({ block: 'center' }); })(); EOF。
- 截图并目视检查:ab screenshot /tmp/highlight-check.png;读取截图检查红框是否包围正确内容。
- 如果正确,移除高亮并继续裁剪:ab eval 'document.querySelector("<selector>").style.outline = ""; document.querySelector("<selector>").style.outlineOffset = "";'。
- 如果错误,尝试下一个候选或改进 selector,重新高亮并重新检查。
- 使用 fallback 的时机:页面有复杂/嵌套组件且不确定哪个容器正确;存在多个相似元素需选正确者;用户描述模糊(「页面中间那个图表」);get box 结果可疑(太大、太小、零尺寸)。
- 最终截图前清理页面:关闭 cookie banners、popups、overlays。
- 清理代码:ab eval --stdin <<'EOF' (function() { // Common cookie/popup selectors const selectors = [ '[class*=cookie] button', '[class*=consent] button', '[class*=banner] [class*=close]', '[class*=modal] [class*=close]', '[class*=popup] [class*=close]', '[aria-label=Close]', '[data-testid=close]' ]; selectors.forEach(sel => { document.querySelectorAll(sel).forEach(el => { if (el.offsetParent !== null) el.click(); }); }); // Hide fixed/sticky elements that overlay content (nav bars, banners) document.querySelectorAll('*').forEach(el => { const style = getComputedStyle(el); if ((style.position === 'fixed' || style.position === 'sticky') && el.tagName !== 'HTML' && el.tagName !== 'BODY') { el.style.display = 'none'; } }); })(); EOF。
- 谨慎使用:隐藏 fixed 元素可能移除重要上下文;仅在 overlays 明显遮挡目标区域时运行。
- 无法关闭的 cookie banners:有些(如 Jina AI 的 Usercentrics)在 shadow DOM 或 iframes 中,无法通过 JS click() 或 remove() 关闭;不要浪费多次 JS 尝试。
- 改为:裁剪掉它——若 banner 在顶部/底部,调整裁剪区域排除;这是最快可靠方法。
- 或滚过它——截图前把目标内容滚离 banner 区域。
- 截图前设置 viewport 以获得一致高质量:标准桌面 ab set viewport 1280 800。
- 更宽用于 dashboard/data-heavy 页面:ab set viewport 1440 900。
- 更窄用于移动式内容(社交媒体帖子):ab set viewport 800 600。
- 选择让目标内容渲染干净的 viewport 宽度——不过挤也不过拉伸。
- Troubleshooting:get box 返回 null 或零尺寸:selector 不匹配任何元素;用 ab get count '<selector>' 验证。
- 元素可能隐藏或尚未渲染;尝试 ab wait 2000 后重试。
- 裁剪图像空白或区域错误:全页截图坐标可能与 viewport 坐标不同;用 screenshot --full 配合 get box(它们使用同一坐标系)。
- 检查页面是否有水平滚动——get box x 值可能有偏移。
- 目标元素在 iframe 内:get box 与 snapshot -i 看不到 iframe 内部;用 eval 访问 iframe 内容:ab eval 'document.querySelector("iframe").contentDocument.querySelector("<sel>").getBoundingClientRect()';注意仅同源 iframe 有效。
- open 成功但内容错误:浏览器可能切到不同 tab(popup/redirect 打开新 tab);导航后总是验证 ab eval 'document.location.href'。
- 如果 URL 错误,用 ab tab list 找正确 tab 并用 ab tab goto <N> 切换。
- 截图命令因字体超时:有些页面(如 Google developer docs)卡在 document.fonts.ready;先强制解析:ab eval 'document.fonts.ready.then(() => "ok")',然后重试截图。
- 页面有懒加载内容:截图前滚动触发加载:ab scroll down 1000;ab wait 1500;ab scroll up 1000。
适用边界 · 注意事项
- 不适用于需要未经裁剪的全页或全视口截图作为最终结果的场景。
- 不适用于无法安装或使用 agent-browser、ImageMagick 的环境。
- 不适用于需要并发多个任务共用同一专用 profile,或无法在专用自动化窗口完成登录/验证的场景。