browser-screenshot

browser-screenshot

使用專用的有頭 Chrome 設定檔(含持久登入狀態),從網頁中擷取聚焦且特定區域的螢幕截圖。根據使用者提供的內容(網址、搜尋查詢、社群媒體貼文)導航至正確頁面,透過 DOM 選擇器定位目標區域,並裁切出乾淨、聚焦的螢幕截圖,而不會附加到使用者的日常瀏覽器。

0星標
0分支
更新於 2026/7/22
SKILL.md
唯讀
名稱
browser-screenshot
描述

使用專用的有頭 Chrome 設定檔(含持久登入狀態),從網頁中擷取聚焦且特定區域的螢幕截圖。根據使用者提供的內容(網址、搜尋查詢、社群媒體貼文)導航至正確頁面,透過 DOM 選擇器定位目標區域,並裁切出乾淨、聚焦的螢幕截圖,而不會附加到使用者的日常瀏覽器。

技能:瀏覽器螢幕截圖

從網頁中擷取特定區域的聚焦螢幕截圖——Reddit 貼文、推文、文章區塊、圖表等——而不只是全頁傾印。

先決條件:必須安裝 agent-browser。此技能使用自己的有頭 Chrome 搭配專用持久設定檔;使用者的日常 Chrome 不需要遠端除錯。

專用瀏覽器設定檔

使用與 my-chrome-automation 相同的專用持久設定檔慣例:

PROFILE_DIR="${AGENT_BROWSER_PROFILE:-$HOME/.agent-browser-recorder-chrome}"
NAMESPACE="${NAMESPACE:-browser-screenshot}"
SESSION="${SESSION:-focused-capture}"

ab() {
  agent-browser --namespace "$NAMESPACE" --session "$SESSION" --headed --profile "$PROFILE_DIR" "$@"
}

所有瀏覽器指令都透過 ab 執行。請勿使用 --auto-connect、通用 CDP 發現或使用者的日常 Chrome 設定檔。專用設定檔可在任務之間保留 Cookie 和登入狀態,同時讓使用者的正常 Chrome 保持開啟且不受影響。

在實際可行時,為任務選擇描述性的 SESSION。請勿同時對同一個設定檔執行多個任務;應依序重複使用,以避免設定檔鎖定衝突。

如果目標網站需要登入,請使用 ab 開啟它,暫停讓使用者在專用的有頭視窗中完成登入或驗證,然後繼續使用相同的設定檔和工作階段。

如果專用設定檔已在執行中

第二次啟動 Chrome 使用相同設定檔時,可能會在建立 DevTools 端點之前退出。絕對不要回退到任何已開啟的 Chrome。請重複使用此設定檔的已知 Agent Browser 工作階段,或明確僅附加到命令列中包含確切 --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}')"

ab() {
  agent-browser --namespace "$NAMESPACE" --session "$SESSION" --cdp "$CDP_PORT" "$@"
}

在附加之前,要求非空且明確的 PROFILE_PIDCDP_PORT 值。如果無法驗證,請要求使用者關閉專用自動化視窗並重試。請勿關閉此任務僅附加到的瀏覽器。


概述

此技能處理完整的流程:

  1. 研究要截圖的最佳頁面(網路搜尋、擷取)
  2. 導航到瀏覽器中的正確頁面
  3. 定位頁面上的目標元素/區域
  4. 擷取僅該區域的聚焦、裁切螢幕截圖

嚴格規則:禁止全螢幕截圖

絕對不要輸出未裁切的完整視窗或全頁螢幕截圖作為最終結果。 全螢幕截圖包含太多雜訊(導覽列、側邊欄、廣告、不相關的內容),不適合用作文章插圖。每張螢幕截圖都必須裁切到聚焦區域。


步驟 0:研究——在開啟瀏覽器之前尋找並驗證來源

瀏覽器是用來擷取,不是用來瀏覽的。 在 Chrome 中開啟任何內容之前,請使用基於文字的工具(WebSearch、WebFetch)來尋找候選頁面、閱讀其內容,並決定哪些頁面實際上值得截圖。

研究優先的工作流程

  1. WebSearch 尋找該主題的候選頁面
  2. WebFetch 每個候選頁面以閱讀其文字內容——檢查它是否有你需要的資訊/視覺元素
  3. 評估:這個頁面值得截圖嗎?它是否有清晰、聚焦的區域可以作為插圖?
  4. 然後才開啟瀏覽器來擷取螢幕截圖

這可以節省大量時間——大多數候選頁面不值得截圖,你可以在沒有瀏覽器導航開銷的情況下排除它們。

