我建立了一個 fixture 測試站,來檢驗 Colly 中一個單看頁面數或速度口碑無法回答的問題:它的 callbacks 是否能擷取到預期資料、正確路由 HTTP 錯誤、依照限制邊界的 graph 前進,以及讀取渲染 HTML 之外所提供的內容。這次重點是正確性與邊界審視,不是吞吐量基準測試。
在受控的 fixtures 上,它擷取了所有預期的靜態資料,將一個 500 回應導向 OnError,並在設定的深度限制 graph 中造訪了 17 個 URL。對於兩個只有在 JavaScript 執行後才會出現元素的頁面,它回傳的目標元素數量都是 0。某個可直接存取的 JSON endpoint 在不使用瀏覽器的情況下仍然可用,這點很重要,因為這與渲染客戶端介面是不同概念。
Colly 到底是什麼

Colly 自稱是 Golang 的「優雅爬蟲與 crawler framework」,這個描述比表面看起來更貼切。它是一個 Go library——GitHub 上大約有 25,300 顆 stars、1,850 個 forks——採用 Apache-2.0 授權。它不是那種下載後直接丟一個 URL 就能跑的 CLI。你需要用 Go 開發、import Colly、註冊幾個 callbacks,然後把整套流程編譯成一個可執行檔。
它的心智模型是事件驅動。你把 handlers 掛在 Collector 上:OnHTML 會針對符合的 CSS selector 執行擷取邏輯,OnResponse 提供原始 response body,而 OnError 負責處理 request 失敗。link handler 會對找到的 URL 呼叫 Visit(),而 MaxDepth 則用來限制 traversal 深度。對於這些純 HTTP 路徑,目標主機不需要另外安裝 Go runtime 或 browser;至於產出的 executable 是否完全靜態,則取決於 build flags 與 CGO 的使用情況,而這次測試沒有記錄這些資訊。
主要功能,以及它們在底層如何運作

callback 模型是理解 Colly 的關鍵,因為這也是它和一般 request-and-parse script 感覺不同的原因。我這次測試的每一項,都靠三個 callback 撐起來。
OnHTML(selector, handler) 是主力。把它註冊在 .product 或 article p 上後,Colly 會在解析 DOM 時,針對每個匹配元素各執行一次 handler。結構化擷取就是在這裡完成的,而且語意很清楚——你在描述要抓什麼,而不是手寫一整段 parse loop。
OnResponse(handler) 層級更低一點,會直接給你原始位元組。當目標回傳的是 JSON 而不是 HTML,你就可以完全跳過 DOM,自行 unmarshal body。正因為有這個 callback,我在測試中才能讓 Colly 直接處理 JSON API,而完全不需要任何 HTML parsing。
OnError(handler) 負責 request 失敗,也能把 response status 提供給呼叫端。在這次測試裡,一個 status 500 的 fixture 回應成功進入了註冊的 callback。Retries、timeout、DNS failure、connection reset、callback panic、persistence 與 alerting 都沒有測試。
除了 callbacks 之外,還有兩個實務特性。MaxDepth 會依照 Colly 的深度語意限制 link traversal。編譯好的 Go executable 也免去了目標主機上另外安裝語言 runtime 的需求。不過這次執行沒有記錄 build flags 或 CGO 狀態,所以不能據此宣稱每個輸出的 binary 都是完全靜態連結。
安裝前要知道的:需要 Go 工具鏈
依賴關係不長,但確實存在,所以在安裝任何東西之前先講清楚。我測試的機器原本沒有安裝 Go,而 Colly 又是 Go library——因此第一步就是先把 Go toolchain 裝上去(我透過 Homebrew 安裝了 Go 1.26.5)。如果你的團隊本來就不是在 Go 環境裡工作,真正的摩擦點其實不是 Colly 本身,而是它在編譯前就要求具備的語言環境。
Go 裝好之後,go get github.com/gocolly/colly/v2 解析到的是 v2.3.0。測試流程不需要 browser 或 headless Chrome。
有一個版本資訊容易讓讀者困惑。Go module 解析到的是 v2.3.0(2025 年 12 月發布),但我查看時,GitHub Releases UI 上最新可見的是 v2.2.0(2025 年 3 月)。這裡的差異是 module/repository version 與 GitHub Release entry 的不同,不是 module 與 Git tag 的差別。我測試的是 v2.3.0。
實測:擷取效果與操作邊界

