Recenzja Katana: `-jc` i `-headless` znajdują różne endpointy, a jedna komenda nie wykryła obu

Ostatnia aktualizacja: August 19, 2026
Recenzja Katana: `-jc` i `-headless` znajdują różne endpointy, a jedna komenda nie wykryła obu
Podsumowanie AI

Katana to crawler ProjectDiscovery do wykrywania endpointów — binarka Go na licencji MIT, która przyjmuje cel i zwraca adresy URL oraz endpointy dla kolejnego narzędzia w pipeline. Działa w trybie HTTP bez przeglądarki albo z -headless, który uruchamia Chromium. Oficjalne wskazówki przedstawiają tryb headless jako opcję o szerszym zasięgu; ten test pokazuje, że równie ważny jak liczba jest sam typ endpointu. Zbudowałem małą stronę z trzema celowo różnymi klasami endpointów i sprawdziłem, który tryb wykrywa każdą z nich w v1.6.1 przy -d 4.

Katana to crawler do wykrywania endpointów od ProjectDiscovery — binarka napisana w Go, na licencji MIT, która bierze adres docelowy i zwraca URL-e oraz endpointy dla kolejnego narzędzia w łańcuchu. Działa w trybie HTTP bez przeglądarki albo z -headless, który uruchamia Chromium. Oficjalne wskazówki przedstawiają tryb headless jako opcję o szerszym pokryciu; ten test pokazuje, że równie ważny jak liczba jest rodzaj endpointu.

Zbudowałem małą witrynę z trzema celowo różnymi klasami endpointów i sprawdziłem, który tryb wykrywa każdy z nich w v1.6.1 przy -d 4. Zwykły HTML był widoczny w 4/4 linków i w pełnym trzyetapowym łańcuchu we wszystkich czterech konfiguracjach. Różnice pojawiły się przy endpointach ujawnianych przez źródło JavaScript albo przez zmiany DOM w czasie działania.

W tym teście headless znalazł klasę opartą o runtime DOM, której nie zauważyły badane tryby bez przeglądarki, natomiast standardowy tryb z -jc znalazł literały w plikach JavaScript, których nie wykryły oba uruchomienia headless. Żaden wiersz w macierzy czterech komend nie pokrył obu klas naraz. Dodatkowe granice praktyczne wyznaczały scope, resume i zachowanie known-files.

Czym właściwie jest katana

Crawler katana — projectdiscovery/katana na GitHubie — jest napisany w Go i wydany na licencji MIT. Testowałem v1.6.1 27 lipca 2026 r.; wersja ma znaczenie, bo wnioski o pokryciu i known-files poniżej są obserwacjami zależnymi od konkretnego buildu.

Tu kategoria ma większe znaczenie niż zwykle. Crawler do wykrywania endpointów nie jest ekstraktorem danych. Jeśli szukasz go web crawlera, który zwróci nazwy produktów i ceny jako uporządkowany JSON, katana jest zupełnie nie tym narzędziem — z przyjemnością powie Ci, że /products/1138 istnieje, ale nie powie nic o tym, co znajduje się na tej stronie. Tak właśnie ma działać, a ocenianie jej pod kątem ekstrakcji byłoby jak recenzowanie wykrywacza metalu za to, czy umie wycenić biżuterię.

To narzędzie jest stworzone do reconu w security ofensywnej i automatyzacji pipeline’ów: STDIN do środka, URL-e na wyjściu, a potem przekazanie wyników do kolejnego narzędzia. I tu od razu ważne zastrzeżenie — wszystkie pomiary wykonałem na lokalnym fikcyjnym serwerze na 127.0.0.1, który sam napisałem. Używaj katany wyłącznie wobec hostów, do których masz prawo testów i które są przez Ciebie autoryzowane. Nie chodzi tu o obchodzenie zabezpieczeń — tylko o to, ile powierzchni endpointów dany wynik rzeczywiście wylicza.

Trzy tryby i to, co każdy z nich widzi

