Katana 是 ProjectDiscovery 的端點發現爬蟲——一個以 Go 撰寫、採用 MIT 授權的二進位工具,輸入目標後會輸出 URL 與端點,交給管線中的下一個工具使用。它可以在不啟動瀏覽器的 HTTP 模式下爬取,也可以用 -headless 由 Chromium 執行頁面。官方文件把 headless 描述成涵蓋率較高的選項;而這個測試樣本則顯示,端點的「類型」和「數量」同樣重要。
我搭了一個小型網站,刻意設計出三種不同的端點類別,並在 v1.6.1、-d 4 的條件下測試每種模式能抓到哪些端點。一般 HTML 在四種設定下都能抓到 4/4 連結,以及完整的三跳鏈結。差異出現在透過 JavaScript 原始碼暴露的端點,以及執行時 DOM 變動產生的端點。
在這個樣本中,headless 找到了瀏覽器模式未命中的「執行時 DOM」類別;而標準模式搭配 -jc 則找到了兩種 headless 都漏掉的 JavaScript 檔案字面值。四種指令組合裡,沒有任何一種同時覆蓋這兩類。範圍、續跑,以及 known-files 的行為,則提供了其他實務上的邊界。
Katana 到底是什麼
Katana 爬蟲——GitHub 上的 projectdiscovery/katana——是用 Go 寫成,採 MIT 授權。我在 2026 年 7 月 27 日測試的是 v1.6.1;版本之所以重要,是因為下面關於涵蓋率與 known-files 的結果,都是特定版本的實測觀察。
這裡的分類標籤比平常更關鍵。端點發現爬蟲不是欄位擷取器。如果你要的是一個 Go 網頁爬蟲,能把商品名稱與價格整理成結構化 JSON,Katana 根本不是那個用途——它會很樂意告訴你 /products/1138 存在,卻完全不會告訴你那個頁面裡有什麼。這正是它的設計;拿它的擷取能力來評價它,就像拿金屬探測器去評估珠寶鑑定一樣不對題。
它真正的主場是攻擊面盤點與自動化管線:從 STDIN 餵資料,往外吐 URL,再丟給下一個工具。也因此要先講明白一個限制:我這裡所有測量都只針對我自己寫的、位於 127.0.0.1 的本機樣本。請只把 Katana 用在你擁有,或已獲書面授權測試的主機上;除此之外都不行。這篇內容不是在講如何繞過防禦,而是在量化某個命令實際枚舉了多少網站端點。
三種模式,各自能看見什麼
標準模式就是 Go 的 HTTP client。它會抓取頁面、解析 HTML、追蹤 href,但完全不啟動瀏覽器。速度快、成本低,但對所有必須等 JavaScript 跑完才出現的內容都看不見。
-jc(-js-crawl)是在這條不啟動瀏覽器的路徑上再接上一個 JavaScript 解析器。它會下載連結的 .js 檔,從原始碼裡抓出長得像 URL 的字串常值;不執行,只讀取。README 裡也提到 -jsl(jsluice),那是一個更重、記憶體更吃重的解析器——我沒有測它,所以不評論它是否會改變涵蓋率結果。