我把 Colly 跑在一個自包含的 fixture server(Go 的 httptest)以及兩個公開 demo site 上。現有的 benchmark directory 和 results/colly-test-summary.json 雖然公開了產物,但兩個連結都指向會變動的 branch。文章本身沒有提供已測試的 commit、精確指令、build flags 或 fixture seed,因此目前還不能算是不可變的重現步驟。
| 測試 | 目標 | 結果 |
|---|---|---|
| 靜態目錄 + 分頁 | 本地 fixture | 擷取到 12/12 筆預期產品 |
| 文章擷取 | 本地 fixture | 標題 + 3/3 段落 |
| 直接 JSON 回應 | 本地 fixture | 透過 OnResponse 擷取到 8/8 筆預期項目 |
| HTTP 500 處理 | 本地 fixture | 路由到 OnError,status 500 |
Crawl graph(MaxDepth 2) | 本地 fixture | 17 個頁面 |
| Books to Scrape | 公開 demo | 20 個產品 |
| 動態頁面(無 JS) | 本地 fixture | 0 個卡片(符合預期) |
| Quotes JS(未渲染) | 公開 demo | 0 個(符合預期) |
在受控的靜態 fixtures 上,設定好的 selector 成功產出 12/12 筆預期產品資料,以及全部 3 段預期文章段落。直接的 JSON 回應完全沒有經過 HTML parser:OnResponse 直接提供 body,而測試框架將 8 筆預期資料全數 decode 出來。那個單一的 500 fixture 進入了 OnError,並且 status 也被帶出來,而且這次執行沒有當掉;但這不代表它在無人值守情境下就一定可靠。至於公開的 Books to Scrape 頁面,selector 則抓到 20 個產品,作為公開網站的基本 smoke test。
在 traversal 方面,collector 以測試框架的 seed-depth 慣例設定為 MaxDepth(2),並在 fixture graph 中造訪了 17 個 URL。這個結果代表的是 crawl coverage,不是速度。實際觀察到的 trace——不是對任意 graph 的廣泛宣稱——可在 results/local_crawl_graph.json 中查看。

Colly 不會執行 JavaScript。那個以 JavaScript 渲染的 fixture 產生了 0 個目標卡片,而公開的 Quotes to Scrape JS page 也產生了 0 則目標 quotes。若元素只會在 browser 執行之後才出現,而且又沒有可直接存取的後端 endpoint 提供資料,那麼這條純 HTTP 路徑就看不到那些元素被渲染後的 DOM。做法要嘛是搭配 renderer,要嘛在有可用 endpoint 時直接呼叫背後的資料來源,像這次 JSON fixture 所示。
我沒有測試 async collector、rate limiting 或 politeness 設定、proxy rotation、retries,或 queue 與 storage backend。也沒有量測耗時、吞吐量、concurrency、CPU、memory、目標延遲或比較基準。因此這篇文章不做速度或無人值守可靠性的宣稱。
如何解讀這些 fixture 結果
三條成功的內容路徑,其實在測試三種不同的契約。目錄與文章案例是在測試伺服器回傳 HTML 上的 CSS selection。它們的分母是擷取前就寫好的 fixture 期望值:12 筆產品與 3 段文章。把結果描述成「擷取到預期資料」是刻意為之。這次執行沒有定義模糊比對、重複項處理、部分欄位容錯,或全資料集層級的 recall 指標,所以不應把它直接升格成一般性的擷取準確率。
JSON 案例則跳過了 DOM selection。Colly 透過 OnResponse 接收到 response bytes,而 JSON decode 則由測試框架處理。這也說明了為什麼「Colly 不會渲染 JavaScript」不等於所有依賴 client 的網站都抓不到。如果 client 使用的資料來源本身是可直接呼叫的 endpoint,而且這個 request 在瀏覽器外也能重現,那麼 HTTP crawler 仍然可能足夠。Authentication、動態簽章、只存在於瀏覽器中的狀態,以及 anti-bot 機制,都可能改變答案;這次都沒有測試到。
那個 500 路由測的是 dispatch,不是 recovery。它只能證明註冊的 OnError callback 收到了該 fixture 回應與其 status。真正上線的 crawler 仍需要針對可重試狀態碼、backoff、終止性失敗、持久化與 alerting 制定明確政策。這次測試沒有提供這些選擇的證據,而「callback 有被觸發」不能被解讀成「這個 job 可以安心無人看管」。

