Playwright 評測:Chromium 的 JavaScript 渲染很強,但爬取層要自己補上

最後更新於 August 18, 2026
Playwright 評測:Chromium 的 JavaScript 渲染很強,但爬取層要自己補上
AI 摘要
Playwright 是 Microsoft 的瀏覽器自動化框架:一個以 TypeScript 為優先、採 Apache-2.0 授權的程式庫,能啟動真實瀏覽器,透過單一 API 操作,並在 JavaScript 執行完成後回傳頁面。官方把它定位成端到端測試框架,但很多人其實私下會拿它來處理這種情況:HTTP 請求只拿到一個空殼,真正的資料卻不見蹤影。從外觀上看,它和 Puppeteer、Selenium 是同一類工具——你操作的是真實瀏覽器,而不是解析 HTTP 客戶端回應。我用固定的一組抓取測試檢驗了 microsoft/playwright 1.56.0:包含有分頁的靜態目錄、文章頁、JavaScript 渲染目錄、JSON API、失敗的 500 回應、小型爬取圖,以及兩個公開練習網站;執行環境是 Node v22.22.3、macOS arm64,而且只測 Chromium。

Playwright 是 Microsoft 的瀏覽器自動化框架:一個以 TypeScript 為優先、採 Apache-2.0 授權的程式庫,能啟動真實瀏覽器,透過單一 API 操作,並在 JavaScript 執行完成後回傳頁面。官方把它定位成端到端測試框架,但很多人其實私下會拿它來處理這種情況:HTTP 請求只拿到一個空殼,真正的資料卻不見蹤影。從外觀上看,它和 Puppeteer、Selenium 是同一類工具——你操作的是真實瀏覽器,而不是解析 HTTP 客戶端回應。

我用固定的一組抓取測試檢驗了 microsoft/playwright 1.56.0:包含有分頁的靜態目錄、文章頁、JavaScript 渲染目錄、JSON API、失敗的 500 回應、小型爬取圖,以及兩個公開練習網站;執行環境是 Node v22.22.3、macOS arm64,而且只測 Chromium。渲染部分表現乾淨俐落。至於爬取部分,Playwright 根本沒有提供,而在真正投入使用前,這個缺口最值得先搞清楚。

亮點觀察

最上面的兩個結果最值得注意,而且它們各自指向不同的面向。

第一個是符合預期的瀏覽器結果,但仍受我設定的等待條件限制。當 page.goto(..., { waitUntil: 'domcontentloaded' }) 完成後,動態測試會等待 #dynamic-products article.product-card,公開的 Quotes to Scrape 測試則等待 .quote。這些應用專屬 selector 出現後,執行結果拿到了 8/8 個 fixture 項目與 10 則公開網站 quote;fixture 的召回率對八筆真實資料是 1.0。整個過程不需要自訂輪詢迴圈,但 Playwright 也沒有幫你消除「何時算準備好」這件事——完成條件仍然是測試自己提供的。第一次呼叫時,整頁截圖也成功儲存。

第二個結果使用了 browserContext.request:也就是在 Chromium 已經啟動、瀏覽器 context 也已存在後,直接呼叫 ctx.request.get(...)。它直接打到 fixture 的 JSON 端點,沒有建立或渲染頁面,就回傳了 8/8 個產品。這省掉的是 DOM 工作,而不是這個測試架構中的瀏覽器程序成本。和瀏覽器頁面綁定的 request client 可以共用 cookie 狀態;而獨立的 playwright.request.newContext() 不需要瀏覽器 context,但也不會自動共享該 session。本次只測了前者。

Playwright 也沒有內建爬取佇列、資料集寫出器,或自動節流。我的 crawl-graph 測試——沿著內部連結走訪、追蹤深度、避免重複造訪——最後跑到 12 個頁面,深度分布為 {0:1, 1:4, 2:7},但這個廣度優先遍歷是我自己寫的測試碼。Playwright 負責開頁與檢查頁面;前沿資料持久化、URL 規則、重試與排程,則屬於另一層。

Playwright 到底是什麼

這個工具——GitHub 上的 microsoft/playwright——以 TypeScript 撰寫,採 Apache-2.0 授權,由 Microsoft 維護。本次測試的版本是 1.56.0,時間為 2026 年 7 月 9 日。以下結果是針對這個版本的實測,不應視為對後續版本相容性的宣告。