何時改用瀏覽器優先

在以下情況下,跳過 WebSearch/WebFetch 階段,直接前往 Chrome 瀏覽:

  • 目標平台需要登入——Reddit、LinkedIn、X/Twitter 和其他社群平台通常會將內容隱藏在登入牆後。直接使用專用設定檔,以便重複使用其儲存的登入狀態。
  • 使用者指定了平台且有明確的搜尋需求——例如「找一篇關於 X 的 Reddit 貼文」或「截圖一篇關於 Y 的推文」。直接在 Chrome 中前往該平台的搜尋頁面。
  • WebFetch 回傳被封鎖或不完整的內容——某些網站會積極封鎖非瀏覽器請求。如果你收到 403、CAPTCHA 頁面或內容被剝離,請切換到 Chrome。

在這些情況下,Chrome 瀏覽會取代 WebSearch——導航到平台的搜尋頁面、瀏覽結果,並在決定要截圖什麼之前視覺化評估頁面。

頁面選擇策略

正確的頁面取決於文章的上下文以及主題的新近度/知名度:

主題類型 最佳尋找頁面 如何尋找
新模型/功能發布(< 6 個月) 宣布該功能的官方部落格文章 WebSearch "<model name>" site:<vendor-domain> blog
已建立的產品(> 6 個月) 產品登陸頁面或文件概覽 WebSearch "<model name>" official page
開源模型 HuggingFace 模型卡或 GitHub 儲存庫 直接網址:huggingface.co/<org>/<model>
API 服務 API 文件頁面 WebSearch "<service name>" API docs

注意:此表格列出常見的主題類型,但並非詳盡無遺。對任何主題類型應用相同的研究優先策略——為手邊的主題找到最權威且視覺上最乾淨的來源頁面。

好的螢幕截圖來源的條件

核心原則:少即是多。專注於內容,而不是瀏覽器 chrome。

好的螢幕截圖來源包含聚焦、自成一體的資訊——一段文字、一個關鍵引述、一個資料表格、一個圖表。它不應該是一個充滿按鈕、導覽、側邊欄和互動元素的繁忙頁面。

  • 偏好:部落格文章中帶有清晰標題和 1-2 段文字的部分。單一圖表或圖形。帶有名稱和描述的模型卡標題。引述或關鍵發現。
  • 避免:帶有 CTA 和導覽的完整登陸頁面。具有多個面板的儀表板檢視。以 UI 控制項(按鈕、下拉選單、表單)為主而非可讀內容的頁面。
  • 官方部落格文章是理想的:它們有英雄圖片、突出的標題和為分享而設計的簡潔描述
  • 產品登陸頁面也可以,但僅限於你裁切到英雄區塊時——忽略其餘部分
  • HuggingFace 模型卡對於開源模型來說是可靠的:一致的佈局,模型名稱 + 描述始終在頂部
  • API 文件是可接受的備案:顯示產品名稱和主要規格

經驗法則:如果你計劃擷取的區域包含的互動式 UI 元素(按鈕、連結、導覽項目)多於可讀的文字內容,那就是一個糟糕的裁切。尋找內容更豐富的區域,或選擇完全不同的頁面。

預先網址驗證

在瀏覽器中開啟之前,使用 WebFetch(輕量級 HEAD/GET)驗證網址,以避免浪費時間在 404 或重新導向上:

WebFetch: <candidate-url>
→ 檢查狀態碼、標題和內容片段
→ 如果是 404 或重新導向到不相關的頁面,嘗試下一個候選

區域選擇策略

思考文章讀者需要在這個螢幕截圖中看到什麼

文章上下文 要擷取的內容 目標區域
在系列中介紹一個模型 模型名稱 + 關鍵標語/描述 部落格英雄區塊或 HF 模型卡標題
比較能力 功能亮點或規格表 顯示規格/功能的部落格區塊
討論特定功能 功能描述 相關區塊標題 + 1-2 段文字
展示產品/服務 品牌識別 + 價值主張 登陸頁面英雄區塊(標題 + 副標題 + 視覺元素)

螢幕截圖應該讓讀者覺得「啊,這就是這個模型/產品的樣子」——而不是「我在看什麼?」


步驟 1:導航到目標頁面

始終從列出分頁開始

ab tab list

檢查該頁面是否已在專用工作階段中開啟。當現有分頁具有正確的登入和頁面狀態時,重複使用它們。

根據輸入類型導航