Tryb standardowy to klient HTTP w Go. Pobiera strony, parsuje HTML, podąża za href i nigdy nie uruchamia przeglądarki. Jest szybki, tani i ślepy na wszystko, co pojawia się dopiero po wykonaniu JavaScriptu.

-jc (-js-crawl) dokłada parser JavaScript do tej ścieżki bez przeglądarki. Pobiera podłączone pliki .js i wyciąga ze źródła stringi wyglądające jak URL-e. Bez wykonywania kodu — tylko odczyt. Jest też -jsl (jsluice), opisany w README jako cięższy i bardziej pamięciożerny parser — nie testowałem go, więc nie mogę powiedzieć, czy zmienia obraz pokrycia.

System diagram: Scope Is Applied in Layers

-headless uruchamia Chromium i wykonuje skrypty strony. W tym teście był to jedyny badany tryb Katany, który odzyskał ścieżkę złożoną z fragmentów i wstrzykniętą do runtime DOM. Ten wynik nie przesądza, co odzyska każdy parser albo przyszły tryb Katany.

Jest jeszcze model scope — i to jest część, którą warto zapamiętać zanim wpisze się cokolwiek produkcyjnego.

FlagaCo kontrolujeWartości / domyślne
-fs (field scope)które hosty wchodzą w grędn, rdn, fqdn albo własny regex — domyślnie rdn
-cs i -cosregexy URL-i, które filtrują wewnątrz tego field scope
-kfknown files: robots.txt i sitemap.xmlw README podano, że wymaga minimalnej głębokości 3
-dgłębokośćdomyślnie 3
-resumewznawia przerwany crawl

Kolejność nie jest kosmetyczna: decyduje, czy regex hosta rozszerzy crawl, czy po cichu wyczyści go do zera.

Konfiguracja: jedna binarka, jeden gwiazdkowy wyjątek

Są trzy drogi instalacji i tylko jedna wymaga toolchaina:

Sposób instalacjiWymaganie
Ze źródeł: go install github.com/projectdiscovery/katana/cmd/katana@latestwymagana jest wersja Go 1.25 lub nowsza
Prekompilowane binarki na stronie releasebez toolchaina
Obraz Dockerbez toolchaina

U mnie binarka trafiła do ~/go/bin/katana i przy każdym uruchomieniu raportowała Current version: v1.6.1. Na tym etapie klasyczna przyjemna historia Go: jeden plik, bez runtime.

Gwiazdkowy wyjątek dotyczy headless, gdzie przeglądarka jest osobnym wymaganiem względem binarki:

Gdzie działa -headlessCzego potrzebuje
Na mojej maszyniekatana automatycznie wykryła już zainstalowane Chromium; nie zapisałem wersji przeglądarki ani nie podawałem ścieżki
Na czystym serwerze, zgodnie z instrukcjami projektu dla Ubuntunajpierw apt install google-chrome-stable, zanim headless zacznie działać
W wariancie Dockerdziała headless z -system-chrome

Na czystym serwerze ta wygoda znika. Gdy tylko -headless pojawia się w poleceniu, trzeba budżetować nie tylko binarkę, ale i przeglądarkę.

Jeszcze jedna drobna rzecz, warta uwagi, jeśli uruchamiasz to w CI: katana przy starcie sprawdza wersję na GitHubie. -duc wyłącza ten check. Na laptopie to szum, ale na runnerze bez dostępu do sieci albo z limitem żądań to dodatkowy round trip sieciowy przy każdym uruchomieniu, o który nie prosiłeś. W moich pomiarach czasu użyłem -duc, żeby liczby odzwierciedlały crawl, a nie telefon do domu.

Jak to testowałem

