從 Hacker News 首頁取前五則標題,再開第一則留言,兩套工具拿到相同的五則資料和留言網址。agent-browser 先回一棵很大的頁面快照,再從中找操作目標。Playwright 可以在腳本裡直接檢查筆數和留言 ID,之後每次照同一套規則跑。
實測環境:Debian 12 容器、Node.js 22.23.4、agent-browser 0.42.0、Playwright 1.65.0,2026-11-10。
| 核對項目 | agent-browser | Playwright |
|---|---|---|
| 首頁輸出 | 快照定位,再用 eval 取得五筆 |
腳本直接取五筆標題與網址 |
| 留言驗收 | 點擊後用 get url 讀目前網址 |
點擊後用 waitForURL 核對第一則 ID |
| 單次擷取、點擊及截圖 | 3.925 秒 | 1.836 秒 |
| 開到哪裡 | /item?id=50436640 |
/item?id=50436640 |
先分清楚這裡比較的是哪一層
這篇實測的是 Vercel 的 agent-browser CLI,另一邊是用 Node.js 呼叫 Playwright JavaScript API 的小程式。CLI 適合把瀏覽器動作拆成終端指令,先讀頁面再決定下一步。JavaScript API 讓你把同一份規則寫成程式,重跑時能接上自己的輸出與錯誤處理。Playwright CLI、Playwright MCP 和 Playwright Test 是別的入口。看到「Playwright」的比較,先確認對方用哪個入口,因為模型收到的資料和失敗回報方式會跟著變。 agent-browser 指令 · Playwright API
agent-browser 從快照找出要點的連結
安裝時用 npm install agent-browser 和 npx agent-browser install。第一次把 --args=--no-sandbox 放在子指令前,CLI 回傳 Unknown command: --args=--no-sandbox。拿掉該參數後順利開頁。以下從安裝套件的目錄執行。
npx agent-browser open https://news.ycombinator.com/
npx agent-browser snapshot
npx agent-browser eval 'Array.from(document.querySelectorAll("tr.athing")).slice(0,5).map(row => { const link = row.querySelector(".titleline > a"); return {id: row.id, title: link?.textContent.trim(), url: link?.href}; })'
完整快照以 wc -lc 量得 691 行、26,626 位元組。快照能找到要點的連結,擷取結果則只需要五則的 ID、標題、網址。已經知道欄位時,可以縮小快照的範圍,或只把 eval 擷取出的結果交給下一步。上述數字只描述這份快照,跟模型的 token 計量分開看。 agent-browser 指令參考

在快照裡找到第一則標題下的 comments 或 discuss 連結。把下方的 @e12 換成這次快照給的參照。頁面重載後就重新讀一次快照。點擊後看 get url,確認網址走到 Hacker News 的 /item,而且 id 等於剛剛第一筆的 ID。
npx agent-browser click @e12
npx agent-browser get url
npx agent-browser screenshot hn-agent-comments.png
npx agent-browser close
Playwright 把首頁和留言檢查寫進同一次執行
原實測用 npm install playwright,再在 Debian 安裝 Chromium 及依賴,指令是 npx playwright install --with-deps chromium。原腳本啟動瀏覽器後會先檢查首頁回應,取五列,再用第一則 ID 定位留言連結。原本的終端輸出如下。
Discussion: https://news.ycombinator.com/item?id=50436640
Elapsed ms: 1836