使用者提供 策略
直接網址 ab open <url>
搜尋查詢 ab open https://www.google.com/search?q=<encoded-query> → 找到並點擊最佳結果
平台 + 主題 建構平台搜尋網址(見下方)→ 定位目標內容
模糊描述 Google 搜尋 → 評估結果 → 導航到最佳匹配

特定平台的搜尋網址

平台 搜尋網址模式
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 作為安全的替代方案。


步驟 2:定位目標區域

這是關鍵步驟。目標是找到一個CSS 選擇器,精確地包裹要擷取的內容。

主要方法:DOM 選擇器發現

  1. 拍攝帶註解的螢幕截圖以了解頁面佈局:

    ab screenshot --annotate
    
  2. 拍攝快照以查看頁面的無障礙樹:

    ab snapshot -i
    
  3. 識別目標容器元素。尋找:

    • 語意 HTML 容器:<article><main><section>
    • 特定平台的元件(參見平台選擇器
    • 資料屬性:[data-testid="..."][data-id="..."]
  4. 使用 get box 驗證以確認元素具有合理的邊界框:

    ab get box "<selector>"
    

    這會回傳 { x, y, width, height }。合理性檢查:

    • 寬度應 > 100px 且 < 視窗寬度
    • 高度應 > 50px
    • 如果框是整個頁面,則選擇器太寬泛——請精煉它
  5. 如果選擇器難以找到,使用 eval 探索 DOM:

    ab eval "document.querySelector('article')?.getBoundingClientRect()"
    

平台選擇器

熱門平台的常見容器選擇器:

平台 目標 典型選擇器
Reddit 一篇貼文 shreddit-post[data-testid="post-container"]
X / Twitter 一則推文 article[data-testid="tweet"]
LinkedIn 一則動態貼文 .feed-shared-update-v2
Hacker News 一則故事 + 留言 #hnmain .fatitem
GitHub 一個儲存庫卡片 [data-hpc].repository-content
YouTube 影片播放器區域 #player-container-outer
通用文章 主要內容 articlemain[role="main"].post-content.article-body

這些選擇器可能會隨著時間而改變。在使用前務必使用 get box 驗證。

多個匹配元素

如果選擇器匹配多個元素(例如,時間軸上的多則推文),請縮小範圍:

# 計算匹配數量
ab get count "article[data-testid='tweet']"

# 使用 nth-child 或 :first-of-type,或更特定的選擇器
# 或使用 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) 或唯一的父選擇器來定位特定的一個。


步驟 3:擷取聚焦的螢幕截圖

方法 A:捲動 + 視窗螢幕截圖(偏好用於視窗大小的目標)

最適合目標元素適合視窗的情況。

# 將目標捲動到視野中
ab scrollintoview "<selector>"
ab wait 500

# 拍攝視窗螢幕截圖
ab screenshot /tmp/browser-screenshot-raw.png

然後使用邊界框進行裁切(參見裁切)。

方法 B:全頁螢幕截圖 + 裁切(適用於任何大小的目標)

最適合目標可能大於視窗或需要精確裁切的情況。

# 拍攝全頁螢幕截圖
ab screenshot --full /tmp/browser-screenshot-full.png

# 取得目標元素的邊界框
ab get box "<selector>"
# 輸出:{ x: 200, y: 450, width: 680, height: 520 }

然後裁切(參見裁切)。

裁切

使用 ImageMagick(IMv7 使用 magickconvert 已棄用)將螢幕截圖裁切到目標區域。加入內邊距以提供視覺呼吸空間。

Retina 顯示器處理

關鍵:在 macOS Retina 顯示器上,螢幕截圖以 2 倍解析度擷取。1728x940 的視窗會產生 3456x1880 的影像。你必須考慮這一點:

  1. 檢測縮放因子:比較視窗大小與實際影像尺寸:

    # 檢查實際影像尺寸
    magick identify /tmp/screenshot.png
    # → 3456x1880 表示在 1728x940 的視窗上為 2 倍縮放
    
  2. 在裁切之前將 get box 座標乘以縮放因子

    # get box 回傳視窗座標:{ x: 200, y: 450, width: 680, height: 520 }
    # 對於 2 倍 Retina,實際影像座標為:
    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 之前,將它們四捨五入為整數。

內邊距:使用 12–20px(視窗像素)。如果目標具有明顯的視覺邊界(卡片、邊框框),則增加到約 30px。如果使用者想要緊密裁切,則使用 0。

輸出路徑

  • 如果使用者指定了輸出路徑,則使用該路徑
  • 否則,以描述性名稱儲存到目前目錄,例如 reddit-post-screenshot.pngtweet-screenshot.png

步驟 4:驗證結果

裁切後,讀取輸出影像以驗證它擷取了正確的內容:

# 使用 Read 工具視覺化檢查裁切的螢幕截圖

如果裁切錯誤(遺漏內容、太多空白、錯誤的元素),請調整選擇器或邊界框並重試。


備用方案:視覺化高亮確認

當基於 DOM 的定位不確定時——選擇器可能錯誤、存在多個候選、或目標不明確——使用 JS 注入的高亮在裁切前進行視覺化確認。

運作方式

  1. 在候選元素上注入高亮邊框

    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
    
  2. 拍攝螢幕截圖並視覺化檢查:

    ab screenshot /tmp/highlight-check.png
    

    讀取螢幕截圖以檢查紅色邊框是否包圍正確的內容。

  3. 如果正確,移除高亮並繼續裁切:

    ab eval "document.querySelector('<selector>').style.outline = ''; document.querySelector('<selector>').style.outlineOffset = '';"
    
  4. 如果錯誤,嘗試下一個候選或精煉選擇器,重新高亮,並重新檢查。

何時使用此備用方案

  • 頁面具有複雜/巢狀元件,且你不確定哪個容器是正確的
  • 存在多個相似元素,你需要選擇正確的那個
  • 使用者的描述模糊(「頁面中間的那個圖表」)
  • get box 結果看起來可疑(太大、太小、零大小)

頁面準備:在擷取前清理

在拍攝最終螢幕截圖之前,清理頁面以獲得更好的結果:

# 關閉 Cookie 橫幅、彈出視窗、覆蓋層
ab eval --stdin <<'EOF'
(function() {
  // 常見的 Cookie/彈出視窗選擇器
  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();
    });
  });

  // 隱藏覆蓋內容的固定/黏性元素(導覽列、橫幅)
  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