Trzy klasy endpointów, dobrane specjalnie tak, by rozdzielały tryby. Całość działa na lokalnym serwerze testowym, a stan referencyjny został zapisany zanim wystartował jakikolwiek crawl, więc recall liczy się względem stałego zestawu, a nie tego, co akurat wypisała katana.

  • Klasa A — zwykły HTML. /page/a, /page/b, /page/c oraz trzyetapowy łańcuch /depth/1 → /depth/2 → /depth/3. Każdy crawler powinien to złapać.
  • Klasa B — literały w pliku JavaScript. /api/js-endpoint-7 i /api/js-endpoint-8 istnieją tylko jako stringi w podłączonym /static/app.js. Da się je odczytać bez przeglądarki, o ile coś w ogóle czyta JS.
  • Klasa C — tylko runtime DOM. Ścieżka składana w czasie działania z fragmentów ('endpoint' + (6 * 7)) i wstrzykiwana do DOM przez skrypt. String /runtime-only/endpoint42 nie występuje ciągiem w żadnym bajcie wysyłanym przez serwer — ani w HTML, ani w źródle JS. Tylko wykonanie ujawnia tę ścieżkę.

Do tego robots.txt, sitemap.xml z dwoma endpointami <loc> niewystępującymi nigdzie indziej, route zwracający 500, martwy link i link poza zakresem prowadzący do drugiego serwera na innym hostname.

Równie ważny jak fixture jest instrument: serwer liczy to, co faktycznie zostało pobrane, więc twierdzenia o scope i resume opierają się na prawdzie z hit logów, a nie na stdout Katany. Surowe uruchomienia są w repo benchmarkowym, jeśli chcesz sprawdzić moje rachunki.

Różnica w pokryciu, której nikt nie mierzy

Measured results chart: Endpoint coverage by Katana mode

Macierz, tryb względem klasy endpointu, przy -d 4:

TrybLinki HTML (A)Łańcuch głębokości (A)Literały z pliku JS (B)Runtime DOM (C)
standard4/43/30/2nie znaleziono
standard -jc4/43/32/2nie znaleziono
-headless4/43/30/2znaleziono
-headless -jc4/43/30/2znaleziono

Jeśli czytać dwie ostatnie kolumny razem, problem od razu wychodzi na wierzch. Klasa B została znaleziona tylko przez jedną konfigurację: standardowy tryb z -jc. Klasa C została znaleziona tylko przez dwie: oba uruchomienia headless. Nie ma wiersza, który trafia w obie kolumny naraz. Pełna macierz jest w discovery-summary.json, gdzie obliczone pole headless_jc_covers_both ma wartość false.

Praktyczny wniosek jest taki, że „po prostu użyj headless, będzie lepsze pokrycie” okazało się tu zbyt uproszczone. Headless nie dodał klasy B do wyniku standardowego; odzyskał klasę C, ale nie znalazł klasy B. Pokrycie wszystkich zasadzonych klas w tym fixture wymagało dwóch crawlów i scalenia:

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

Wiersz -headless -jc to ten, na który najchętniej zobaczyłbym odpowiedź upstream. Dodanie parsera JavaScript do uruchomienia headless nie odzyskało niczego — dalej 0/2 dla klasy B, w każdym uruchomieniu, także po świeżej reprodukcji. Raportuję zachowanie, nie twierdzę, że prześledziłem mechanizm; nie instrumentowałem wnętrza Katany, by sprawdzić, dlaczego ścieżka przeglądarkowa przestaje wnosić literały z plików JS. Traktuj to jako powtarzalną obserwację i dobry issue na GitHubie, a nie diagnozę. (Warto przy tym odnotować, że kombinacja -hl -jc kończyła się poprawnie z kodem 0 w v1.6.1 na macOS ARM, co historycznie nie zawsze było prawdą.)

Oficjalna dokumentacja opisuje headless jako dający lepsze pokrycie, i faktycznie tak było dla klasy renderowanej w runtime w tym teście. Zweryfikowane wskazówki nie opisały jednak tego rozdziału source-literal/runtime-DOM, więc potraktuj tę macierz jako powód, by przetestować obie ścieżki na własnych klasach endpointów, a nie jako uniwersalną taksonomię.

Ile kosztuje headless w czasie wall clock

Trzy kolejne uruchomienia na tryb na inaczej bezczynnej maszynie:

Trybp50min–maxśrednia
standard13.08s13.07–13.17s13.11s
-headless66.82s66.78–67.68s67.09s