原始終端機輸出重新排版,保留標題、網址和耗時。
要重跑,將下面的範例存成 hn-check.mjs,在裝好 Playwright 的資料夾執行 node hn-check.mjs。範例會輸出當下的五筆資料,並以當下第一則 ID 驗收,舊 ID 用來對照原始紀錄。如果 8 秒內沒有等到預期的留言網址,錯誤訊息會附上預期 ID 和目前網址。
新聞標題可能連到站外。程式會在首則新聞的下一列另外找留言連結,要求連結文字是 discuss 或留言數。若出現 No unique comments link for story one,先核對下一列的結構與連結。這時點擊還沒執行,拉長網址等待時間也不會找到缺少的連結。
import assert from 'node:assert/strict';
import { chromium } from 'playwright';
const home = 'https://news.ycombinator.com/';
const browser = await chromium.launch();
try {
const page = await browser.newPage();
const response = await page.goto(home, { waitUntil: 'domcontentloaded' });
assert.ok(response?.ok(), 'Could not load Hacker News');
const posts = await page.locator('tr.athing').evaluateAll(rows =>
rows.slice(0, 5).map(row => {
const link = row.querySelector('.titleline > a');
return { id: row.id, title: link?.textContent.trim(), url: link?.href };
})
);
assert.equal(posts.length, 5, 'Expected five stories');
assert.ok(posts.every(post => post.id && post.title && post.url),
'A story is missing an ID, title or URL');
const [first] = posts;
const comments = page
.locator(`tr[id="${first.id}"] + tr a[href="item?id=${first.id}"]`)
.filter({ hasText: /^(discuss|\d+\s+comments?)$/i });
assert.equal(await comments.count(), 1, 'No unique comments link for story one');
try {
await Promise.all([
page.waitForURL(url =>
url.origin === new URL(home).origin &&
url.pathname === '/item' &&
url.searchParams.get('id') === first.id,
{ timeout: 8000 }
),
comments.click()
]);
} catch (error) {
throw new Error('Expected discussion ' + first.id + ', reached ' + page.url(), { cause: error });
}
console.log(JSON.stringify({ posts, discussion: page.url() }, null, 2));
await page.screenshot({ path: 'hn-comments.png' });
} finally {
await browser.close();
}
若要改測「第一則有可用討論連結的新聞」,兩套流程都要套用這個新規則。首頁標記若改版,先確認 tr.athing 和 .titleline 仍指向新聞和標題。 Playwright Locator · Playwright 的 waitForURL

頁面變動後,哪一步會抓到失敗
補測用一個本機頁面固定五則資料,兩邊用同一個 Chrome 版本,每個案例開新的工作階段。一組是基準,另兩組各只改一個條件。
補測環境:Windows、Node.js 24.14.0、Chrome 156.0.8078.80、agent-browser 0.42.0、Playwright 1.65.0,2026-11-10。這組結果與前面的 Debian 計時分開。
| 本機頁面狀態 | agent-browser 看到什麼 | Playwright 在哪一步停下 |
|---|---|---|
基準,首則留言應為 101 |
取到五筆,點擊後 get url 的網址帶 id=101 |
取到五筆,waitForURL 通過 |
只把新聞列 class 從 athing 改為 story-card |
快照還能找到 Comments 101,舊 eval 回傳空陣列 |
tr.athing 定位得到 0 筆,筆數檢查在點擊前中止 |
連結保留 item?id=101,伺服器用 HTTP 302 轉到 999 |
click 成功,讀最後網址才知道 999 和首則 101 不符 |
取到五筆,但等 101 的 waitForURL 逾時,最後網址是 999 |