-headless 會驅動 Chromium,執行頁面腳本。在這個樣本裡,它是唯一一種能找回「由片段組裝、再注入 runtime DOM」的 Katana 模式。這個結果不能推論成所有解析器,或未來任何 Katana 模式,都會得到相同結果。
接下來是範圍模型;如果要用在正式環境,這是我會在輸入任何東西之前先記住的部分。
| 旗標 | 控制什麼 | 值 / 預設 |
|---|---|---|
-fs(field scope) | 哪些主機納入範圍 | dn、rdn、fqdn,或自訂 regex —— 預設為 rdn |
-cs 和 -cos | 在該 field scope 內,進一步過濾 URL 的 regex | — |
-kf | known files:robots.txt 與 sitemap.xml | README 指出至少需要 depth 3 |
-d | 深度 | 預設 3 |
-resume | 從中斷的爬取續跑 | — |
這個順序不是裝飾:它會決定某個主機 regex 是會擴大爬取範圍,還是悄悄把結果清空。
安裝:一個二進位,外加一個例外
有三種進入方式,其中只有一種需要 toolchain:
| 安裝方式 | 前置需求 |
|---|---|
從原始碼安裝:go install github.com/projectdiscovery/katana/cmd/katana@latest | 官方要求 Go 1.25 或更新版本 |
| Release 頁面的預編譯二進位檔 | 不需要 toolchain |
| Docker 映像 | 不需要 toolchain |
我這邊安裝後的位置是 ~/go/bin/katana,每次執行都會回報 Current version: v1.6.1。到目前為止,典型的 Go 好消息:單一檔案,無執行期依賴。
例外在於 headless:瀏覽器是獨立於二進位之外的另一個前置條件。
-headless 在哪裡執行 | 需要什麼 |
|---|---|
| 我的機器 | Katana 自動偵測到已安裝的 Chromium;我沒有記錄瀏覽器版本,也沒有手動提供 browser path |
| 專案官方 Ubuntu 指南中的裸機伺服器 | 先執行 apt install google-chrome-stable,headless 才能運作 |
| Docker 路線 | 以 -system-chrome 執行 headless |
在一台裸機伺服器上,這種便利性就不見了。只要 -headless 進了你的命令列,就要把瀏覽器成本一起算進去,而不只是二進位。
如果你在 CI 裡跑,還有一個小細節值得注意:Katana 啟動時會對 GitHub 發一次版本檢查請求。-duc 可以把它關掉。筆電上這只是噪音;但在離線或受限流的執行環境裡,這是你原本沒打算要的每次執行一次的網路往返。我這裡的計時測試都加了 -duc,讓數字只反映爬取本身,而不是回呼 GitHub 的時間。
我怎麼測的
我刻意選了三種會把各模式分開的端點類別。所有內容都放在一個 本機樣本伺服器 裡,而 ground truth 是在任何爬取開始之前就先寫好的,因此回憶率是對照固定集合來算,而不是看 Katana 最後印了什麼。
- Class A — 純 HTML。
/page/a、/page/b、/page/c,外加一條三跳鏈/depth/1 → /depth/2 → /depth/3。任何爬蟲都應該抓得到。 - Class B — JavaScript 檔案字面值。
/api/js-endpoint-7與/api/js-endpoint-8只以字串常值的形式存在於連結的/static/app.js之中。如果有工具願意讀 JS,不用瀏覽器也能看到。 - Class C — 只在 runtime DOM 出現。 一個路徑是由執行時組裝的片段(
'endpoint' + (6 * 7))構成,再由腳本插入 DOM。字串/runtime-only/endpoint42在伺服器送出的任何 byte 裡都不會連續出現——HTML 裡沒有,JS 原始碼裡也沒有。只有執行才看得到。
另外還有 robots.txt、一個包含兩個 <loc> 端點的 sitemap.xml、回傳 500 的路由、一個死連結,以及一個指向不同 hostname、位於第二台伺服器上的範圍外連結。
量測工具和樣本同樣重要:伺服器會記錄實際被抓取的內容,因此 scope 與 resume 的說法是根據命中事實,而不是 Katana 自己的 stdout。原始執行紀錄也都提交在 benchmark repo 裡,如果你想核對我的計算,可以直接看。
沒多少人量化過的涵蓋率差異