To stosunek 5,1x, a zakresy nawet się do siebie nie zbliżają — mój najwolniejszy run standardowy (13.17s) nadal był o ponad 53 sekundy szybszy od mojego najszybszego uruchomienia headless (66.78s) (cost-summary.json). To nie jest szum pomiarowy.

Jedno zastrzeżenie do tych 13 sekund: moja fixture celowo zawiera route 500 i martwy link, a tryb standardowy spędza przy obu domyślny ogon ponownych prób -timeout 10. Nie stroiłem timeoutu tak, by ładniej wyglądał szybki tryb, co oznacza, że po optymalizacji standardowy run prawdopodobnie jeszcze bardziej rozszerzyłby różnicę, a nie ją zmniejszył.

Ten współczynnik to lokalny sygnał pojemności, nie prognoza produkcyjna. Prawdziwe cele różnią się opóźnieniami, liczbą błędów, pracą skryptów i planowaniem zadań, podczas gdy ta fixture zawiera domyślny ogon timeoutu. Użyj zmierzonej różnicy 5,1x, żeby zdecydować, czy headless zasługuje na osobny budżet i podzbiór celów, a potem sprawdź ten plan na reprezentatywnych, autoryzowanych hostach.

Scope się utrzymał, ale jedna flaga po cichu nic nie zrobiła

Test scope używał dwóch serwerów: głównego na 127.0.0.1 oraz drugiego dostępnego jako localhost na innym porcie, serwującego ścieżkę, która istnieje wyłącznie tam. Trafienie w tę ścieżkę dowodzi więc, że host poza zakresem został rzeczywiście pobrany, a nie tylko wypisany.

KonfiguracjaHost poza zakresem pobrany?Trafienia na drugim serwerze
domyślna (-fs rdn)nie0
-fs fqdnnie0
-cs localhostnie0
`-fs '(127.0.0.1localhost)'`tak

Dyscyplina scope to dobra wiadomość: domyślnie katana zostawała w granicach, a rozszerzenie wymagało świadomego działania. To właściwy default dla narzędzia, które trafia do cudzej infrastruktury.

Najciekawszy jest wiersz -cs localhost. Nie rozszerzył on crawl’a na drugi host — i jednocześnie zwrócił zero URL-i. Ponieważ -cs filtruje wewnątrz field scope, a field scope nadal wskazywał na główny host, regex nie dopasował niczego i crawl zwrócił pusty zbiór zamiast błędu. Jeśli kiedyś pisałeś regex scope’u na host, który chciałeś dołączyć, i patrzyłeś w pusty plik wyjściowy, to właśnie ten mechanizm (scope-summary.json). Żeby dodać host, ustaw -fs. Żeby zawęzić już posiadane hosty, użyj -cs/-cos.

Resume jest bardziej zgrubne, niż sugeruje flaga

README opisuje flagę jako -resume string resume scan using resume.cfg, co brzmi jak plik lądujący w katalogu roboczym. Tak nie jest. Na mojej maszynie checkpoint był zapisywany do ~/.config/katana/resume-<xid>.cfg — zmierzone, nie odczytane z dokumentacji, bo dokumentacja nie podaje ścieżki.

Zawartość jest jeszcze ciekawsza. Plik trzymał mapę InFlightUrls zawierającą dokładnie jedną rzecz: seed URL. Nie odwiedzone URL-e, nie frontiera. I właśnie tak wyglądało to, gdy przerwałem crawl SIGINT-em po trzech sekundach i potem go wznowiłem:

UruchomienieUnikalne ścieżki
Pełny crawl bazowy11
Pobranie przed przerwaniem10
Ponownie pobrane przez wznowieniewszystkie 11, w tym wszystkie 10 już ukończonych

