Katana ist ProjectDiscoverys Crawler zur Erkennung von Endpunkten — eine Go-Binary unter MIT-Lizenz, die ein Ziel entgegennimmt und URLs sowie Endpunkte für das nächste Tool in einer Pipeline zurückliefert. Er crawlt entweder ohne Browser im HTTP-Modus oder mit -headless, wobei Chromium gesteuert wird. Die offizielle Dokumentation stellt den Headless-Modus als die Variante mit höherer Abdeckung dar; dieses Testset zeigt jedoch, dass die Art des Endpunkts genauso wichtig ist wie die reine Anzahl.
Ich habe eine kleine Website mit drei absichtlich unterschiedlichen Endpunkt-Klassen gebaut und gemessen, welche davon v1.6.1 bei -d 4 findet. Normales HTML wurde in allen vier Konfigurationen vollständig mit 4/4 Links und der kompletten Drei-Hop-Kette erfasst. Die Differenz zeigte sich bei Endpunkten, die entweder aus JavaScript-Quellcode stammen oder erst durch DOM-Änderungen zur Laufzeit entstehen.
In diesem Testset fand Headless die Runtime-DOM-Klasse, die die getesteten browserlosen Modi verpassten, während der Standardmodus mit -jc jene JavaScript-Datei-Literale fand, die beide Headless-Läufe verfehlten. Keine der vier Kommandozeilen-Konfigurationen deckte beide Klassen zugleich ab. Scope, Resume und das Verhalten bei Known Files bildeten die übrigen praktischen Grenzen.
Was Katana eigentlich ist
Der Katana-Crawler — projectdiscovery/katana auf GitHub — ist in Go geschrieben und MIT-lizenziert. Ich habe am 27. Juli 2026 v1.6.1 getestet; die Version ist relevant, weil die unten beschriebenen Erkenntnisse zu Abdeckung und Known Files versionsabhängige Beobachtungen sind.
Die Kategorisierung ist hier wichtiger als sonst. Ein Crawler zur Endpunkt-Erkennung ist kein Feld-Extractor. Wenn Sie einen Go-Webcrawler suchen, der Ihnen Produktnamen und Preise als strukturiertes JSON liefert, dann ist Katana schlicht das falsche Regal — er kann Ihnen problemlos sagen, dass /products/1138 existiert, aber nichts darüber, was auf dieser Seite steht. Genau dafür ist das Tool gebaut. Wer es an der Extraktion misst, bewertet im Grunde einen Metalldetektor danach, wie gut er Schmuck taxieren kann.
Sein natürliches Einsatzgebiet ist Recon im Offensivbereich und die Automatisierung von Pipelines: STDIN rein, URLs raus, dann an das nächste Tool weiterreichen. Damit ist auch die wichtigste Einschränkung gleich vorneweg gesagt — alle Messungen hier liefen gegen ein von mir selbst gebautes Testsystem auf 127.0.0.1. Setzen Sie Katana nur auf Hosts ein, die Ihnen gehören oder für die Sie ausdrücklich eine Prüfungserlaubnis haben, und auf nichts anderes. Es geht hier nicht darum, Schutzmechanismen zu umgehen, sondern darum, wie viel von der Endpunktfläche einer Site ein bestimmter Befehl tatsächlich auflistet.
Die drei Modi und was jeder davon sehen kann
Der Standardmodus ist ein Go-HTTP-Client. Er lädt Seiten, parst HTML, folgt hrefs und startet nie einen Browser. Schnell, günstig und blind für alles, was erst nach der Ausführung von JavaScript existiert.
-jc (-js-crawl) setzt einen JavaScript-Parser auf diesen browserlosen Pfad. Er lädt verknüpfte .js-Dateien herunter und zieht URL-ähnliche String-Literale aus dem Quelltext. Keine Ausführung, nur Lesen. Außerdem gibt es noch -jsl (jsluice), das in der README als schwergewichtigere, speicherintensivere Parser-Variante beschrieben wird — ich habe es nicht getestet und kann daher nicht sagen, ob sich dadurch das Abdeckungsbild verändert.