以下是在 -d 4 下,各模式對應各端點類別的矩陣:
| 模式 | HTML 連結 (A) | 深度鏈 (A) | JS 檔案字面值 (B) | Runtime DOM (C) |
|---|---|---|---|---|
| standard | 4/4 | 3/3 | 0/2 | 未找到 |
standard -jc | 4/4 | 3/3 | 2/2 | 未找到 |
-headless | 4/4 | 3/3 | 0/2 | 找到 |
-headless -jc | 4/4 | 3/3 | 0/2 | 找到 |
把最後兩欄一起看,問題就很明顯了。Class B 只有一種設定抓得到:標準模式加 -jc。Class C 則只有兩種:兩個 headless 都能抓到。沒有任何一列同時在兩欄都命中。完整矩陣放在 discovery-summary.json 裡,其中計算欄位 headless_jc_covers_both 的值是 false。
實際上的結論是:對這次測試來說,「直接用 headless 就好,涵蓋率更高」這句話是不完整的。Headless 並沒有在標準結果之上再補到 Class B;它是補到了 Class C,卻漏掉了 Class B。要把這個樣本裡預先埋好的類別全部覆蓋,得跑兩次再合併:
katana -u https://target.example -jc -d 4 -silent -o pass-jc.txt
katana -u https://target.example -headless -d 4 -silent -o pass-headless.txt
sort -u pass-jc.txt pass-headless.txt > endpoints.txt
-headless -jc 這個組合,是我最希望上游能回應的一個點。把 JavaScript 解析器加到 headless 上,沒有帶來任何新增結果——Class B 仍然是 0/2,而且每次重跑都一樣,包括重新驗證也如此。我是在回報這個行為,不是在宣稱我已經追到它的機制;我沒有去 instrument Katana 內部看為什麼瀏覽器路徑不再對 JS 檔案字面值有貢獻。請把它當成可重現的觀察與一個很好的 GitHub issue,而不是診斷結果。(順帶一提:在 v1.6.1、macOS ARM 上,-hl -jc 這個組合能正常完成並回傳 0,這在歷史上可不一定總是如此。)
官方文件 把 headless 描述成有更好的涵蓋率,而在這裡它確實對 runtime-rendered 類別有幫助。但文件並沒有把這種「原始碼字面值 / runtime DOM」的分裂講得那麼清楚,所以請把這個矩陣視為:要對自己的端點類別做測試的理由,而不是一個放諸四海皆準的分類法。
Headless 在時間成本上要付出什麼
在一台基本閒置的機器上,每種模式連續跑三次:
| 模式 | p50 | 最小–最大 | 平均 |
|---|---|---|---|
| standard | 13.08s | 13.07–13.17s | 13.11s |
-headless | 66.82s | 66.78–67.68s | 67.09s |
這是一個 5.1 倍 的差距,而且範圍完全沒有接近重疊——我最慢的 standard(13.17s)仍然比我最快的 headless(66.78s)快了 53 秒以上(cost-summary.json)。這不是量測雜訊。
這 13 秒有一個前提:我的樣本刻意包含一條 500 路由和一個死連結,而 standard 模式會在兩者上都跑完預設的 -timeout 10 重試尾巴。我沒有把 timeout 調到對快模式更有利,因此如果做過調校的 standard,差距很可能會更大,而不是更小。
這個倍率只能當作本機容量訊號,不是生產環境預測。真實目標的延遲、失敗率、腳本工作量和排程都不一樣,而這個樣本還包含預設 timeout 尾巴。請用這個量到的 5.1 倍差距,來判斷 headless 是否值得獨立預算與獨立目標子集,然後再在具代表性且已授權的主機上做基準測試。
範圍有守住,但有一個旗標默默沒起作用
這個 scope 測試用了兩台伺服器:主伺服器在 127.0.0.1,另一台可以透過 localhost 與不同 port 存取,且只在那裡存在一條路徑。所以,如果那條路徑有命中,就能證明範圍外主機確實被抓過,而不是只是被印出來。
| 設定 | 是否抓到範圍外主機? | 第二台伺服器的命中次數 |
|---|---|---|
預設(-fs rdn) | 否 | 0 |
-fs fqdn | 否 | 0 |
-cs localhost | 否 | 0 |
| `-fs '(127.0.0.1 | localhost)'` | 是 |
範圍控制是好消息:預設情況下 Katana 乖乖待在本範圍內,而且要明確動作才會把範圍放大。對一個會被拿去掃別人基礎設施的工具來說,這是對的預設值。
比較有意思的是 -cs localhost 這一列。它沒有把爬取範圍擴到第二台主機——而且也完全沒有輸出任何 URL。因為 -cs 是在 field scope 內做過濾,而 field scope 仍然是主機本身,所以 regex 沒匹配到任何東西,結果爬取就變成空集合,而不是報錯。如果你曾經寫過一個爬取範圍 regex,明明是想指定要包含某主機,最後卻看著空白輸出檔案,那就是這個機制在作用(scope-summary.json)。要加入主機,請設 -fs;要在既有主機集合內縮小範圍,才用 -cs / -cos。
Resume 比旗標字面意思更粗粒度
README 對這個旗標的說明是 -resume string resume scan using resume.cfg,看起來像是把檔案丟在工作目錄裡。但實際上不是。我這台機器上,checkpoint 被寫到 ~/.config/katana/resume-<xid>.cfg——這是實測出來的,不是從文件猜的,因為文件沒寫路徑。
更意外的是檔案內容。那個檔案裡只有一個 InFlightUrls map,而且裡面只有一樣東西:seed URL。不是已訪問集合,也不是 frontier。於是當我在三秒後用 SIGINT 中斷爬取,再續跑時,結果是這樣:
| 執行 | 不同路徑數 |
|---|---|
| 完整基準爬取 | 11 |
| 中斷前已抓到 | 10 |
| resume 重新抓取的內容 | 全部 11 條,包含已完成的 10 條 |
Resume 最後還是回到同樣的端點集合,所以功能沒有壞掉。但 checkpoint 的粒度是以輸入 seed 為單位,不是以 URL 為單位——記憶體中的 dedupe filter 不會被持久化,所以對單一 seed 續跑時,等於從頭再爬一次(resume-summary.json)。如果你餵給 Katana 的是 500 個主機,resume 應該能幫你省下那些已完整結束的主機;這種多 seed 行為是從狀態儲存方式推得出來的,但我只量了單 seed 的情況。如果你是在一個超大的單一網站裡深爬,resume 保證的是正確性,不是時間。
Known files:有請求,但最後被放掉