Resume doprowadziło do tego samego finalnego zestawu endpointów, więc nic nie jest zepsute. Ale ziarnistość checkpointu jest na seed wejściowy, nie na pojedynczy URL — filtr deduplikacji w pamięci nie jest nigdzie utrwalany, więc wznowienie crawl’a z jednym seedem przechodzi przez ten seed od zera (resume-summary.json). Jeśli podasz katanie listę 500 hostów, resume powinno oszczędzić hosty, które zakończyły się w całości; to zachowanie wieloseedowe wynika z tego, jak przechowywany jest stan, ale ja mierzyłem tylko przypadek z jednym seedem. Jeśli siedzisz głęboko w jednej ogromnej witrynie, resume daje Ci poprawność, nie czas.

Known files: poproszone, a potem porzucone

System diagram: Known files: requested, then dropped

-kf all -d 3 rzeczywiście pobrało oba pliki — robots.txt i sitemap.xml pojawiły się w logu hitów serwera — a potem odzyskało 0 z 2 endpointów wypisanych w elementach <loc> tej sitemap. Recall 0.0.

Zanim uznałem to za ograniczenie, próbowałem zrobić z tego swój błąd. Każda wariacja dawała to samo:

Przetestowana wariacjaOdzyskane endpointy z sitemap <loc>
-kf all0/2, recall 0.0
-kf sitemapxml0/2, recall 0.0
-kf robotstxt0/2, recall 0.0
depth 30/2, recall 0.0
depth 40/2, recall 0.0
depth 50/2, recall 0.0
z dodanym -jc0/2, recall 0.0
z seedem bezpośrednio na /sitemap.xml0/2, recall 0.0

Wymóg opisany w dokumentacji — użyj -kf i wejdź przynajmniej trzy poziomy głębokości — był spełniony za każdym razem. To nie jest historia o brakującej fladze.

Najpierw decyzja praktyczna: na tej testowej konfiguracji opartej na IP nie zakładaj, że samo zażądanie known files oznacza, że URL-e z <loc> zostały dołączone do crawl’a. Sprawdź recall albo wyciągnij i zasiej te URL-e samodzielnie.

Kod v1.6.1 jest spójny z tą obserwacją, ale nie instrumentowałem go podczas uruchomienia. W sitemapxml.go w v1.6.1 NewNavigationRequestURLFromResponse buduje requesty na podstawie <loc> bez wypełnionego RootHostname. Następnie request trafia do ValidateScope; w scope.go w v1.6.1 gałąź dla IP-literal porównuje host URL-a z tym pustym rootem i może go odrzucić. Własna komenda -fs '(127.0.0.1|localhost)' w innym teście scope przeszła inną gałąź walidacji, więc jest to przewidziane ze źródła obejście, a nie zmierzony workaround dla -kf. Próba potwierdzenia została zablokowana przez sporadyczne problemy z dialowaniem w kliencie known-files na tym hoście; raportowany wynik pozostaje więc 0/2.

W praktyce, dopóki ktoś nie potwierdzi tej flagi, zrobiłbym tak: pobrać sitemapę samemu, wyciągnąć URL-e z <loc> i podać je katanie jako listę seedów. Dwie linie shellowe, bez walidacji scope po drodze.

Jedna rzecz zachowywała się dokładnie tak, jak powinna, i zasługuje na zdanie: route 500 i martwy link zostały pobrane, zalogowane i pominięte. Każde uruchomienie bez przeglądarki kończyło się kodem 0. Crawler, który pada na pierwszym błędnym response, jest bezużyteczny bez nadzoru, a katana taki nie jest.

Jak przed wdrożeniem sprawdzić pokrycie dla konkretnego targetu

Macierz z fixture jest najbardziej użyteczna jako szablon do testowania własnych autoryzowanych targetów. Zdefiniuj klasy endpointów przed uruchomieniem Katany: zwykłe linki, literały w podłączonych skryptach, ścieżki tworzone dopiero po wykonaniu kodu i wpisy z known files to cztery rozsądne początkowe koszyki. Dla każdej klasy trzymaj mały zestaw ground truth. Bez takiej wcześniejszej listy większy stdout może wyglądać jak lepsze pokrycie, nawet jeśli jakaś klasa po prostu zniknęła.