17 個 URL 的 graph 也同樣是窄範圍結果。它只確認了在這個 fixture、這種 seed 慣例與 MaxDepth(2) 下所產生的 visited set。它不能證明每秒頁數、公平性、記憶體增長,或在 cycle 與重複 URL 形式上的行為。這些都需要另外的 workload 與 queue 測試。
以這次實測為基礎的選型清單
先看 Colly 實際收到的 response 是什麼。如果必要欄位已經存在於伺服器回傳的 HTML 中,就用 OnHTML,並在接受資料前先驗證欄位數量或必要 key。如果回應是 JSON,就透過 OnResponse 處理 body,並驗證 schema。如果 HTML 只是 application shell,就先檢查是否存在可直接呼叫的後端 request 能拿到資料,再考慮加 browser。
| 回應內容 | Colly 路徑 | 驗收檢查 |
|---|---|---|
| 伺服器回傳的 HTML 中已包含必要欄位 | OnHTML selectors | 必要 key 與預期資料筆數 |
| 可直接呼叫的 JSON payload | OnResponse 加上 JSON decoding | schema 與必要欄位驗證 |
| 由可重現 request 支撐的 HTML shell | 請求背後的 endpoint | 回應狀態、schema 與完整性 |
| 只有在 browser 執行後才產生的資料 | 加 renderer 或改用 browser crawler | 目標特定的 readiness 與完整性 |
當真的需要 browser 執行時,應把它視為另一個元件,而不是期待 Colly 某個 flag 就能開啟 rendering。browser 必須先完成 readiness、暴露渲染後內容或後端回應,並把資料送進後續 pipeline。這次審視沒有測試這樣的整合。
若要部署,請記錄 Go version、module version、build flags、CGO 狀態、精確指令、fixture seed,以及 repository commit。這些資訊在目前的公開連結中都缺失,而這正是可檢視的產物與可長期重現之間的差別。若要用於營運,請先建立 failure matrix,並針對真正關心的 workload 做量測,再來談系統快不快、穩不穩。
優缺點
優點:
- 透過
OnHTML擷取到 12/12 筆預期目錄產品與 3/3 段預期文章段落。 - 透過
OnResponse做到乾淨的 JSON 處理,不需要 DOM parsing——8/8 筆 API 資料。 - 測試中的 500 回應成功進入
OnError,並且 status 可見。 - 單一 collector 就能完成深度限制的 crawl,並到達 17 個頁面。
- 可編譯成 Go executable;對於測試過的路徑,目標端不需要另外安裝 Go runtime。
- 採用寬鬆的 Apache-2.0 授權。
缺點:
- 不支援 JavaScript 執行——需要 client 渲染的內容就是 0,沒有例外。
- 需要 Go toolchain;非 Go 團隊在開始寫任何爬蟲前就得先承擔這個安裝成本。
- 測試的 module(
v2.3.0)比我當時看到的最新 GitHub Release entry(v2.2.0)還新。 - 產出是你自己的程式碼——Colly 給你的是 callbacks,不是像 Scrapy 那樣內建的資料集/匯出器。
- async、rate limiting、proxy 與 queue backend 雖然存在,但這裡都沒測到;吞吐量與規模表現仍未知。
適合誰——以及誰該跳過