官方定位非常明確:這是一個用來驅動 Chromium、Firefox 與 WebKit 的網頁測試與自動化框架,透過單一 API 進行操作。Playwright 的主線是測試執行器,內含 fixture、斷言與 trace viewer。若把它當成抓取原始碼的基礎元件,就要遵循官方文件中的 Library mode:先 chromium.launch(),再建立 context,接著建立 page,整個過程都在測試框架外進行。本次評測全部使用這組公開 API。我沒有做跨版本相容性測試,因此不能宣稱每個行為在不同版本間都完全一致。

官方文件提到的廣度,是它在其他工具中最醒目的賣點,所以我先講清楚:Playwright 透過單一 API 驅動三種瀏覽器引擎——Chromium、Firefox、WebKit——而且在 JavaScript 之外,還提供 Python、Java 與 .NET 的一級客戶端。這些都是文件明載的,也確實是它在結構上的最大差異。不過,本次實測真正涵蓋的範圍比較窄:

能力本次評測狀態
Chromium 引擎已測試——本文所有測試都在 Chromium 上執行
Firefox 引擎文件有說明,但本文未驗證
WebKit 引擎文件有說明,但本文未驗證
三種引擎共用單一 API文件有說明,但本文未驗證
Python、Java、.NET 客戶端文件有說明,但本文未驗證
代理設定未測試
多 context 並行規模未測試
用於 API-first 抓取的網路攔截未測試

如果目標在 Safari 的 WebKit 下呈現方式不同,或你的團隊主要使用 Python,那麼這種廣度就是 Playwright 的優勢——但不要把我的結果拿去當作 Firefox 或 WebKit 也完全一致的證據,因為我沒有測這兩者。

底層運作方式

你可以把它想成一個可被你操作的瀏覽器引擎。chromium.launch() 會啟動瀏覽器程序;context 是一個彼此隔離的 session,擁有自己的 cookies、儲存空間與快取;page 則是該 context 裡的一個分頁。你呼叫 page.goto(url),等待代表應用已就緒的條件,再用像 page.$$eval 這類 helper 讀取最後的 DOM。這比解析 HTTP 回應更接近使用者看到的瀏覽器,但它不是「環境完全一致」:headless 訊號、viewport、地區設定、字型、profile 狀態、TLS/網路路徑,以及網站防護機制,都可能改變實際拿到的內容。本次評測沒有測 anti-bot 行為,也沒有測與真實瀏覽器環境的完全一致性。

page.screenshot() 可以擷取已渲染的頁面,支援整頁或裁切範圍;這在我的執行中第一次呼叫就成功了。而前面提到的 request API——context.request.get——會沿用同一個 context 的 cookies,但不會渲染頁面,因此你可以在同一支腳本裡同時混用「載入頁面並讀取 DOM」與「直接打 JSON 端點」,不用切換工具。

但底層並不包含爬蟲基礎設施。它沒有請求排程器、已造訪集合的持久化、禮貌性節流政策或輸出管線。限制範圍的遍歷不難寫,但要做得可靠,還需要 URL 正規化、重導處理、重試、範圍規則、節流與復原。這一層要嘛自己建,要嘛用一個包住瀏覽器引擎的框架。

安裝與部署現實面

安裝分兩步,而第二步才是部署成本的大頭。npm install playwright 只會安裝程式庫;你還要另外執行 npx playwright install 來下載瀏覽器版本(我這次用的是 Chromium)。因此要預留磁碟空間、下載時間、CI 中的瀏覽器快取,以及程序清理機制,不能把 npm 套件本身當成完整可執行系統。

如果你安裝 Playwright 時以為它就是爬蟲,然後照著測試教學走,你一開始會接觸到 test file 和 expect() 斷言。真正用於抓取時,則是直接使用 library API。兩者文件都有,但在查範例與規劃部署指令時,這個差異非常重要。

在本次執行中,真正好用的體驗很具體:browser context 可以隔離 session 狀態、非同步呼叫很容易組合、截圖只要一行、HTTP 500 也能透過 response object 檢查。比較麻煩的是操作面而不是語法面:你必須另外安裝瀏覽器 build,並且自己管理它的生命週期,而不是讓程式庫包到底。

實測結果

實測結果圖:三種資料路徑的表現

所有本地數字都在 127.0.0.1 上的 fixture server 執行,且在抓取前就先寫下真實值。完整測試架構在 run_playwright_material_tests.mjs,而提交到版本庫的 原始成果 則包含真實資料與各測試輸出。這些都只是作者在單一機器、單次執行下的觀察;連結的目的,是提供可重現的範圍,而不是把它們包裝成廣泛的基準測試。