Najpierw uruchom osobno ścieżki browserless i headless jako niezależne pomiary. Zapisz dokładne komendy, wersję Katany, wersję przeglądarki, kody zwrotne i output. Normalizuj i porównuj zbiory endpointów, zamiast zestawiać same liczby linii. Jeśli standardowe -jc nie wnosi nic unikalnego na Twoim próbku, polityka tylko-headless może wystarczyć; jeśli zbiory rozchodzą się tak jak tutaj, trzymaj oba przebiegi osobno i scal po zebraniu. Nie zakładaj, że dodanie obu flag do jednej komendy daje sumę, dopóki diff specyficzny dla targetu tego nie potwierdzi.

Zweryfikuj scope danymi spoza outputu Katany. Umieść canary URL na hoście, który ma pozostać wykluczony, i sprawdź log żądań po stronie serwera. Jeśli crawl ma się rozszerzyć na drugi host, przetestuj również ten docelowy drugi host. Uruchomienie -cs localhost tutaj wygenerowało pusty output, bo filtrowanie content-scope nie rozszerzyło field scope; własne wywołanie -fs '(127.0.0.1|localhost)' rzeczywiście połączyło się z drugim serwerem. Zapisanie dokładnego wyrażenia regularnego ma znaczenie, bo zmiana jednego znaku może zmienić regex, a nie tylko jego zapis.

Testuj przerwanie i known files osobno od recallu discovery. Dla resume przerwij reprezentatywny seed po kilku stronach, zapisz wygenerowaną ścieżkę checkpointu i policz, ile już ukończonych URL-i zostało pobranych ponownie. Dla -kf potwierdź zarówno to, że robots/sitemap zostały zażądane, jak i to, że zasiane URL-e z <loc> faktycznie trafiły do harmonogramu. To są różne twierdzenia. W tym teście pliki zostały pobrane, ale oba endpointy z sitemap zniknęły, więc do zobaczenia granicy potrzebne były zarówno logi żądań, jak i output endpointów.

Na koniec ustanów lokalny baseline kosztu, wykonując kolejne uruchomienia na bezczynnej maszynie, a potem powtórz to na reprezentatywnych hostach. Zachowaj minimum, maksimum i medianę, a nie tylko mnożnik. Współczynnik 5,1x tutaj uwzględnia błędy i timeout tej fixture; mówi Ci, że headless zasługuje na osobny budżet, a nie ile potrwa produkcyjny inventory crawl.

Plusy i minusy

Plusy:

  • Perfekcyjny recall dla zwykłego HTML we wszystkich trybach — 4/4 linków i pełny łańcuch 3/3, bez dodatkowej konfiguracji.
  • -jc działa naprawdę bez przeglądarki: 2/2 endpointów odzyskanych z literałów w podłączonym pliku JS, bez kosztu przeglądarki.
  • -headless jako jedyny znalazł endpoint złożony w czasie działania — klasę, która z definicji jest niewidoczna dla parsowania źródła.
  • Domyślne scope jest zachowawcze. Host poza zakresem nigdy nie został pobrany przy default, -fs fqdn ani -cs.
  • Jedna binarka Go, licencja MIT, prekompilowane buildy i obraz Docker, I/O w stylu pipeline.
  • Odporność na błędy: 500 i martwe linki nie zatrzymują crawl’a.

Minusy:

  • Żadna pojedyncza komenda nie pokryła jednocześnie endpointów z pliku JS i z runtime DOM. Pełne pokrycie wymaga dwóch uruchomień i scalenia.
  • -jc nie wnosił nic przy -headless — 0/2 dla klasy B w każdym uruchomieniu headless.
  • Headless kosztuje 5,1x czasu wall clock (p50 66.82s vs 13.08s, zakresy bez nakładania).
  • -resume ponownie pobiera ukończone strony w obrębie jednego seeda. Przywraca zestaw endpointów, nie Twój czas.
  • Known files zażądały robots.txt i sitemap.xml, ale odzyskały 0/2 endpointów <loc> z sitemap wobec targetu opartego na IP.
  • Headless po cichu wymaga obecnego w systemie Chromium; historia o „jednej binarce” kończy się na przeglądarce.
  • Tylko discovery. Bez ekstrakcji strukturalnej, bez konwersji treści, bez schematu pól.