如果你本來就用 Go,且目標是伺服器端渲染的 HTML 或可直接存取的 JSON,Colly 很合適。callback 模型把結構化匹配、原始 payload 與 request failure 分開處理。編譯後的 executable 也能免去目標機器上另外安裝語言環境的需要,雖然這裡沒有驗證是否為完全靜態連結。
如果目標元素只會在 browser 執行後出現,而且沒有可用的後端 endpoint,就該加入 renderer。直接的 JSON endpoint 在不渲染的情況下仍然可以請求。對於不想碰 Go toolchain 的團隊,或希望由抽取服務直接負責 schema shaping 與 selector 維護的團隊,Colly 也不是最合適的選擇。
替代方案,以及 Thunderbit 的定位
Colly 是你自己部署與維護的開源軟體。它沒有廠商使用費,但 compute、bandwidth、proxy、storage、observability 與工程維護成本都由你承擔。若目標需要 rendering,request 行為、parse callbacks、crawl 邏輯與 browser 整合也都要你自己處理。
managed extraction service 會把部分責任轉交給供應商。我們打造的是 Thunderbit,但這次沒有拿它和這些 fixtures 做測試,所以本文不做 rendering、anti-bot、品質、延遲或成本比較。能確認的差異在於責任歸屬:Colly 會在你的 Go 程式裡把 HTTP response 與 callbacks 暴露給你;managed service 則可以代管 acquisition 與 schema shaping,按次收費。
相關 benchmark 評測: 完整的開源爬蟲比較、Scrapy 的 Python crawler 評測、以及 Scrapling 的自適應 selector 評測。
結論
對於使用 Go、目標是伺服器端渲染 HTML 或直接 JSON,且願意自行負責擷取程式的團隊來說,Colly 是不錯的候選。這些 fixtures 證明了它能擷取預期資料、完成一條受限制的 crawl trace,並處理一次 500 callback——但不代表速度、規模或無人值守可靠性。若沒有可直接呼叫的底層資料 endpoint,browser-rendered DOM 仍需要另一條路徑。
試用 Thunderbit 進行網頁資料擷取 Get Started Free
常見問題
這篇評測有量測 Colly 的速度嗎? 沒有。它量測的是預期資料擷取、直接 JSON 處理、一次 error callback,以及 fixture crawl graph 的覆蓋情況。沒有量測耗時、吞吐量、concurrency、CPU、memory 或比較基準。
Colly 可以抓 JavaScript 渲染的頁面嗎? Colly 不會執行頁面的 JavaScript。因此測試中的 HTTP 路徑找不到那些只會在渲染後 DOM 才出現的目標元素。不過它仍然可以直接請求可存取的後端 JSON endpoint,像這次的 JSON fixture 所示。若必須執行 browser,而且沒有可重現的後端 request 提供資料,就應該使用 renderer。
使用 Colly 一定要懂 Go 嗎?
是的。Colly 是 Go library,不是獨立 CLI——你要 import 它、註冊 callbacks(OnHTML、OnResponse、OnError),然後編譯。我的測試機器原本沒有 Go,所以一開始就得先安裝 Go toolchain(1.26.5)。如果你的團隊本來不在 Go 環境裡,這個環境本身就是主要的 setup 成本。
為什麼我安裝的版本和 Colly 最新 GitHub release 對不上?
Go module 解析到的是 v2.3.0(2025 年 12 月),而我看到的最新 GitHub Release entry 是 v2.2.0(2025 年 3 月)。我測試的是 v2.3.0;這只是不同版本顯示面的差異,不代表安裝壞掉。
Colly 可以免費商業使用嗎? 可以,它採用 Apache-2.0,授權寬鬆,對商業使用相當友善。不過,和往常一樣,在正式採用前,請先到 repo 確認目前的授權狀態。
在導入 production 之前,應該加入與實際營運風險相符的測試,而不是把 fixture 結果類比延伸出去。要對代表性目標做重複 crawl 的耗時測試,記錄 CPU 與 peak memory,測試可重試與不可恢復的失敗,並在 concurrency 下驗證 politeness。如果 persistence 很重要,就要在檢查重複處理與 queue 狀態的同時停止並恢復 crawl。如果部署簡化很重要,就要記錄精確的 compiler 與 linker 設定,並檢查產出 executable 的 runtime dependencies。這些檢查不會改變目前 fixture 已證明的事;它們決定的是,同樣的 library 設定是否適合某個特定的 production 任務。