-headless steuert Chromium und führt Seitenskripte aus. In diesem Testset war es der einzige getestete Katana-Modus, der den aus Fragmenten zusammengesetzten und zur Laufzeit ins DOM eingesetzten Pfad wiederfand. Das bedeutet nicht, dass jeder Parser oder ein zukünftiger Katana-Modus dasselbe leisten würde.
Dann ist da noch das Scope-Modell, und genau diesen Teil würde ich verinnerlichen, bevor ich irgendetwas in einer produktiven Umgebung tippe.
| Flag | Was es steuert | Werte / Standard |
|---|---|---|
-fs (field scope) | welche Hosts überhaupt berücksichtigt werden | dn, rdn, fqdn oder ein benutzerdefinierter Regex — Standard ist rdn |
-cs und -cos | URL-Regexe, die innerhalb dieses Field Scopes filtern | — |
-kf | bekannte Dateien: robots.txt und sitemap.xml | laut README ist eine Mindesttiefe von 3 nötig |
-d | Tiefe | Standard 3 |
-resume | setzt einen unterbrochenen Crawl fort | — |
Die Reihenfolge ist nicht kosmetisch: Sie entscheidet, ob ein Host-Regex einen Crawl erweitert oder ihn stillschweigend leer laufen lässt.
Einrichtung: eine Binary, ein Sternchen
Drei Wege stehen zur Verfügung, und nur einer davon verlangt eine Toolchain:
| Installationsweg | Voraussetzung |
|---|---|
Aus dem Quellcode: go install github.com/projectdiscovery/katana/cmd/katana@latest | Als Voraussetzung wird Go 1.25 oder neuer genannt |
| Vorgebaute Binaries von der Release-Seite | keine Toolchain |
| Docker-Image | keine Toolchain |
Bei mir landete das Binary unter ~/go/bin/katana und meldete bei jedem Lauf Current version: v1.6.1. Bis hierhin die übliche angenehme Go-Geschichte: eine Datei, keine Runtime.
Das Sternchen betrifft Headless, denn dort ist der Browser eine separate Voraussetzung zusätzlich zur Binary:
Wo -headless läuft | Was dafür nötig ist |
|---|---|
| Auf meinem Rechner | Katana erkannte automatisch ein bereits installiertes Chromium; ich habe weder den Browser-Build notiert noch einen Browserpfad angegeben |
| Auf einem nackten Server, laut der Ubuntu-Anleitung des Projekts | Vor Headless muss apt install google-chrome-stable ausgeführt werden |
| Über Docker | Headless läuft mit -system-chrome |
Auf einem nackten Server verschwindet dieser Komfort sofort. Planen Sie also einen Browser mit ein — nicht nur eine Binary — sobald -headless in Ihrer Kommandozeile auftaucht.
Ein kleiner, aber wichtiger Hinweis für CI-Einsätze: Katana ruft beim Start eine Versionsprüfung bei GitHub ab. -duc schaltet das ab. Auf dem Laptop ist das harmlos; auf einem air-gapped oder rate-limitierten Runner ist es ein zusätzlicher Netzwerk-RTT pro Lauf, den Sie gar nicht wollten. Meine Timing-Messungen verwenden -duc, damit die Zahlen das Crawling messen und nicht einen Phone-home-Aufruf.
So habe ich getestet
Drei Klassen von Endpunkten, absichtlich so gewählt, dass sie die Modi voneinander trennen. Alles liegt auf einem lokalen Fixture-Server, und die Ground Truth wurde vor jedem Crawl notiert, sodass Recall gegen eine feste Menge gemessen wird und nicht gegen das, was Katana zufällig ausgibt.
- Klasse A — normales HTML.
/page/a,/page/b,/page/csowie eine Drei-Hop-Kette/depth/1 → /depth/2 → /depth/3. Das sollte jeder Crawler finden. - Klasse B — JavaScript-Datei-Literale.
/api/js-endpoint-7und/api/js-endpoint-8existieren nur als String-Literale in einer verknüpften/static/app.js. Ohne Browser lesbar, sofern etwas den JS-Code überhaupt einliest. - Klasse C — nur Runtime-DOM. Ein Pfad, der zur Laufzeit aus Fragmenten zusammengesetzt (
'endpoint' + (6 * 7)) und per Script ins DOM eingefügt wird. Die Zeichenfolge/runtime-only/endpoint42kommt in keinem Byte vor, das der Server sendet — weder im HTML noch im JS-Quelltext. Nur Ausführung macht sie sichtbar.
Dazu kamen eine robots.txt, eine sitemap.xml mit zwei <loc>-Endpunkten, die sonst nirgends auftauchen, ein Route, die 500 zurückgibt, ein toter Link und ein Out-of-Scope-Link auf einen zweiten Server mit anderer Hostname.
Das Messinstrument ist genauso wichtig wie das Fixture: Der Server zählt was tatsächlich abgerufen wurde, sodass Scope- und Resume-Aussagen auf tatsächlichen Treffern beruhen und nicht auf Katana-Stdout. Die Rohdurchläufe sind im Benchmark-Repo eingecheckt, falls Sie meine Rechnung prüfen möchten.
Die Abdeckungslücke, die niemand quantifiziert