Nie testowałem, więc poza zakresem tych liczb pozostaje: -jsluice, osobny test odcięcia głębokości na -d 1/-d 2, resume z wieloma seedami, automatyczne wypełnianie formularzy i jakakolwiek prawdziwa produkcyjna strona silnie oparta na JavaScript albo chroniona. Wszystkie liczby pochodzą z jednej maszyny (macOS arm64) i lokalnej fixture.

Dla kogo to jest, a kto powinien to pominąć

Jeśli Twoją pracą jest tworzenie inwentarza endpointów infrastruktury, do której masz prawo, katana ma właściwy kształt pipeline’u: plumbing STDIN/STDOUT, binarka do dystrybucji oraz tryby bez przeglądarki i z przeglądarką. W tym teście potrzebne było dwupasmowe scalanie; czy Twoje targety też tego wymagają, trzeba ustalić na reprezentatywnych stronach.

Pomiń to, jeśli chcesz danych, a nie adresów. Katana nigdy nie zwróci tabeli produktów; poda URL-e, pod którymi produkty mogą się znajdować, a do ekstrakcji służy coś innego. Pomiń też, jeśli potrzebujesz, by jedna komenda załatwiała wszystko — dwupasmowe scalanie jest w pipeline’ie w porządku, ale w promptcie bywa irytujące. A jeśli Twoje enumerate opiera się na endpointach <loc> z sitemap, a celem są adresy IP, sprawdź najpierw, co naprawdę dostajesz, zanim zaufasz wynikowi, bo na mojej fixture ta ścieżka zwracała nic.

Alternatywy i granica ekstrakcji

Katana jest darmowa, na licencji MIT i self-hostowana. To po Twojej stronie zostawia discovery, wybór trybu, deployment przeglądarki i scalanie wyników.

W open source sensowne porównania robi się raczej po zadaniu niż po języku. Colly to druga opcja w Go, ale jest biblioteką, którą kompilujesz z własnymi callbackami i w ogóle nie renderuje JavaScriptu. Crawl4AI uruchamia prawdziwą przeglądarkę i produkuje Markdown dla pipeline’ów LLM, co daje zupełnie inny output. Jeśli porównujesz kilka takich narzędzi naraz, nasze open-source scraper roundup zestawia te kategorie obok siebie.

Ujawnienie: Thunderbit to produkt wydawcy i nie był testowany w tej fixture Katany. Siedzi dalej w kategorii zarządzanej ekstrakcji, zamieniając strony na tekst lub rekordy strukturalne, zamiast wyliczać powierzchnię endpointów autoryzowanego targetu. Workflow może korzystać z obu kategorii, ale ten test dostarcza dowodów wyłącznie na zachowanie discovery Katany.

Wypróbuj Thunderbit do ekstrakcji danych z sieci

Werdykt

Użyj katany, gdy rezultatem ma być lista endpointów dla targetów, które wolno Ci crawlować, i możesz zweryfikować pokrycie trybów na tych właśnie celach. W tym teście standardowe -jc odzyskało zasiane literały z pliku JavaScript, a headless odzyskał endpoint wstawiany do runtime DOM; badane tryby bez przeglądarki nie odzyskały tej ścieżki runtime. Domyślny scope zatrzymał też drugi host poza pobraniem, a uruchomienia bez przeglądarki przechodziły dalej mimo 500 i martwego linku.

Zastrzeżenia są operacyjne: przy mieszanych klasach endpointów może być potrzebne scalanie z dwóch przebiegów, headless trwał lokalnie około pięć razy dłużej, single-seed resume ponownie pobierał ukończone ścieżki, a recall known-files wyniósł 0/2 wobec targetu IP. To są wyniki fixture v1.6.1, a nie gwarancje dla każdej strony. Wystarczą jednak, by zdefiniować kontrole, które powinno się powtórzyć w produkcyjnej ocenie.

Wypróbuj Thunderbit do ekstrakcji danych z sieci Get Started Free