謹慎使用:隱藏固定元素可能會移除重要的上下文。僅在覆蓋層明顯阻擋目標區域時才執行此操作。

無法關閉的 Cookie 橫幅

某些 Cookie 同意橫幅(例如 Jina AI 的 Usercentrics)位於 Shadow DOM 或 iframe 中,無法透過 JS click()remove() 關閉。不要浪費時間嘗試多種 JS 方法。相反地:

  1. 將其裁切掉——如果橫幅在頂部或底部,只需調整裁切區域以排除它。這是最快且最可靠的方法。
  2. 捲動過去——在擷取前將目標內容捲離橫幅區域。

視窗大小設定

為了獲得一致、高品質的螢幕截圖,請在擷取前設定視窗大小:

# 標準桌面視窗
ab set viewport 1280 800

# 更寬,適用於儀表板/資料密集型頁面
ab set viewport 1440 900

# 更窄,適用於類似行動裝置的內容(社群媒體貼文)
ab set viewport 800 600

選擇一個能讓目標內容清晰呈現的視窗寬度——不要太擁擠,也不要太拉伸。


疑難排解

get box 回傳 null 或零大小

  • 選擇器不匹配任何元素。使用 get count "<selector>" 驗證。
  • 元素可能隱藏或尚未渲染。嘗試 wait 2000 並重試。

裁切的影像為空白或錯誤區域

  • 全頁螢幕截圖的座標可能與視窗座標不同。使用 screenshot --full 搭配 get box(它們使用相同的座標系統)。
  • 檢查頁面是否有水平捲動——get box 的 x 值可能偏移。

目標元素位於 iframe 內

  • get boxsnapshot -i 無法看到 iframe 內部。
  • 使用 eval 存取 iframe 內容:
    ab eval "document.querySelector('iframe').contentDocument.querySelector('<sel>').getBoundingClientRect()"
    
    注意:僅適用於同源 iframe。

open 成功但頁面內容錯誤

  • 瀏覽器可能已切換到不同的分頁(例如,彈出視窗或重新導向開啟了新分頁)。導航後務必驗證:
    ab eval "document.location.href"
    
  • 如果網址錯誤,使用 tab list 找到正確的分頁,並使用 tab goto <N> 切換。

螢幕截圖指令在字型上逾時

  • 某些頁面(例如 Google 開發者文件)在 document.fonts.ready 上掛起。先強制解析它:
    ab eval "document.fonts.ready.then(() => 'ok')"
    
    然後重試螢幕截圖。

頁面有延遲載入的內容

  • 在拍攝螢幕截圖前向下捲動以觸發載入:
    ab scroll down 1000
    ab wait 1500
    ab scroll up 1000