Die Matrix, Modus nach Endpunktklasse, bei -d 4:
| Modus | HTML-Links (A) | Tiefenkette (A) | JS-Datei-Literale (B) | Runtime-DOM (C) |
|---|---|---|---|---|
| standard | 4/4 | 3/3 | 0/2 | nicht gefunden |
standard -jc | 4/4 | 3/3 | 2/2 | nicht gefunden |
-headless | 4/4 | 3/3 | 0/2 | gefunden |
-headless -jc | 4/4 | 3/3 | 0/2 | gefunden |
Wenn man die letzten beiden Spalten zusammen liest, springt das Problem sofort ins Auge. Klasse B wurde nur von genau einer Konfiguration gefunden: dem Standardmodus mit -jc. Klasse C wurde nur von genau zwei gefunden: beiden Headless-Läufen. Es gibt keine Zeile mit Treffern in beiden Spalten. Die vollständige Matrix liegt in discovery-summary.json, wo das berechnete Feld headless_jc_covers_both den Wert false trägt.
Die praktische Konsequenz ist, dass „einfach Headless für bessere Abdeckung verwenden“ für diesen Test zu kurz greift. Headless fügte Klasse B nicht zusätzlich zum Standardergebnis hinzu; es fand Klasse C, ließ aber Klasse B aus. Alle eingebetteten Klassen dieses Fixtures abzudecken, erforderte zwei Crawls und ein Zusammenführen:
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
Die Zeile -headless -jc ist diejenige, zu der ich am liebsten eine offizielle Erklärung sehen würde. Das Hinzufügen des JavaScript-Parsers zum Headless-Lauf brachte nichts Neues — weiterhin 0/2 bei Klasse B, in jedem Lauf, auch bei einer frischen Reproduktion. Ich berichte hier das Verhalten, behaupte aber nicht, den Mechanismus aufgeklärt zu haben; ich habe Katana intern nicht instrumentiert, um herauszufinden, warum der Browser-Pfad keine JavaScript-Datei-Literale beiträgt. Behandeln Sie das als reproduzierbare Beobachtung und als guten GitHub-Issue-Kandidaten, nicht als Diagnose. (Ein Detail am Rand: Die Kombination -hl -jc lief unter v1.6.1 auf macOS ARM sauber mit Rückgabecode 0 durch, was historisch nicht immer so war.)
Die offizielle Dokumentation beschreibt Headless als besser in der Abdeckung, und genau das zeigte sich hier bei der runtime-gerenderten Klasse. Die geprüfte Anleitung erwähnte diese Trennung zwischen Quelltext-Literalen und Runtime-DOM nicht explizit, daher sollte die Matrix als Anlass dienen, beide Pfade gegen die eigenen Endpunktklassen zu testen — nicht als universelle Taxonomie.
Was Headless an Zeit kostet
Drei sequentielle Läufe pro Modus auf einem sonst ruhigen Rechner:
| Modus | p50 | min–max | Mittelwert |
|---|---|---|---|
| standard | 13.08s | 13.07–13.17s | 13.11s |
-headless | 66.82s | 66.78–67.68s | 67.09s |
Das entspricht einem Faktor von 5,1x; die Bereiche überlappen sich nicht einmal ansatzweise — mein langsamster Standardlauf (13.17s) war immer noch mehr als 53 Sekunden schneller als mein schnellster Headless-Lauf (66.78s) (cost-summary.json). Das ist keine Messunschärfe.
Ein Hinweis zu diesen 13 Sekunden: Mein Fixture enthält bewusst eine 500-Route und einen toten Link, und der Standardmodus wartet bei beiden die Standard-Timeout-Nachlaufzeit von -timeout 10 ab. Ich habe den Timeout nicht zugunsten des schnellen Modus optimiert; ein getunter Standardlauf würde die Lücke also vermutlich vergrößern statt verkleinern.
Das Verhältnis ist ein lokales Kapazitätssignal, keine Produktionsprognose. Echte Ziele unterscheiden sich bei Latenz, Fehlern, Skriptlast und Scheduling, während dieses Fixture den Standard-Timeout-Nachlauf enthält. Verwenden Sie den gemessenen 5,1x-Unterschied, um zu entscheiden, ob Headless ein eigenes Budget und eine eigene Zielmenge verdient, und testen Sie diesen Plan dann auf repräsentativen, autorisierten Hosts.
Scope blieb erhalten, aber ein Flag tat stillschweigend nichts
Der Scope-Test verwendete zwei Server: den primären auf 127.0.0.1 und einen zweiten, erreichbar als localhost auf einem anderen Port, der einen Pfad bedient, der nur dort existiert. Ein Treffer auf diesem Pfad ist also ein Beweis dafür, dass der Host außerhalb des Scopes tatsächlich abgerufen wurde und nicht bloß ausgegeben wurde.
| Konfiguration | Host außerhalb des Scopes abgerufen? | Treffer auf dem zweiten Server |
|---|---|---|
Standard (-fs rdn) | nein | 0 |
-fs fqdn | nein | 0 |
-cs localhost | nein | 0 |
| `-fs '(127.0.0.1 | localhost)'` | ja |
Scope-Disziplin ist eine gute Nachricht: Standardmäßig blieb Katana auf seinem eigenen Terrain, und es brauchte eine explizite Aktion, um den Scope zu erweitern. Genau so sollte ein Tool standardmäßig arbeiten, das auf fremder Infrastruktur angesetzt wird.
Die interessante Zeile ist -cs localhost. Sie erweiterte den Crawl nicht auf den zweiten Host — und gab außerdem überhaupt keine URLs aus. Weil -cs innerhalb des Field Scopes filtert und der Field Scope weiterhin der Primärhost war, passte der Regex auf nichts, und der Crawl lieferte statt eines Fehlers ein leeres Set zurück. Wenn Sie schon einmal einen Crawl-Scope-Regex geschrieben haben, der einen Host enthalten sollte, und dann auf eine leere Ausgabedatei gestarrt haben, ist das genau der Mechanismus (scope-summary.json). Um einen Host hinzuzufügen, setzen Sie -fs. Um innerhalb bereits vorhandener Hosts enger zu filtern, verwenden Sie -cs/-cos.
Resume ist gröber, als das Flag vermuten lässt
Die README beschreibt das Flag als -resume string resume scan using resume.cfg, was so klingt, als würde im Arbeitsverzeichnis eine Datei abgelegt. Ist aber nicht so. Auf meinem Rechner wurde der Checkpoint unter ~/.config/katana/resume-<xid>.cfg geschrieben — gemessen, nicht aus einer Dokumentation übernommen, weil die Doku keinen Pfad nennt.
Der wichtigere Überraschungspunkt ist der Inhalt. Die Datei enthielt eine InFlightUrls-Map mit genau einem Eintrag: der Seed-URL. Nicht die bereits besuchten URLs, nicht die Frontier. Genau das passierte, als ich einen Crawl nach drei Sekunden per SIGINT unterbrach und anschließend fortsetzte:
| Lauf | Unterschiedliche Pfade |
|---|---|
| Vollständiger Baseline-Crawl | 11 |
| Vor dem Interrupt abgerufen | 10 |
| Vom Resume-Lauf erneut abgerufen | alle 11, einschließlich aller 10 bereits abgeschlossenen |
Resume erreichte denselben finalen Endpunkt-Satz, also ist nichts kaputt. Aber die Granularität des Checkpoints ist pro Input-Seed, nicht pro URL — der In-Memory-Dedupe-Filter wird nie persistiert, sodass ein Resume eines Single-Seed-Crawls diesen Seed von vorne neu crawlt (resume-summary.json). Wenn Sie Katana eine Liste mit 500 Hosts geben, sollte Resume Ihnen die Hosts ersparen, die bereits vollständig abgeschlossen waren; dieses Verhalten bei mehreren Seeds folgt daraus, wie der Zustand gespeichert wird, aber ich habe nur den Single-Seed-Fall gemessen. Wenn Sie tief in einer einzigen großen Site stecken, bringt Resume Ihnen Korrektheit, nicht Zeit.
Known Files: angefordert, dann fallengelassen