FAQ

Gdzie katana zapisuje plik resume i czy wznawianie pomija strony, które już przeskanowałem? Checkpoint trafił do ~/.config/katana/resume-<xid>.cfg, a nie do resume.cfg w katalogu roboczym, jak sugeruje help przy fladze. I nie, nie pomija ukończonych stron: plik przechowuje tylko seed URL-e w locie, więc wznowiony crawl z jednym seedem pobrał ponownie wszystkie 11 ścieżek bazowych, w tym 10 już ukończonych. Dostajesz ten sam finalny zestaw endpointów, tylko bez zaoszczędzonego czasu.

Dlaczego -kf all pobrało moją sitemap.xml, ale nie przeskanowało URL-i w środku? Wobec targetu opartego na IP wynik ten jest spójny z granicą walidacji scope, a nie z pomyłką w fladze. W kodzie v1.6.1 parser sitemap Katany buduje każdy request <loc> bez przenoszenia dalej root hostname, a DNS-scope check dla hostów typu IP-literal może potem odrzucić taki URL; nie instrumentowałem uruchomienia, by to potwierdzić. Na każdej wersji flag, depth i seeda, które próbowałem, wynik pozostawał na 0 recall. Własny regex hosta w -fs przechodzi inną gałąź walidacji i to on, według źródeł, powinien pomóc — ale nie potwierdziłem tego przeciw -kf na swojej maszynie, więc traktuj to jako nieprzetestowane. Dzisiaj najbardziej ufałbym samodzielnemu wyciągnięciu URL-i z <loc> i podaniu ich katanie jako seedów.

Co powinienem zapisać, raportując test pokrycia Katany? Zanotuj dokładną wersję Katany i komendę, łącznie z wyrażeniem -fs zapisanym znak w znak; zdefiniuj klasy endpointów przed uruchomieniem; zachowaj server-side hit logi oprócz stdout; i oddzielaj obserwowane zachowanie od hipotez opartych na źródle. Dla uruchomień headless zapisuj też build przeglądarki — w tym teście tego nie zrobiono, co ogranicza reprodukcję.

Czy używać -jc, -headless, czy obu? Wybór zależy od klas endpointów, których potrzebujesz. W tej fixture standardowe -jc znalazło literały zapisane w pliku JavaScript, a headless znalazł endpoint wstawiony do runtime DOM. Żaden z tych trybów nie pokrył samodzielnie obu klas, więc dwupasmowe uruchomienie z deduplikacją było tutaj najrozsądniejsze dla mieszanego targetu.

Czy jeden błędny URL zatrzyma crawl? W tym kontrolowanym uruchomieniu nie. Katana kontynuowała po odpowiedzi 500 i martwym linku, a mimo to zwróciła pozostałe osiągalne ścieżki. To nie zastępuje produkcyjnego rozliczania błędów: trzymaj logi nieudanych requestów i ustal akceptowalny poziom błędów, żeby częściowo udany crawl nie został pomylony z pełnym pokryciem.

Ke
Ke
CTO w Thunderbit | Starszy data scientist i ekspert ML Dzięki prawie dziesięciu latom doświadczenia w uczeniu maszynowym i data science, Ke Shen jest absolwentem Columbia University i byłym starszym data scientistą w Walmart Labs. Dysponując dogłębną, uznaną przez branżowych ekspertów wiedzą w zakresie Python, R, Java i statystyki, dzieli się sprawdzonymi w boju spostrzeżeniami na temat wdrażania złożonych algorytmów AI — od teorii po architekturę gotową do produkcji.
Spis treści
Thunderbit · Agent AI do danych z internetu

Wyciągaj dane z dowolnej strony w 1 klik

Zaufało nam ponad 250 000 użytkowników
dostępny darmowy plan
Od strony do arkusza kalkulacyjnego
Opisz, czego potrzebujesz — Agent AI Thunderbit zbierze to i wyeksportuje do Excela, Google Sheets, Airtable lub Notion. Start jest darmowy.
Chrome Store Rating
PRODUCT HUNT#1 Product of the Week