-kf all -d 3 確實有去請求兩個檔案——robots.txt 和 sitemap.xml 都出現在伺服器的命中紀錄裡——但最後只找回 sitemap 的 <loc> 裡列出的 0/2 端點。回憶率是 0.0。
在把它直接歸類為限制之前,我先試著排除是不是自己操作有問題。每一種變化都得到相同結果:
| 嘗試的變化 | 回收的 sitemap <loc> 端點 |
|---|---|
-kf all | 0/2,recall 0.0 |
-kf sitemapxml | 0/2,recall 0.0 |
-kf robotstxt | 0/2,recall 0.0 |
| depth 3 | 0/2,recall 0.0 |
| depth 4 | 0/2,recall 0.0 |
| depth 5 | 0/2,recall 0.0 |
再加上 -jc | 0/2,recall 0.0 |
直接以 /sitemap.xml 當 seed | 0/2,recall 0.0 |
文件上要求的條件——使用 -kf,深度至少到 3——每次都符合。這不是漏加旗標的故事。
真正有用的判斷順序是這樣:在這個 IP-literal 樣本裡,不要假設你要求 known files,就代表 sitemap 裡的 <loc> URL 也一起進了爬取範圍。請自己驗證 recall,或者自己先把那些 URL 抽出來,再作為 seed 餵給 Katana。
v1.6.1 的程式路徑與這個觀察是相符的,但我在執行過程中沒有把它 instrument 出來。根據 sitemapxml.go at v1.6.1,NewNavigationRequestURLFromResponse 會從 response 建立 <loc> 導航請求,但沒有帶上填妥的 RootHostname。接著請求會進到 ValidateScope;而在 scope.go at v1.6.1 裡,IP-literal 分支會拿 URL host 去比對那個空的 root,進而把它拒絕掉。我在另一個 scope 測試裡,-fs '(127.0.0.1|localhost)' 是走不同的 scope 分支,所以它是根據原始碼推測出的救援方式,不是我在 -kf 上實測成功的 workaround。由於這台主機在 known-files client 上有偶發的撥號問題,確認嘗試被阻擋了,因此最終報告仍然是 0/2。
如果今天就要上線,實務上我會怎麼做:自己抓 sitemap、抽出 <loc> URL,再把它們當成 seed list 餵給 Katana。兩行 shell 指令,沒有 scope 驗證這件事介入。
有一件事則完全如預期,而且值得單獨說一句:500 路由與死連結都被抓到、記錄到,然後跳過了。所有 browserless 執行最後都以 return code 0 結束。會在第一個壞回應就死掉的爬蟲根本不能放著不管,而 Katana 不會這樣。
部署前,先做一個針對目標的涵蓋率檢查
這個樣本矩陣最適合拿來當模板,測你自己已授權的目標。跑 Katana 前,先定義端點類別:純連結、連結腳本中的字面值、只有執行後才出現的路由,以及 known-file 項目,這四種是合理的起始分類。每一類都保留一小組 ground truth。如果沒有這份事前清單,stdout 再長也可能看起來像涵蓋率更高,實際上某一類卻已經消失了。
先把 browserless 與 headless 當成兩次獨立量測來跑。保存精確命令、Katana 版本、瀏覽器版本、return code 與輸出。比對端點集合時要做正規化和 diff,而不要只看行數。如果標準 -jc 在你的樣本上沒有貢獻任何獨特結果,那麼只用 headless 可能就夠;但如果集合像這裡一樣分歧,那就應該把兩次執行拆開,最後再合併。不要先假設把兩個旗標放在同一個命令裡,就等於兩者聯集;要由目標特定的 diff 來證明。
驗證 scope 時,請用 Katana 輸出以外的證據。放一個 canary URL 在應該被排除的主機上,並檢查那台伺服器的 request log。如果 crawl 本來就應該擴展,也要測試預期中的第二台主機。這裡的 -cs localhost 之所以產生空輸出,是因為 content-scope 過濾沒有擴大 field scope;而自訂的 -fs '(127.0.0.1|localhost)' 則確實有連到第二台伺服器。記錄精確的正規表示式很重要,因為只差一個字元,就可能改變的是 regex 本身,而不只是它的顯示方式。
把中斷與 known files 的測試,和 discovery recall 分開做。對 resume 而言,先在代表性 seed 上跑到幾個頁面後中斷,保存產生的 checkpoint 路徑,再計算已完成的 URL 被重新抓了多少次。對 -kf 而言,要同時確認 robots/sitemap 有被請求,且 sitemap 裡埋的 <loc> URL 真的有被排進排程。這兩件事不是同一個主張。在這個樣本中,檔案確實有被抓到,但 sitemap 的兩個端點卻沒有出現,所以 request log 和 endpoint output 兩者都必要,才能看出邊界。
最後,請在一台基本閒置的機器上,用連續執行建立本地成本基準,然後再到具代表性的主機上重測。不要只記倍數,也要保留最小值、最大值與中位數。這裡的 5.1 倍已經把樣本中的失敗與 timeout 行為算進去了;它告訴你 headless 值不值得獨立預算,而不是告訴你生產環境的盤點會花多久。
優點與缺點
優點:
- 在所有模式下,對一般 HTML 都有完整回憶率——4/4 連結、完整 3/3 深度鏈,幾乎不需要額外設定。
-jc在 browserless 模式下確實有效:從連結的 JS 檔字串常值中回收 2/2 個端點,而且不需要瀏覽器成本。-headless是唯一找到 runtime 組裝端點的模式——這類端點天生不可能被原始碼解析看見。- 預設 scope 很保守。範圍外主機在預設、
-fs fqdn或-cs下都不會被抓到。 - 單一 Go 二進位、MIT 授權、預編譯版本與 Docker 映像、以及適合管線的輸入輸出模式。
- 對失敗很耐打:500 與死連結不會讓爬蟲停掉。
缺點:
- 沒有任何單一執行,能同時覆蓋 JS 檔案端點與 runtime DOM 端點。要完整覆蓋,必須跑兩次再合併。
- 在
-headless下,-jc沒有帶來任何額外結果——每次 headless 執行,Class B 都是 0/2。 - Headless 的 wall time 要多 5.1 倍(p50 為 66.82s 對 13.08s,範圍完全不重疊)。
-resume會重新爬已完成的頁面。它恢復的是端點集合,不是你省下來的時間。- Known files 會請求 robots.txt 與 sitemap.xml,但在 IP 目標上,sitemap 的
<loc>端點回收是 0/2。 - Headless 在機器上其實默默要求有 Chromium;「一個二進位」的故事到瀏覽器這關就結束了。
- 這只是 discovery,不是擷取:沒有結構化提取、沒有內容轉換、沒有欄位 schema。
沒有測、因此不在這些數字涵蓋範圍內的項目包括:-jsluice、在 -d 1 / -d 2 的專門深度截斷測試、多 seed resume、自動表單填寫,以及任何真實的 JavaScript 密集或受保護的正式網站。所有數字都來自同一台機器(macOS arm64)與本機樣本。
適合誰用,誰應該跳過
如果你的工作是為你有權限接觸的基礎設施產出端點清單,Katana 的管線形狀很對味:有 STDIN/STDOUT 連接、可分發的二進位,以及 browserless 與 browser-backed 兩種模式。這個樣本裡的埋點,確實需要兩次合併;你的目標是否也需要兩次,則要用代表性頁面先確認。
如果你要的是資料而不是地址,就跳過它。Katana 永遠不會替你輸出商品表;它只會給你產品可能所在的 URL,而真正的擷取要交給別的工具。若你需要一條指令就完整,也該跳過它——兩次執行後再合併,在管線裡很合理,但在命令提示字元前就顯得麻煩。還有,如果你的枚舉仰賴 sitemap <loc> 端點,而目標又是 IP,請先確認你實際拿到的是什麼,再相信輸出;因為在我的樣本裡,這條路徑是空的。
替代方案,以及擷取邊界
Katana 免費、MIT 授權、自架可控。它把 discovery、模式選擇、瀏覽器部署與結果合併,都留在你的控制邊界內。
在開源工具裡,真正有意義的比較應該是按工作類型,而不是按語言。 Colly 是另一個 Go 選項,但它是要你自己寫 callback 來編譯的 library,而且完全不渲染 JavaScript。 Crawl4AI 會跑真正的瀏覽器,並為 LLM 管線輸出 Markdown,這是另一種完全不同的輸出。如果你一次在看好幾種工具,我們的 開源爬蟲總整理 會把各分類並排展示。
揭露: Thunderbit 是本文發布方的產品,並沒有在這次 Katana 樣本中進行測試。它屬於下游的受管擷取類別,負責把頁面轉成文字或結構化紀錄,而不是枚舉受授權目標的端點表面。實際工作流程可以同時用到這兩類工具,但這篇評測只提供 Katana discovery 行為的證據。
結論
如果你的交付物是端點清單,而且你有權限爬取那些目標,並且能針對目標驗證模式涵蓋率,那就用 Katana。在這個樣本裡,標準 -jc 找回了預先埋好的 JavaScript 檔字面值,而 headless 找回了 runtime DOM 端點;Katana 測過的 browserless 模式則沒有找回那條 runtime 路徑。預設 scope 也確實沒有抓到第二台主機,而 browserless 執行則會繼續跨過 500 與死連結。
限制是營運層面的:混合端點類別可能需要兩次執行再合併,headless 在本機大約要花五倍時間,單一 seed 的 resume 會重新抓已完成路徑,而 known-files 對 IP 目標的回收率是 0/2。這些都是 v1.6.1 樣本結果,不是對每個網站的保證。但它們已足夠定義一個正式評估應該重複檢查的項目。
試試 Thunderbit 進行網頁資料擷取 Get Started Free
常見問題
Katana 的 resume 檔案存在哪裡?續跑會跳過我已經爬過的頁面嗎?
checkpoint 會落在 ~/.config/katana/resume-<xid>.cfg,而不是旗標說明文字看起來像的工作目錄 resume.cfg。答案也是否定的:它不會跳過已完成頁面,因為檔案只存放 in-flight 的 seed URL;所以對單一 seed 的續跑,會把基準的 11 條路徑全部重新抓一遍,包括已完成的 10 條。最後拿到的是同樣的端點集合,只是沒有省到時間。
為什麼 -kf all 有請求我的 sitemap.xml,卻沒有爬裡面的 URL?
在 IP 目標上,這個結果比較像是 scope 驗證邊界,而不是旗標用錯。就 v1.6.1 的程式碼來看,Katana 的 sitemap 解析器在建立每個 <loc> 請求時沒有把 root hostname 一起帶上,而針對 IP-literal 主機的 DNS-scope 檢查就可能把那個 URL 擋掉;我沒有在執行過程中 instrument 它來確認這個機制。這個結果在我試過的所有旗標、深度與 seeding 變化下都維持 0 recall。自訂的 -fs 主機 regex 會走不同的驗證分支,這也是原始碼預測會有效的修法——但我在自己的機器上無法用 -kf 證實,所以請先把它當成未驗證。今天如果要我採信的做法,還是自己先把 <loc> URL 抽出來,再把它們當 seed 餵給 Katana。
回報 Katana 涵蓋率測試時,應該保留什麼?
記錄精確的 Katana 版本與命令,包括逐字元的 -fs 表達式;在執行前先定義端點類別;除了 stdout 之外,也保留伺服器端命中紀錄;並把實測行為和基於原始碼的推測分開。若是 headless 執行,也要記錄瀏覽器版本——這次測試沒有記,會限制重現性。
我該用 -jc、-headless,還是兩個都用?
請依你需要的端點類別來選。在這個樣本裡,標準 -jc 找到了儲存在 JavaScript 檔案中的字面值,而 headless 找到了插入 runtime DOM 的端點。兩種模式都無法單獨覆蓋全部類別,因此對混合目標而言,先兩次執行再去重,是最合理的選擇。
只要有一個 URL 失敗,爬取就會停掉嗎? 在這次受控測試裡不會。Katana 在 500 回應和死連結之後都繼續往下爬,最後仍然回傳其他可達路徑。這不能取代正式環境的錯誤統計:請保留失敗請求紀錄,並定義可接受的失敗率,避免把部分成功誤判成完整覆蓋。