-kf all -d 3 hat beide Dateien tatsächlich angefordert — robots.txt und sitemap.xml tauchten im Server-Hit-Log auf — und anschließend 0 von 2 der Endpunkte aus den <loc>-Elementen dieser Sitemap wiedergefunden. Recall 0.0.
Bevor ich das als Einschränkung bezeichnete, versuchte ich erst, es zu meinem Fehler zu machen. Jede Variante lieferte dasselbe Ergebnis:
| Getestete Variante | Wiedergefundene Sitemap-<loc>-Endpunkte |
|---|---|
-kf all | 0/2, Recall 0.0 |
-kf sitemapxml | 0/2, Recall 0.0 |
-kf robotstxt | 0/2, Recall 0.0 |
| Tiefe 3 | 0/2, Recall 0.0 |
| Tiefe 4 | 0/2, Recall 0.0 |
| Tiefe 5 | 0/2, Recall 0.0 |
mit zusätzlich -jc | 0/2, Recall 0.0 |
direkt auf /sitemap.xml als Seed | 0/2, Recall 0.0 |
Die dokumentierte Voraussetzung — -kf verwenden und mindestens drei Ebenen tief gehen — war jedes Mal erfüllt. Das ist also keine Geschichte über ein fehlendes Flag.
Die brauchbare Erkenntnis kommt zuerst: In diesem IP-literal-basierten Fixture sollten Sie nicht automatisch davon ausgehen, dass das Anfordern bekannter Dateien bedeutet, dass ihre <loc>-URLs wirklich Teil des Crawls wurden. Prüfen Sie den Recall oder extrahieren und seeden Sie diese URLs selbst.
Der Codepfad in v1.6.1 passt zu dieser Beobachtung, aber ich habe ihn während des Laufs nicht instrumentiert. In sitemapxml.go in v1.6.1 baut NewNavigationRequestURLFromResponse <loc>-Navigationsanfragen aus einer Response, ohne einen befüllten RootHostname mitzunehmen. Die Anfrage gelangt dann zu ValidateScope; in scope.go in v1.6.1 kann der IP-literal-Zweig den URL-Host mit diesem leeren Root vergleichen und ablehnen. Der benutzerdefinierte Befehl -fs '(127.0.0.1|localhost)' nahm in einem separaten Scope-Test einen anderen Branch, ist also eine aus dem Quelltext ableitbare Rettung, kein gemessener -kf-Workaround. Ein Bestätigungsversuch scheiterte an sporadischen Verbindungsproblemen im Known-Files-Client auf diesem Host; das berichtete Ergebnis bleibt daher 0/2.
Was ich in der Produktion tatsächlich tun würde, bis jemand das Flag bestätigt: die Sitemap selbst abrufen, die <loc>-URLs extrahieren und sie Katana als Seed-Liste übergeben. Zwei Shell-Zeilen, keine Scope-Prüfung dazwischen.
Ein Verhalten war genau so, wie versprochen, und verdient einen Satz: Die 500-Route und der tote Link wurden abgerufen, geloggt und übersprungen. Jeder browserlose Lauf endete mit Rückgabecode 0. Ein Crawler, der beim ersten Fehler stirbt, ist unbeaufsichtigt unbrauchbar — und Katana tut das nicht.
Ein zielgerichteter Abdeckungscheck vor dem Einsatz
Die Fixture-Matrix ist vor allem als Vorlage für eigene, autorisierte Ziele nützlich. Definieren Sie Endpunktklassen vor dem Katana-Lauf: normale Links, Literale in verknüpften Skripten, nur nach Ausführung erzeugte Routen und Known-File-Einträge sind vier sinnvolle Ausgangskategorien. Halten Sie für jede Klasse eine kleine Ground-Truth-Stichprobe bereit. Ohne diese Vorab-Liste kann eine größere Stdout-Datei wie bessere Abdeckung wirken, selbst wenn eine Klasse verschwunden ist.
Führen Sie browserlose und Headless-Pfade zunächst als getrennte Messungen aus. Speichern Sie die exakten Befehle, die Katana-Version, den Browser-Build, die Rückgabecodes und die Outputs. Normalisieren und vergleichen Sie die Endpunktmengen, statt nur Zeilenzahlen zu vergleichen. Wenn Standard--jc auf Ihrem Sample nichts Einzigartiges beiträgt, kann ein reiner Headless-Ansatz genügen; wenn die Mengen auseinanderlaufen wie hier, halten Sie beide Durchläufe getrennt und mergen Sie anschließend. Beide Flags in einen einzigen Befehl zu packen, sollte nicht ohne target-spezifischen Diff als gleichwertig zur Vereinigung angenommen werden.
Validieren Sie den Scope mit Belegen außerhalb von Katana-Output. Legen Sie eine Canary-URL auf einen Host, der ausgeschlossen bleiben soll, und prüfen Sie das Request-Log dieses Servers. Testen Sie außerdem einen vorgesehenen zweiten Host, falls der Crawl sich erweitern soll. Der Lauf -cs localhost erzeugte hier eine leere Ausgabe, weil das Content-Scope-Filtering den Field Scope nicht erweiterte; der benutzerdefinierte Aufruf -fs '(127.0.0.1|localhost)' kontaktierte den zweiten Server. Das exakte Regex festzuhalten ist wichtig, weil schon ein Zeichen Unterschied den Regex selbst verändert und nicht nur seine Darstellung.
Testen Sie Unterbrechung und Known Files getrennt von der Discovery-Recall-Messung. Unterbrechen Sie für Resume einen repräsentativen Seed nach mehreren Seiten, speichern Sie den erzeugten Checkpoint-Pfad und zählen Sie, wie viele bereits abgeschlossene URLs erneut abgerufen werden. Bei -kf sollten Sie sowohl bestätigen, dass robots/sitemap angefordert wurden, als auch dass die eingebetteten <loc>-URLs tatsächlich geplant wurden. Das sind unterschiedliche Aussagen. In diesem Fixture wurden die Dateien abgerufen, während die beiden Sitemap-Endpunkte fehlten — daher brauchte es sowohl Request-Logs als auch Endpoint-Output, um die Grenze zu erkennen.
Ermitteln Sie schließlich ein lokales Kosten-Baseline mit sequentiellen Läufen auf einem sonst ruhigen Rechner und wiederholen Sie das auf repräsentativen Hosts. Bewahren Sie Minimum, Maximum und Median auf, nicht nur einen Multiplikator. Der hier gemessene Faktor 5,1x enthält das Fehl- und Timeout-Verhalten dieses Fixtures; er sagt Ihnen, dass Headless ein eigenes Budget verdient, nicht wie lange ein Produktionsinventar dauern wird.
Vor- und Nachteile
Vorteile:
- Perfekter Recall bei normalem HTML in jedem Modus — 4/4 Links und die komplette 3/3-Tiefenkette, ohne zusätzliche Konfiguration.
-jcfunktioniert tatsächlich browserlos: 2/2 Endpunkte aus String-Literalen in einer verknüpften JS-Datei, ganz ohne Browserkosten.-headlessist die einzige Variante, die einen zur Laufzeit zusammengesetzten Endpunkt gefunden hat — eine Klasse, die durch Quelltext-Parsing konstruktionsbedingt unsichtbar bleibt.- Die Standard-Scope-Einstellungen sind konservativ. Der Host außerhalb des Scopes wurde unter Standard,
-fs fqdnoder-csnie abgerufen. - Einzelne Go-Binary, MIT-Lizenz, vorgebaute Builds und ein Docker-Image, I/O passend für Pipelines.
- Robust bei Fehlern: 500er und tote Links stoppen den Crawl nicht.
Nachteile:
- Kein einzelner Aufruf deckte sowohl JS-Datei- als auch Runtime-DOM-Endpunkte ab. Vollständige Abdeckung erfordert zwei Läufe und ein Merge.
-jcbrachte unter-headlessnichts — in jedem Headless-Lauf 0/2 bei Klasse B.- Headless kostet 5,1x mehr Laufzeit (66.82s vs. 13.08s p50, nicht überlappende Bereiche).
-resumecrawlt abgeschlossene Seiten innerhalb eines Seeds erneut. Es stellt das Endpunkt-Set wieder her, nicht die gesparte Zeit.- Known Files haben robots.txt und sitemap.xml angefordert, aber gegen das IP-Ziel 0/2 Sitemap-
<loc>-Endpunkte wiedergefunden. - Headless setzt stillschweigend Chromium auf dem System voraus; die „eine Binary“-Geschichte endet beim Browser.
- Nur Discovery. Keine strukturierte Extraktion, keine Inhaltskonvertierung, kein Feldschema.
Nicht getestet und daher außerhalb dessen, was diese Zahlen abdecken: -jsluice, ein dedizierter Tiefe-zu-niedrig-Test bei -d 1/-d 2, Multi-Seed-Resume, automatische Formularbefüllung und jede realistische JavaScript-lastige oder geschützte Produktionsseite. Alle Zahlen stammen von einem Rechner (macOS arm64) gegen ein lokales Fixture.
Für wen es gedacht ist — und wer es besser überspringt
Wenn Ihre Aufgabe darin besteht, ein Endpunkt-Inventar von Infrastrukturen zu erzeugen, die Sie autorisiert prüfen dürfen, hat Katana die richtige Pipeline-Form: STDIN/STDOUT-Verkabelung, eine verteilbare Binary sowie browserlose und browsergestützte Modi. Der Zwei-Pass-Merge war für die eingebetteten Klassen dieses Fixtures notwendig; ob Ihre Ziele beide Durchläufe benötigen, muss man anhand repräsentativer Seiten feststellen.
Überspringen Sie es, wenn Sie Daten statt Adressen wollen. Katana wird Ihnen nie eine Produkttabelle liefern; es liefert die URLs, unter denen Produkte vielleicht leben, und etwas anderes übernimmt die Extraktion. Überspringen Sie es auch, wenn Sie einen einzigen vollständigen Befehl brauchen — der Zwei-Pass-Merge ist in einer Pipeline völlig in Ordnung, an einer Eingabeaufforderung aber lästig. Und wenn Ihre Enumeration bei IP-Zielen stark auf Sitemap-<loc>-Endpunkte setzt, prüfen Sie zuerst, was Sie tatsächlich bekommen, bevor Sie dem Output vertrauen, denn auf meinem Fixture lieferte dieser Pfad nichts.
Alternativen und die Grenze zur Extraktion
Katana ist kostenlos, MIT-lizenziert und self-hosted. Es hält Discovery, Moduswahl, Browser-Bereitstellung und das Zusammenführen der Ergebnisse auf Ihrer Seite der Grenze.
Im Open-Source-Bereich sind die sinnvollen Vergleiche eher nach Aufgabe als nach Sprache zu ziehen. Colly ist die andere Go-Option, aber es ist eine Library, die Sie mit eigenen Callbacks kompilieren, und sie rendert überhaupt kein JavaScript. Crawl4AI läuft in einem echten Browser und erzeugt Markdown für LLM-Pipelines, was ein völlig anderes Ausgabeformat ist. Wenn Sie mehrere dieser Tools gleichzeitig abwägen, ordnet unser Open-Source-Scraper-Überblick die Kategorien direkt nebeneinander ein.
Hinweis zur Offenlegung: Thunderbit ist das Produkt des Herausgebers und wurde in diesem Katana-Fixture nicht getestet. Es liegt in der verwalteten Extraktionskategorie weiter downstream und wandelt Seiten in Text oder strukturierte Datensätze um, statt die Endpunktoberfläche eines autorisierten Ziels zu enumerieren. Ein Workflow kann beide Kategorien verwenden, aber dieser Test liefert nur Belege für Katana's Discovery-Verhalten.
Thunderbit für Web-Datenextraktion testen
Fazit
Setzen Sie Katana ein, wenn das Ergebnis eine Endpunktliste für Ziele ist, die Sie autorisiert crawlen dürfen, und wenn Sie die Modus-Abdeckung gegen diese Ziele validieren können. In diesem Fixture fand der Standardmodus mit -jc die eingebetteten JavaScript-Datei-Literale, während Headless den Runtime-DOM-Endpunkt fand; die getesteten browserlosen Modi von Katana erfassten diesen Runtime-Pfad nicht. Der Standard-Scope hielt außerdem den zweiten Host fern, und browserlose Läufe liefen an der 500-Route und dem toten Link vorbei.
Die Einschränkungen sind operativ: Für gemischte Endpunktklassen kann ein Zwei-Pass-Merge nötig sein, Headless brauchte hier ungefähr die fünffache lokale Laufzeit, Resume eines einzelnen Seeds rief bereits abgeschlossene Pfade erneut ab, und die Known-Files-Abdeckung lag gegen das IP-Ziel bei 0/2. Das sind Ergebnisse aus v1.6.1 und diesem Fixture, keine Garantie für jede Website. Aber sie reichen aus, um die Prüfungen zu definieren, die eine Produktionsbewertung wiederholen sollte.
Thunderbit für Web-Datenextraktion testen Get Started Free
FAQs
Wo speichert Katana seine Resume-Datei, und überspringt das Fortsetzen bereits gecrawlte Seiten?
Der Checkpoint landete unter ~/.config/katana/resume-<xid>.cfg und nicht als resume.cfg im Arbeitsverzeichnis, wie der Hilfetext des Flags nahelegt. Und nein, er überspringt keine bereits abgeschlossenen Seiten: Die Datei speichert nur die aktuell in Bearbeitung befindlichen Seed-URLs, daher rief ein fortgesetzter Single-Seed-Crawl alle 11 Baseline-Pfade erneut ab, inklusive der 10 bereits erledigten. Sie erhalten also denselben finalen Endpunkt-Satz, nur keine gesparte Zeit.
Warum hat -kf all meine sitemap.xml angefordert, aber die URLs darin nicht gecrawlt?
Gegen ein IP-Ziel passt das Ergebnis eher zu einer Scope-Validierungsgrenze als zu einem falschen Flag. Im Code von v1.6.1 baut Katanas Sitemap-Parser jede <loc>-Anfrage, ohne den Root-Hostname mitzugeben, und die DNS-Scope-Prüfung für IP-literal-Hosts kann diese URL dann ablehnen; ich habe den Lauf nicht instrumentiert, um diesen Mechanismus zu bestätigen. Über alle von mir getesteten Flag-, Tiefen- und Seed-Varianten blieb der Recall bei 0. Ein benutzerdefinierter -fs-Host-Regex nimmt einen anderen Validierungszweig und ist laut Quelltext die vorgesehene Rettung — ich konnte das auf meiner Maschine aber nicht mit -kf bestätigen, also behandeln Sie das bitte als ungetestet. Die <loc>-URLs selbst zu extrahieren und Katana direkt damit zu seeden, ist der Ansatz, dem ich heute vertrauen würde.
Was sollte ich bei einem Katana-Coverage-Test mitreporten?
Notieren Sie die exakte Katana-Version und den exakten Befehl, einschließlich des Byte-für-Byte--fs-Ausdrucks; definieren Sie Endpunktklassen vor dem Lauf; bewahren Sie serverseitige Hit-Logs zusätzlich zum Stdout auf; und trennen Sie gemessenes Verhalten von Hypothesen, die aus dem Quellcode abgeleitet sind. Bei Headless-Läufen sollten Sie auch den Browser-Build dokumentieren — das wurde hier nicht getan, was die Reproduzierbarkeit einschränkt.
Sollte ich -jc, -headless oder beides verwenden?
Wählen Sie anhand der Endpunktklassen, die Sie brauchen. In diesem Fixture fand der Standardmodus mit -jc Literale in einer JavaScript-Datei, während Headless den in das Runtime-DOM eingefügten Endpunkt fand. Keine der beiden Modi deckte beide Klassen allein ab, also war ein Zwei-Pass-Lauf mit anschließender Duplikatentfernung die vernünftige Wahl für gemischte Ziele.
Bricht ein einzelner fehlerhafter URL den Crawl ab? In diesem kontrollierten Lauf nicht. Katana lief sowohl nach einer 500-Antwort als auch nach einem toten Link weiter und lieferte dennoch die übrigen erreichbaren Pfade zurück. Das ersetzt allerdings kein Produktions-Fehlertracking: Führen Sie Logs über fehlgeschlagene Requests und definieren Sie eine akzeptable Fehlerquote, damit ein teilweise erfolgreicher Crawl nicht fälschlich als vollständige Abdeckung gilt.