測試目標結果
靜態目錄 + 分頁本地 fixture12/12 個產品,召回率 1.0
文章擷取本地 fixture標題 + 3/3 段落,並分離保留樣板內容
動態 JS 頁面(原生渲染)本地 fixture8/8,召回率 1.0,已儲存整頁截圖
動態 JSON API(page.request本地 fixture8/8,召回率 1.0,未渲染 DOM
HTTP 500 處理本地 fixture可檢視 status 500,導航未拋錯
Crawl graph(手寫 BFS)本地 fixture12 個頁面,深度 {0:1, 1:4, 2:7}
Books to Scrape公開 demo20 個產品
Quotes JS(JS 渲染)公開 demo10 則 quote,原生渲染

分頁流程是明確跟著 next 連結走的;Playwright 不會自己幫你找下一頁。文章擷取時,selector 的設計讓導覽列與頁尾文字不會混進正文結果。遇到失敗路徑時,導航回傳的是 status 500 的 response object,而不是直接丟例外,讓呼叫端自行決定要記錄、重試還是繼續。兩個公開練習站點則回傳了表格中列出的數量。

有一個邊界值得直接說清楚:這裡所有內容都只在 Chromium、單一機器、單次執行下完成。能力表把文件上宣稱的廣度與實際測到的行為分開列出。我沒有在另一個 Playwright build 上重跑,因此不能推導出跨版本結論。每項測試的時間也沒有拿來當 benchmark;在單一筆電上跑一次秒錶,無法支持速度比較。

就緒狀態本來就是擷取契約的一部分

動態結果依賴的是代表目標資料的等待條件,而不只是瀏覽器導航本身。對本地目錄來說,測試流程先用 waitUntil: 'domcontentloaded' 導航,再以 15 秒 timeout 等待 #dynamic-products article.product-card。公開的 Quotes JS 執行也採用相同的導航狀態,並以 20 秒 timeout 等待 .quote。只有在那些 selector 出現後,才開始擷取。

在改寫腳本時,這個差異很重要。domcontentloaded 只表示初始文件已解析,並不代表延遲的 API 回應已抵達、hydration 已完成、無限滾動清單已停止增長,或虛擬化列表中的某一列已進入 viewport。當某個匹配元素出現就足夠時,selector 很好用;但如果完整性取決於已知回應、項目數量、應用狀態或網路安靜窗口,就應該改等那個條件。這個條件必須對齊你的輸出契約:「至少有一張卡片」和「所有預期頁面都載入完成」是完全不同的斷言。

系統圖:就緒狀態本來就是擷取契約

超時處理也應該由呼叫端負責。測試雖然用了有限的 selector timeout,但沒有研究重試策略,也沒有區分是頁面太慢,還是 selector 已永久改變。生產環境的 wrapper 應該記錄是哪個就緒條件失敗、擷取足夠的頁面狀態來協助診斷,並判斷是否還能安全重試下一次導航。Playwright 提供的是事件與 DOM,卻無法替你的工作定義「完整資料」到底是什麼。

這個邊界應該寫在每個 extractor 旁邊,而不是默默靠 timeout 來猜。

API 路徑也有類似的契約。ctx.request.get 之所以合適,是因為瀏覽器 context 已經存在,而共享 session 有時很有價值。若某個任務發現資料端點根本不需要瀏覽器 session,那麼獨立的 request context 就是另一種架構,生命週期與 cookie 行為都不同。本次沒有比較這兩種方式。請先把「沒有渲染 DOM」當成已觀測事實,再另外判斷整體流程是否真的需要瀏覽器程序。

爬取層的問題

crawl-graph 的結果,才是決定你該怎麼看 Playwright 的關鍵。12 個頁面、三層深度、結果正確——但所有走訪邏輯都是我自己寫的。Playwright 只負責「打開這個 URL 並讀取內容」;queue、visited set 和 depth tracking 都是我補上的。

如果是小而固定的工作,這沒什麼問題;但若是要做大規模爬取,就代表你不是在瀏覽器程式庫上寫爬蟲,就是得搭配一個已經做好爬蟲層的工具。文件中較典型的搭配是 Crawlee:它把 Playwright(以及 Puppeteer)包上一個真正的 request queue、dataset storage 與自動節流,你保留 Playwright 的渲染能力,並借用它的編排。如果你想要的是框架本身就內建 queue,而不是事後外掛,那就是 Scrapy 的整體設計;不過 Scrapy 是以 HTTP 為先,自己不會渲染 JavaScript。重點不是 Playwright 不夠好,而是「瀏覽器自動化」和「爬取」本來就是兩件事,Playwright 只主張其中一件。

系統圖:爬取層要你自己補

這個 12 頁 BFS 讓責任邊界更清楚:它為受控圖結構提供了 queue、visited set 與深度追蹤;但真正的 production frontier 仍然要定義 URL 正規化、redirect 處理、允許的 host、去重 key、重試、並發、每個 host 的延遲、持久化與重啟語義。輸出也是另一個選擇:fixture 之所以寫成 JSON 和 CSV,是因為測試架構這麼做,而不是 Playwright 自帶資料集抽象。

session 設計也會影響外層封裝。單一瀏覽器可容納多個 context,每個 context 的 cookies 與 storage 都是隔離的,但本次沒有量測多 context 的並行規模或故障隔離。重用同一個 context 可能保留登入狀態並減少初始化工作;建立獨立 context 則可能避免不同任務之間的狀態外洩。即使 Playwright 提供了 context 這個原語,這些仍然是爬蟲層面的政策。你應該在自己實際要部署的瀏覽器 build 與環境中,針對所選生命週期做基準測試。

優缺點整理

優點:

  • 透過真實 Chromium 引擎執行 JavaScript;兩個動態目標都成功到達作為就緒條件的 selector。
  • 第一次呼叫就成功擷取整頁截圖。
  • 使用 selector 從受控 fixture 中擷取靜態目錄與文章欄位,結果穩定。
  • browserContext.request 在不渲染頁面的情況下打到 JSON 端點,而已啟動的瀏覽器程序仍然是測試架構的一部分。
  • 遇到錯誤回應時表現穩健:HTTP 500 可檢視,導航也沒有拋錯。
  • 文件明載支援三種引擎(Chromium、Firefox、WebKit)與單一 API,並提供 Python、Java、 .NET 客戶端(文件有說明;本次只測 Chromium)。
  • Apache-2.0 授權,由 Microsoft 維護。
  • 一旦進入 library mode,開發體驗乾淨俐落:跨引擎單一 API、一流的非同步支援、截圖幾乎一行搞定。

缺點:

  • 沒有內建爬取 queue、dataset 或自動節流——要做大規模爬取得靠你自己寫,或搭配像 Crawlee 這類 wrapper。
  • 瀏覽器本身有重量:下載 binary 與每頁執行成本,確實比純 HTTP 工具高。
  • 預設敘事是測試執行器;若要拿來抓資料,得先知道 library mode 的存在,並離開官方主打路線。
  • 只測了 Playwright 1.56.0 與 Chromium;沒有驗證跨版本或跨引擎的一致性。
  • 沒有自帶 schema 化的結構化 JSON 輸出;selector 和資料形狀都得自己寫。

適合誰,不適合誰

如果你的問題是:頁面資料要等 JavaScript 跑完才出現,或你想一邊擷取 DOM 一邊收截圖,那 Playwright 是個值得對目標站點實測的候選方案。已經在用 Playwright 測試的團隊,也能直接把相同概念與 selector 技巧延伸到 library mode。Python、Java 與 .NET 客戶端雖然都是文件支援選項,但本次評測只跑了 Node 與 Chromium。

以下三種情況,建議考慮其他層。若所需資料本來就存在 HTTP 回應裡,HTTP-first 工具可省掉瀏覽器啟動與渲染成本;Colly 是這類爬蟲程式庫,而 Trafilatura 則偏向文章擷取。若你需要 queue、持久化與節流,請用爬蟲框架或 Playwright wrapper。若你想要的是 schema 化輸出,又不想維護 selector,那就比較各種代管擷取服務。本次評測沒有對這些替代方案做基準測試。

如果你特別在 Playwright 與 Puppeteer 之間猶豫,那就是另一個一對一比較;我們的 並排比較 會把兩者放進同一組 fixture 裡跑,並整理真正該如何選。

替代方案,以及代管擷取的定位

Playwright 是免費、Apache-2.0、且可自架的。這也代表你要自己負責瀏覽器部署、selector、就緒條件、爬取程式碼、更新與失敗處理。本次評測沒有量測 anti-bot 表現,也沒有比較和代管服務的總營運成本。

在開源工具中,實用的比較方式是按任務分類。若是需要以瀏覽器做大規模爬取,Crawlee 會補上 Playwright 沒有的 queue 與 dataset。若你的輸出目標是從真實瀏覽器直接產出可給 LLM 使用的 Markdown,而不是自己整理成欄位, Crawl4AI 會啟動瀏覽器並為該流程生成 Markdown。如果你一次要比較好幾個工具,我們的 開源爬蟲總整理 會把這些分類並排呈現。

揭露: Thunderbit 是發文方的產品,本次沒有透過這組 Playwright fixture 進行測試。它代表的是代管擷取類別:由服務本身負責渲染並回傳頁面文字或 schema 化紀錄,而 Playwright 則把瀏覽器操作與 selector 邏輯留給開發者。因此,這裡比較的是託管模式、輸出形式與成本模型,而不是本次評測中的效能結果。

試用 Thunderbit 進行網頁資料擷取

結論

當你的目標站需要瀏覽器引擎,且你也準備好自己負責就緒條件、selector 與爬取編排時,就該用 Playwright。本次結果表顯示,在作者實測的這一輪中,它的 Chromium library mode 對受控的靜態頁、動態頁、API、截圖與失敗案例都能如預期運作。

但請保留證據邊界:這次只測了 Chromium 與 Node;12 頁走訪依賴手寫 BFS;browserContext.request 雖然省掉頁面渲染,卻沒有省掉已經在跑的瀏覽器程序;所有動態擷取也都明確用了就緒 selector。這些限制讓 Playwright 在本篇評測裡是一個瀏覽器原語,而不是一個已被量測過的端到端爬取系統。

試用 Thunderbit 進行網頁資料擷取 Get Started Free

常見問題

用 Playwright 抓資料時,還需要等待條件嗎? 需要。瀏覽器執行並不會自動告訴腳本應用資料何時已準備好。這些測試先導航到 domcontentloaded,再等待目標專屬 selector 出現後才擷取。實際網站可能需要不同訊號,例如 response、locator 狀態,或應用事件。

Playwright 可以自己爬完整個網站嗎? 不能直接做到。它沒有內建 request queue、dataset writer 或自動節流——我的 crawl-graph 測試之所以能跑到 12 個頁面、深度 {0:1, 1:4, 2:7},是因為我手寫了廣度優先搜尋。若是要做大規模爬取,請把 Playwright 和 Crawlee 搭配使用,讓後者補上真正的爬取層,或直接使用爬蟲框架。

什麼時候該用 browserContext.request,什麼時候用獨立 request context? 當 HTTP 請求需要和既有瀏覽器 context 的頁面共用 cookies 時,就用 browserContext.request。如果你想要的是純 API 的 context,不啟動瀏覽器,且不需要和瀏覽器頁面自動共享 cookies,就用 playwright.request.newContext()。本次只測了第一種路徑。

這裡有測 Firefox 和 WebKit 嗎? 沒有。本文所有測試都在 Chromium、單一機器、單次執行完成。Playwright 的三引擎支援(Chromium、Firefox、WebKit)以及 Python、Java、.NET 客戶端,都是我依文件如實陳述,而非本次實測驗證;Firefox 與 WebKit 的一致性、代理設定、多執行緒規模與網路攔截都不在這組數據範圍內。

這篇評測涵蓋什麼環境? Playwright 1.56.0、Node v22.22.3、macOS arm64,且只測 Chromium。Firefox、WebKit、代理設定、並行規模、anti-bot 行為,以及後續版本的 Playwright 都不在這次執行範圍內。安裝時需要先裝程式庫,還要另外下載瀏覽器 build。

Ke
Ke
Thunderbit 技術長|資深資料科學家與機器學習專家 Ke Shen 在機器學習與資料科學領域擁有近十年經驗,畢業於哥倫比亞大學,曾任 Walmart Labs 資深資料科學家。他精通 Python、R、Java 與統計學,且具備深受同儕認可的深厚專業,分享如何將複雜的 AI 演算法從理論落實到可投入生產的架構的實戰見解。
目錄
Thunderbit · AI 網頁資料代理

一鍵 內擷取任一頁面的資料

深受 250,000+ 使用者信賴
提供免費方案
從網頁到試算表
描述你的需求——Thunderbit 的 AI Agent 會幫你抓取,並匯出到 Excel、Google Sheets、Airtable 或 Notion。可免費開始。
Chrome Store Rating
PRODUCT HUNT#1 Product of the Week