快照找得到連結,擷取卻是零筆
壞掉的是兩邊原本依賴的 CSS 查詢。遇到這種情況,先看快照還有哪些欄位,再比對新的頁面結構。若任務約定要有五筆,就把筆數當成檢查。agent-browser 的呼叫端可以在資料回傳時核對。Playwright 範例把它寫進腳本,遇到零筆直接停下。
點擊成功,目的地卻錯了
agent-browser 要把點擊後的 get url 和首筆 ID 比對,才能發現走錯。Playwright 的 waitForURL 預期 101,在設定的 2.2 秒內沒有等到,拋出 TimeoutError。這時再讀目前網址,就能分辨「到了錯的頁面」和「一直停在首頁」。
工作交接時該留下什麼
| 工作 | 先用什麼 | 留下的證據 |
|---|---|---|
| 第一次探索陌生頁面 | agent-browser 先看快照,找到欄位和可點連結再縮小輸出 | 擷取結果、點擊後網址;遇到改版先保留新快照 |
| 每天重跑、結果要交給另一個流程 | Playwright 把必備欄位、筆數和目的網址寫成固定檢查 | 失敗條件、預期值、實際值,必要時加截圖 |
| 已有 agent-browser 流程且規則明確 | 由呼叫端核對 eval 的筆數與 get url 的 ID |
分開記錄沒資料和點錯頁,避免當成成功交付 |
如何解讀原測試的兩個秒數
當天兩套工具各開一次新瀏覽器,取到相同五則,順序一致。第一則是「Amazon saves millions by replacing Sonnet 4.6 with Strands Decider」。比對網址時,光核對 /item 路徑會漏掉點錯新聞的情況,還要核對擷取結果的第一筆 ID。兩個秒數包含抓資料、點擊和截圖,安裝、撰寫腳本及模型讀取輸出的時間各自排除。要判斷哪套更穩或長期更快,要用相同條件多跑幾輪,連失敗和重跑時間都記下來。
如果輸出要直接寫進資料庫,我會把「沒有抓到資料」和「今天確實沒有資料」分開。對首頁固定取五筆這種工作,零筆要讓呼叫端停下。對允許空結果的搜尋工作,我會加一個頁面提供的空狀態訊號,例如明確顯示「找不到結果」,兩個訊號相符才交付空清單。
登入狀態、隔離與失敗證據
公開的 Hacker News 和本機測試頁都不用登入。若要把流程用在自己的帳號頁,先決定第一次登入由誰做、後續要不要沿用狀態。agent-browser 可用有名稱的工作階段隔離操作,切任務時先確認使用的是哪個工作階段;Playwright 可從新 context 開始,需要沿用登入時再載入已授權的 storage state。登入檔可能帶 cookie 與其他可重用的資料,應放在私有位置。這篇沒有測登入、多因素驗證或跨站帳號。 agent-browser 指令 · Playwright 登入狀態
要交給下一個人接手,先保留發現問題時的頁面狀態。CLI 端可留下最新快照、擷取筆數及目前網址;如果舊的參照失效,先看新的快照再決定是否重找連結。Playwright 可在建立 context 後開啟 tracing,留下各步驟的快照、請求與頁面錯誤,事後用 Trace Viewer 找第一個偏離預期的動作。追蹤檔也可能包含頁面資料,分享前和原始登入狀態一樣要核對內容。這次補測實際交付的是 URL、錯誤及畫面,Trace Viewer 是後續排查選項。 Playwright Trace Viewer
改版後若發現零筆,先比較新快照和已知規格。這次可見連結仍在,所以先查新聞列的 class,而不是重裝瀏覽器。要是頁面上已有穩定的連結名稱或測試 ID,可以改用那個訊號。若確實需要 DOM 的結構才能取資料,就維持 selector,但要讓它找不到資料時立刻報錯。修完先跑基準頁和改版頁,再驗一次錯誤轉址,確認修正沒有讓目的地檢查放寬。
怎麼比較輸出和執行成本
若只需要找可互動的連結,可用互動元素快照。若需要檢查頁面上沒有按鈕的說明文字,則要保留能看到那段內容的輸出。 agent-browser 快照指令
CLI 的輸出位元組不能直接換算成 token,也不能拿 Playwright 程式只印出的五筆 JSON,和 agent-browser 傳給模型的整頁快照當成同一種工作。要比 token,固定同一個模型與任務,記錄真正放進請求的提示、快照、重試和工具結果。若整個程序已由程式決定,模型可能根本不用讀快照。原實測量的是工具輸出和操作耗時,沒有量模型帳單。
排程每天跑時,錯誤的目的頁若通過驗收,就可能把別則新聞的資料交給下游。保留預期與實際值可以直接判斷要改 selector,還是找被改寫的轉址規則。要量執行成本,可讓兩邊都從新的瀏覽器工作階段跑同一批任務,分開記開啟、擷取、驗收、截圖和失敗重試。若想另外比沿用工作階段的速度,就另做一組,別跟全新啟動混算。
何時選別的方案
如果手上已有 Puppeteer 專案,原本的程式能控制 Chrome 或 Firefox,並有可靠的測試和紀錄,先補上缺少的檢查就能回答眼前問題。要把瀏覽器檢查放進整套自動測試時,可把這篇的驗收條件寫成 Playwright Test 的斷言,讓失敗與其他測試一起管理。若你需要在程式裡用自然語言指定瀏覽器動作,Stagehand 提供對應的介面,仍須自行決定如何驗收結果。這三個選項的能力來自文件,本次沒有拿它們跑同一組任務。 Puppeteer 文件 · Playwright Test · Stagehand 文件
若任務需要可控的登入帳號、保存工作階段或代管瀏覽器,先問清楚狀態放在哪、誰能取用、失敗時會交付什麼。實際費用要依選定服務查運算、瀏覽器時間和模型計價。這次都在本機用公開或受控頁面完成,沒有量代管服務,也沒有測網站的反自動化規則。