Recenzja Apache Nutch: cztery granice, które decydują, czy działa i co potrafi znaleźć

Ostatnia aktualizacja: August 14, 2026
Recenzja Apache Nutch: cztery granice, które decydują, czy działa i co potrafi znaleźć
Podsumowanie AI
Apache Nutch to crawler rozwijany przez Apache Software Foundation, którego prace rozpoczęły się w 2004 roku. To system JVM oparty na Hadoopzie, zbudowany jako pętla, a nie pojedyncze polecenie strumieniowe: adresy startowe są wstrzykiwane do trwałej bazy, po czym następują kolejne rundy generate → fetch → parse → updatedb, z miejscami na pluginy odpowiedzialne za protokół, parser, filtrowanie URL-i i scoring. Zwykle wynik trafia do indeksu wyszukiwarki, takiej jak Solr lub Elasticsearch, a nie do CSV. Uruchomiłem Nutch 1.22 na kontrolowanej lokalnej stronie testowej — takiej, która loguje każde żądanie po stronie serwera, więc wyniki oceniam na podstawie tego, co naprawdę zobaczył serwer, a nie tego, co twierdził crawler.

Apache Nutch to crawler rozwijany przez Apache Software Foundation, którego prace rozpoczęły się w 2004 roku. To system JVM oparty na Hadoopie, zbudowany jako pętla, a nie pojedyncze polecenie strumieniowe: adresy startowe są injectowane do trwałej bazy, po czym następują kolejne rundy generate → fetch → parse → updatedb, z miejscami na pluginy odpowiedzialne za protokół, parser, filtrowanie URL-i i scoring. Zwykle wynik trafia do indeksu wyszukiwarki, takiej jak Solr lub Elasticsearch, a nie do CSV.

Uruchomiłem Nutch 1.22 na kontrolowanej lokalnej stronie testowej — takiej, która loguje każde żądanie po stronie serwera, więc wyniki oceniam na podstawie tego, co naprawdę zobaczył serwer, a nie tego, co twierdził crawler. Na przebieg testu wpłynęły cztery granice: wersja JDK, http.agent.name, zakres crawl’u oraz to, czy parse-js znajduje się w plugin.includes. Cały cykl był uruchamiany wielokrotnie z testowaną konfiguracją; zmiana JDK albo pozostawienie identyfikatora agenta pustego powodowały zatrzymanie jeszcze przed pobraniem użytecznych stron.

Granica JDK pojawia się zanim crawl w ogóle ruszy. Nutch 1.22 nie uruchomił się tutaj na JDK 26.0.1: pierwszy job Hadoop zakończył się błędem w Subject.getSubject(), po tym jak Java usunęła ścieżkę SecurityManagera. Nutch dołącza Hadoop 3.4.2, a poprawka pojawiła się dopiero w Hadoop 3.4.3, siedem dni po wydaniu Nutch 1.22. Osobno, parse-js zmienił odzyskiwanie dwóch literalnych adresów z pliku JavaScript z 0/2 do 2/2, bez uruchamiania przeglądarki.

Do czego służy Nutch, a do czego nie

Nutch nie jest scraperem. Nie służy do wyciągania ustrukturyzowanych pól: jego zadaniem jest wykrywanie i pobieranie URL-i na dużą skalę, utrzymywanie trwałej bazy tych adresów i ich stanów (crawldb) oraz przekazywanie segmentów do czegoś innego, co zamienia je w indeks. Jeśli skierujesz go na katalog, licząc na tabelę z nazwami i cenami, dostaniesz zamiast tego crawldb.

Ta architektura tłumaczy większość tego, co następuje dalej. Nutch wyprzedza erę crawlerów „jednobinarych” o około dwie dekady i został zbudowany do problemu, do którego stworzono Hadoop: pobierania większej liczby stron, niż mieści się na jednej maszynie. Uruchamianie go na laptopie przeciwko testowi z 12 stronami jest jak wynajęcie towarowego pociągu do przewiezienia regału — pouczające dla samego pociągu, ale niesprawiedliwe, jeśli oczekujesz ergonomii roweru.

Aktualna wersja to 1.22, ogłoszona 17 lutego 2026. Projekt jest na licencji Apache-2.0, repozytorium miało 3 272 gwiazdki i 8 otwartych zgłoszeń, gdy sprawdzałem je 27 lipca 2026, a gałąź master była wypchnięta cztery dni wcześniej. To projekt rozwijany, a nie porzucony — i właśnie tak należy patrzeć na problem z JDK: jako na okno pakietowania, które zamknęło się tydzień za wcześnie, a nie na zaniedbanie.

Macierz wersji: JDK 24+, Hadoop 3.4.2 i poprawka w dwóch liniach

Blokada wynika z trójstronnej zależności wersji, a jedyną częścią, którą kontrolujesz bezpośrednio, jest JDK, na którym działa Nutch. Pierwszy job Hadoop, uruchomiony na domyślnym JDK hosta, zakończył się błędem już na etapie inicjalizacji:

java.lang.UnsupportedOperationException: getSubject is not supported
    at java.base/javax.security.auth.Subject.getSubject(Subject.java:277)
    at org.apache.hadoop.security.UserGroupInformation.getCurrentUser(UserGroupInformation.java:588)
    at org.apache.nutch.crawl.Injector.inject(Injector.java:473)

Kod wyjścia 255. Zero pobranych stron. bin/nutch inject nawet nie dochodzi do sieci — inicjalizuje Hadoop LocalJobRunner, ten pyta, kim jest bieżący użytkownik, co wywołuje Subject.getSubject(), a JEP 486 zamienił tę operację w bezwarunkowy wyjątek, gdy JDK 24 trwale usunął SecurityManagera. Na hoście miałem OpenJDK 26.0.1, czyli daleko poza tą granicą.

Tradycyjna furtka awaryjna też nie działa. Dodanie -Djava.security.manager=allow, czyli flagi, która kiedyś przywracała stare zachowanie, zostaje odrzucone przez VM jeszcze zanim załaduje się kod Nutch:

Error occurred during initialization of VM
java.lang.Error: A command line option has attempted to allow or enable the Security
Manager. Enabling a Security Manager is not supported.

To kod wyjścia 1 i koniec drogi z założenia — ta flaga została usunięta razem z funkcją.

Źródłem problemu jest wersja Hadoop dołączona do Nutch 1.22. Błąd getSubject jest śledzony jako HADOOP-19212 i został naprawiony w Hadoop 3.4.3 oraz 3.5.0; Nutch 1.22 zawiera hadoop-common-3.4.2. Nutch 1.22 ukazał się 17 lutego 2026, a Hadoop 3.4.3 wyszedł mniej więcej tydzień później.

To nie jest też problem zależności od Solr ani klastra Hadoop. Często zakłada się, że Nutch potrzebuje klastra Hadoop i działającego Solr, żeby cokolwiek zrobić. To nieprawda. Tryb lokalny uruchamia wbudowany LocalJobRunner Hadoop — bez demona HDFS, bez YARN, bez klastra. Cały cykl inject → generate → fetch → parse → updatedb działa na jednej maszynie, bez niczego dodatkowego. Ściana JDK wynika wyłącznie z wersji biblioteki dołączonej do pakietu i zatrzymuje Cię jeszcze zanim w ogóle pojawi się pytanie o tę infrastrukturę.

Praktyczna macierz wersji, wszystkie trzy wiersze zmierzone:

Użyte JDKPolecenieWynik
OpenJDK 26.0.1bin/nutch injectNie działa, rc=255 — UnsupportedOperationException: getSubject is not supported
OpenJDK 26.0.1bin/nutch inject + -Djava.security.manager=allowNie działa, rc=1 — VM odmawia startu
OpenJDK 17.0.20 (LTS)bin/nutch injectDziała, rc=0 — Total new urls injected: 1

Naprawa wymaga dwóch poleceń. Zainstaluj JDK LTS i wskaż je Nutchowi:

brew install openjdk@17
export NUTCH_JAVA_HOME=/opt/homebrew/opt/openjdk@17

To instalacja typu keg-only, więc nie zmienia systemowego domyślnego JDK. Własne CI Nutch celuje w Java 17, a projekt publicznie ogłosił, że 1.22 jest ostatnim wydaniem działającym na Java 11, a 1.23 będzie wymagał Java 17. Zatem JDK LTS nie jest obejściem — to wspierana konfiguracja. Rozjazd dotyczy tego, co wspiera Nutch, a co daje brew install openjdk w 2026 roku, a są to dwie różne kwestie, które zderzają się już przy pierwszym poleceniu.

Dalej wszystko działało na OpenJDK 17.0.20, gdzie cały cykl przebiegał czysto.

Konfiguracja w liczbach: 396 MB i jedna właściwość, która blokuje wszystko

„Ciężki” to słowo, po które sięga każdy, ale bez skali nic nie znaczy. Oto, co faktycznie zawiera rozpakowana dystrybucja binarna Nutch 1.22:

ElementDystrybucja binarna Nutch 1.22
Rozpakowany rozmiar≈396 MB
JAR-y w lib/188 (≈113 MB)
— w tym dołączony stos Hadoop13
Katalogi pluginów78
JAR-y w tych katalogach pluginów533
Pliki konfiguracyjne35
Skrypty w bin/2 — crawl i nutch

Dla porównania, nowoczesny crawler Go, taki jak katana, dostarcza się jako jeden binarny plik o wielkości około 50 MB, bez JVM i bez zewnętrznych JAR-ów.

Potem jest jeszcze bramka, o której nikt nie ostrzega. Dołączony nutch-site.xml jest pusty, a http.agent.name domyślnie ma pusty ciąg. Bez tej wartości mój pierwszy crawl pobrał zero ścieżek i zalogował:

ERROR Fetcher: No agents listed in 'http.agent.name' property.

Ustawienie tylko tej jednej właściwości — niczego więcej — od razu sprawiło, że pobieranie zaczęło działać. Gdy pole pozostało puste, polecenie zakończyło się bez pobierania stron, a log pokazał powyższy błąd z nazwą agenta; nie było to ciche niepowodzenie.

Minimalna działająca konfiguracja okazała się składać z trzech elementów: conf/nutch-site.xml (nazwa agenta, zestaw pluginów, zakres), conf/regex-urlfilter.txt (ograniczenie do hosta) oraz pliku z seed URL. To nie jest dużo. Po prostu o trzy pliki więcej niż crawler run <url>.

Co znalazł: przełącznik pluginu, który ma znaczenie

System diagram: What it found: the plugin toggle that matters

Strona testowa miała trzy celowo różne klasy endpointów, a zachowanie Nutch rozdzieliło się po nich bardzo wyraźnie:

  • Klasa A — zwykłe linki HTML (4 strony, plus łańcuch o głębokości 3 linków)
  • Klasa B — endpointy istniejące wyłącznie jako literały tekstowe wewnątrz powiązanego pliku JavaScript: jeden jako argument wywołania, fetch('/api/js-endpoint-7'), drugi jako przypisanie, const other = "/api/js-endpoint-8"
  • Klasa C — endpoint istniejący dopiero po wykonaniu JavaScriptu i wstrzyknięciu go do DOM

Wyniki z logów trafień po stronie serwera, powtórzone trzy razy:

Konfiguracja pluginówKlasa A (linki HTML)Klasa B (literały w pliku JS)Klasa C (DOM w runtime)
Domyślna z pakietu — parse-(html|tika)4/4 (recall 1.0)0/2 (recall 0.0)nieosiągnięta
Z parse-jsparse-(html|tika|js)4/4 (recall 1.0)2/2 (recall 1.0)nieosiągnięta

Identycznie we wszystkich trzech powtórzeniach. Deterministycznie.

Najbardziej niedoszacowany jest skok klasy B. Nutch znalazł oba endpointy osadzone w JavaScript bez uruchamiania przeglądarki, używając regexowego skanowania treści JS przez plugin parse-js. Sam plik app.js był pobierany w obu konfiguracjach — Nutch traktuje <script src> jako outlink niezależnie od ustawień — więc cała różnica polega na tym, czy ktoś czyta zawartość pliku, szukając ciągów przypominających URL. Po włączeniu pluginu obie formy literałów zostały wykryte.

Na tym teście domyślna konfiguracja Nutch i standardowy tryb katany osiągnęły ten sam zestaw klasy A, a Nutch z parse-js oraz katana z -jc osiągnęły klasy A i B bez przeglądarki. Wersja katany i pełne polecenie nie są w tym artykule podane, więc jest to raczej kontekst niż ścisły benchmark produktu.

Klasa C to uczciwy sufit. Żadna statyczna konfiguracja pluginów do niej nie dotarła, co jest zgodne z oczekiwaniami: odzyskanie endpointu istniejącego dopiero po wykonaniu skryptu wymaga faktycznego uruchomienia tego skryptu. Próbowałem też zamienić protocol-http na protocol-htmlunit, czyli czysto Javowy protokół Nutch wykonujący JS. Załadował się i działał bez crasha, ale w tym samym czterorundowym harnessie ukończył tylko jedną rundę, pobrał wyłącznie stronę startową i app.js, nie dotarł do A/B/C, a w rundzie drugiej zgłosił 0 records selected for fetching. To raczej słabo skonfigurowany probe niż wyrok dla możliwości HtmlUnit. Wniosek jest węższy: zamiana na protokół wykonujący JS nie jest zmianą typu plug-and-play, a klasa C pozostała nieosiągnięta we wszystkich testowanych przeze mnie konfiguracjach.

Sterowanie crawl’em i zachowanie przy błędach

Głębokość nie jest flagą. W Nutch nie ma --depth 3; głębokość to liczba rund generate → fetch → parse → updatedb, które uruchomisz, bo runda R pobiera frontier wykryty w rundzie R-1. Mój test łańcucha głębokości potwierdził to dokładnie:

Liczba uruchomionych rundNajgłębiej osiągnięta ścieżka
2/depth/1
3/depth/2
4/depth/3

Czysto i mechanicznie, ale oznacza to, że głębokość jest liczbą iteracji w skrypcie, a nie parametrem.

Teraz pułapka. Domyślne ustawienie Nutch to db.ignore.external.links=false, połączone z permissive +. w filtrze URL — co oznacza, że domyślny crawl Nutch będzie podążał za linkami poza host startowy. Zasiałem stronę zawierającą jeden link w zakresie oraz jeden prowadzący do innej nazwy hosta, a crawl pobrał host zewnętrzny. Dwa niezależne sygnały potwierdziły to samo: crawldb Nutch oznaczył go jako db_fetched, a licznik żądań na drugim serwerze odnotował trafienie.

Pozostanie w obrębie zakresu jest opcją włączaną świadomie, a oba sposoby działają i dają się zweryfikować:

KonfiguracjaZewnętrzny host w crawldbTrafienie na serwerze zewnętrznymCrawl ograniczony?
db.ignore.external.links=false (domyślne z pakietu)db_fetched+1Nie
db.ignore.external.links=truebrak0Tak
Reguła hosta w regex-urlfilter.txt (+^http://127.0.0.1: potem -.)brak0Tak

Jeśli crawlujesz jedną stronę, ustaw jedno z tych rozwiązań przed pierwszym realnym uruchomieniem. Jedna uwaga metodologiczna: ten konkretny test jest wrażliwy na obciążenie lokalnego serwera, więc te trzy wiersze pochodzą z uruchomienia, w którym nic innego nie dotykało fixture. Samo zachowanie jest mechanicznie jasne i potwierdzone przez dwa niezależne sygnały; konkretne wartości w wierszach to jeden czysty przebieg, a nie średnia z wielu.

Sitemapy to osobny krok. Politeness jest włączony — zwykły crawl pobrał /robots.txt — ale sam sitemap wymaga własnego polecenia:

PodejścieCzy zażądano /sitemap.xml?Endpointy istniejące tylko w sitemapie
Zwykły crawlnigdy nie zażądano0/2
bin/nutch sitemap, uruchomione jawnie wobec crawldbpobrano2/2 wpisów zainjectowanych, pełny recall
Wbudowany tryb -kf known-files katany, ten sam fixture, na hoście IPnie zarejestrowano0/2

To inny model niż crawle, które pobierają znane pliki „w locie”, i kosztuje jedno dodatkowe polecenie, ale wykonuje zadanie w pełni.

Dwa mniejsze zachowania również wypadły dobrze.

Obsługa błędów: crawl po stronie prowadzącej do 500 i 404 zakończył wszystkie rundy poprawnie, nadal pobrał wszystkie cztery strony klasy A i osobno zapisał każdy błąd:

Błędna odpowiedź podlinkowana ze stronyzapisany stan crawldb
500db_unfetched (kwalifikujące się do ponowienia)
404db_gone

Nic się nie rozsypało.

Politeness: przy jednym wątku na kolejkę odstęp między pobraniami z tego samego hosta odpowiadał ustawieniu:

fetcher.server.delayMediana przerwy między pobraniami z tego samego hosta
1.0 sekunda1.009 s (minimum 1.006 s)
0.00.002 s

Gałka robi dokładnie to, co obiecuje. Domyślna wartość to 5,0 sekundy, co jest konserwatywne i znowu prawdopodobnie słuszne dla narzędzia, które ma crawlować cudze serwery.

Koszt batchowania, w sekundach

Każde polecenie Nutch to świeży JVM. Sam ten fakt bardziej niż cokolwiek związanego z pobieraniem dominuje profil czasowy.

Faza (na rundę)Mediana w sekundach
inject (raz)1.81
generate3.93
fetch2.82
parse1.78
updatedb1.81
Jedna pełna runda12.14

Efektywne minimum na job — start JVM plus inicjalizacja Hadoop, mierzone jako najtańsza faza z trywialną pracą — to około 1,77 sekundy. Pomnóż to przez cztery polecenia na rundę, dodaj początkowy inject, a cały obraz crawl’u wygląda tak:

NarzędzieCrawl na głębokość 4 dla fixture 12-stronicowegoProcesy
Nutchokoło 45 sekund (zmierzyłem 45,8 s i 45,0 s dla dwóch konfiguracji)około 17 uruchomień JVM, z czego praktycznie żadne nie wykonują pracy sieciowej
katana w trybie standard, ten sam fixtureokoło 13 sekundjeden proces

Ta różnica nie wynika z przepustowości pobierania; oba narzędzia proszą o ten sam niewielki zestaw stron. To kwestia architektury. Nutch płaci stały koszt procesu za każdą fazę, bo te fazy są zaprojektowane jako joby MapReduce. Przy małym lokalnym crawl’u koszt przygotowania dominuje. Ten stały koszt powinien stanowić mniejszą część dłuższego zadania, ale ten test nie mierzył skali, przy której Nutch i katana się zrównują, ani tego, czy ich proporcja się odwraca.

Zalety i wady

Zalety

  • Deterministyczne wykrywanie statyczne: 4/4 w klasie HTML, 3/3 w łańcuchu głębokości, identycznie we wszystkich trzech powtórzeniach.
  • parse-js odzyskuje endpointy z literalami w plikach JavaScript (2/2) bez przeglądarki, łapiąc zarówno formę argumentu wywołania, jak i przypisania.
  • Dwa zweryfikowane mechanizmy ograniczania zakresu, które całkowicie zamykają crawl (db.ignore.external.links oraz hostowy regex-urlfilter).
  • Pobieranie sitemap przez bin/nutch sitemap osiągnęło pełny recall 2/2 dla endpointów, których zwykły crawl nie widział w ogóle.
  • Odporność na błędy: 500 i 404 obsłużone z różnymi stanami crawldb, crawl trwa dalej.
  • W tym lokalnym uruchomieniu zaobserwowany odstęp dla tego samego hosta był zgodny z ustawionym opóźnieniem 1,0 s; domyślna wartość z pakietu to 5,0 s.
  • Apache-2.0, aktywnie rozwijany projekt, 78 pluginów i trwały crawldb, który śledzi stan każdego URL między rundami.
  • Działa w trybie lokalnym bez klastra, bez HDFS i bez konieczności instalowania Solr.

Wady

  • Nie uruchamia się na JDK 24 ani nowszym, gdzie usuwa go zmiana SecurityManagera (ja zmierzyłem błąd na 26.0.1) — dołączony Hadoop 3.4.2 jest starszy niż poprawka upstream, a flaga awaryjna już nie istnieje, więc pin do JDK LTS jest twardym wymaganiem, a nie preferencją.
  • Około 396 MB po rozpakowaniu, 188 JAR-ów bibliotecznych, 78 katalogów pluginów, 35 plików konfiguracyjnych.
  • Nowy JVM przy każdym poleceniu oznacza około 1,77 s stałego narzutu na fazę; około 45 s dla crawl’u głębokości 4 na 12 stronach wobec około 13 s dla jednoplikowego crawlera na identycznym materiale.
  • Domyślna konfiguracja podąża za linkami do zewnętrznych hostów; pozostanie tylko na jednej stronie trzeba włączyć świadomie.
  • http.agent.name w pakiecie jest pusty i fetcher nie rusza, dopóki go nie ustawisz.
  • Brak flagi głębokości — głębokość to liczba pętli, którą sam kontrolujesz.
  • Endpointy w runtime DOM były nieosiągalne we wszystkich testowanych konfiguracjach, a zamiana na protokół wykonujący JS nie była zmianą typu plug-and-play.
  • Testowałem tryb lokalny na jednym hoście i małym fixture. Tryb rozproszony/HDFS, indeksowanie do Solr, hostdb, resume i harmonogram inkrementalnego ponownego crawl’u nie były objęte tym przebiegiem — traktuj je tutaj jako nieprzetestowane, a nie jako potwierdzone.

Dla kogo to ma sens, a kto powinien odpuścić

Nutch sprawdza się wtedy, gdy najtrudniejsza jest sama faza crawl’u. Jeśli budujesz indeks wyszukiwania, prowadzisz szeroki crawl wielodomenowy, potrzebujesz trwałej bazy URL-i z informacją o stanie każdego adresu i retry semantics albo zakładasz, że w przyszłości rozdzielisz pracę na wiele maszyn, to jest infrastruktura, która wykonuje dokładnie tę pracę od czasów sprzed większości alternatyw. System pluginów pozwala zmieniać zachowanie protokołu, parsera, filtra i scoringu bez rozwidlana kodu. Domyślne ustawienia polityki uprzejmości są konserwatywne w sposób sugerujący, że autorzy naprawdę myśleli o dobrym zachowaniu wobec cudzych serwerów.

Odpuść, jeśli chcesz z kilku stron wyciągnąć dane strukturalne. Nutch je pobierze i przeparsuje, a potem odda Ci crawldb i segmenty, oczekując, że sam podłączysz indeksator. Odpuść, jeśli Twoje cele to aplikacje SPA renderowane po stronie klienta — klasa C pozostała nieosiągnięta we wszystkim, co uruchomiłem. Odpuść, jeśli Twój zespół nie pracuje na JVM, bo do obecnego stosu dokładane byłyby toolchain Java, pin do JDK LTS i 396 MB JAR-ów, których dziś tam nie ma. A jeśli zadanie brzmi: „crawl jednej strony, cztery poziomy w głąb, raz w tygodniu”, więcej czasu spędzisz na pętli rund i plikach konfiguracyjnych niż sam crawl jest wart.

Dla większości osób szukających scrapera właśnie ten ostatni przypadek jest tym prawdziwym. To nie jest zarzut wobec Nutch — to niedopasowanie między narzędziem a zadaniem. Jeśli chcesz zobaczyć szerszy rynek, nasz przegląd scraperów open source oraz najlepsze projekty web scraping na GitHubie omawiają lżejszą część tego spektrum bardziej szczegółowo.

Alternatywy, w tym miejsce naszego własnego stacku

Najpierw uczciwe zastrzeżenie: Nutch jest darmowy, ma licencję Apache, działa self-hosted i należy do Ciebie na zawsze, bez opłat za każde żądanie. To realna przewaga i nic poniżej tego nie unieważnia.

Powiązana recenzja: Recenzja Browsertrix Crawler.

W świecie open source porównanie zależy od tego, co optymalizujesz. Jeśli chcesz framework w Pythonie z kontrolą crawl’u i filozofią „najpierw request”, Scrapy jest bliższym odpowiednikiem dla wielu projektów; ten artykuł nie mierzył jednak jego rozmiaru instalacji na tych samych zasadach. Jeśli chcesz kompaktowego crawlera Go bez przeglądarki, Colly jest kolejną opcją do rozważenia. Jeśli problemem jest przekształcenie stron w treść gotową dla LLM, a nie samo odkrywanie URL-i, Crawl4AI działa na innym poziomie.

Usługa zarządzana, taka jak Thunderbit, przenosi pobieranie, renderowanie i ekstrakcję za API, podczas gdy Nutch trzyma stan crawl’u i infrastrukturę pod Twoją kontrolą. Thunderbit nie był uruchamiany na tym fixture, więc to porównanie modeli własności, a nie teza o identycznym recallu czy wydajności na dynamicznych stronach.

Wybór to kontrola kontra narzut i nie jest subtelny. Nutch daje pełną kontrolę, trwały crawldb, skalowanie klastrowe z założenia i zerowy koszt krańcowy — w zamian za JVM, pin do JDK LTS, 396 MB JAR-ów, pętlę rund i własną warstwę indeksującą. Zarządzane API daje ustrukturyzowany wynik już przy pierwszym wywołaniu i brak infrastruktury — w zamian za cennik za wywołanie i mniejszą kontrolę nad frontem crawl’u. Jeśli zadanie brzmi „zindeksuj 50 milionów stron”, model Nutch jest właściwy, a API byłoby absurdalne. Jeśli zadanie brzmi „zebrać strukturalne rekordy z 200 stron produktowych do czwartku”, prawdą jest odwrotność.

Wypróbuj Thunderbit do ekstrakcji danych webowych

Werdykt

Apache Nutch warto rozważyć, jeśli prowadzisz ciągły crawl wielodomenowy i już utrzymujesz infrastrukturę JVM. Na tym fixture statyczne wykrywanie było deterministyczne między powtórzeniami, parse-js znalazł oba literalne endpointy JavaScript, błędy pozostały zapisane w crawldb, a obserwowane odstępy między żądaniami odpowiadały skonfigurowanemu opóźnieniu.

Koszt wejścia należy oszacować uczciwie. Nutch 1.22 nie zadziałał tutaj na JDK 26.0.1; OpenJDK 17.0.20 to jedyna konfiguracja LTS zweryfikowana w tej recenzji, a Java 21 nie była testowana. Potem ustaw http.agent.name, jasno określ zakres i uwzględnij obserwowaną stałą granicę około 1,77 s na fazę w tym małym lokalnym uruchomieniu. To, czy taki kompromis ma sens, zależy od czasu trwania crawl’u, jego szerokości i potrzeby utrzymywania trwałego stanu.

Wypróbuj Thunderbit do ekstrakcji danych webowych Get Started Free

FAQ

Dlaczego Apache Nutch wyświetla błąd „getSubject is not supported”? Na JDK 24 lub nowszym JEP 486 sprawił, że Subject.getSubject() zawsze rzuca wyjątek, podczas gdy dołączony Hadoop 3.4.2 nadal go wywoływał. Pierwszy job Hadoop kończy się więc zanim pobrana zostanie jakakolwiek strona, a stara furtka -Djava.security.manager=allow nie uruchamia już VM. Użyj zweryfikowanej konfiguracji Java 17 i ustaw NUTCH_JAVA_HOME; Java 21 może być obsługiwana, ale ten test nie obejmował pełnego cyklu na tej wersji.

Na jakiej wersji Javy powinienem uruchamiać Nutch 1.22? Java 17 to najbezpieczniejsza odpowiedź — własne CI Nutch celuje właśnie w nią i u mnie działała bezproblemowo na OpenJDK 17.0.20. Java 11 również pozostaje wspierana dla 1.22, choć projekt ogłosił, że 1.23 będzie wymagał Java 17. Wszystko od JDK 24 wzwyż nie zadziała. Instalacja Homebrew typu keg-only (brew install openjdk@17) wraz z NUTCH_JAVA_HOME pozostawia systemowe domyślne JDK nietknięte.

Czy Nutch potrafi crawlować strony mocno oparte na JavaScript? Częściowo, i to rozróżnienie ma znaczenie. Po włączeniu pluginu parse-js Nutch znalazł oba endpointy, które istniały wyłącznie jako literały tekstowe w powiązanym pliku JavaScript — 2/2, bez udziału przeglądarki. Bez tego zestawu pluginów nie znalazł żadnego. Jednak endpoint, który pojawia się dopiero po wykonaniu JavaScriptu i zmianie DOM, pozostał nieosiągalny we wszystkich statycznych konfiguracjach, które testowałem, a zamiana na protokół HtmlUnit nie była w moim przebiegu zmianą plug-and-play. Dla aplikacji renderowanych po stronie klienta trzeba planować protokół wykonujący JS i realną konfigurację albo wybrać inne narzędzie.

Czy Nutch wymaga zainstalowanego Hadoop i Solr? Nie. Tryb lokalny uruchamia wbudowany LocalJobRunner Hadoop — bez klastra, bez demona HDFS, bez YARN — i cały cykl inject → generate → fetch → parse → updatedb działa na jednej maszynie bez niczego dodatkowego. Solr jest zwykłym miejscem docelowym dla indeksowania, ale sam crawl go nie wymaga. Trzeba jednak pamiętać, że JAR-y Hadoop są dołączone (13 z nich, wersja 3.4.2), i właśnie dlatego w ogóle istnieje problem zgodności z JDK.

Jak zatrzymać Nutch przed crawl’owaniem innych stron? Ustaw to jawnie, bo domyślna konfiguracja tego nie robi. Nutch 1.22 ma db.ignore.external.links=false oraz permissive filtr URL, a w moim teście crawl domyślny podążył za linkiem do innego hosta i pobrał go. Albo ustaw db.ignore.external.links=true w nutch-site.xml, albo dodaj regułę hosta do conf/regex-urlfilter.txt (na przykład +^https://example\.com/ a potem -.). Oba rozwiązania całkowicie ograniczyły crawl w testach, co potwierdziłem zarówno w crawldb Nutch, jak i w logu żądań drugiego serwera.

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 sieci

Wyodrębnij dane z dowolnej strony w 1 klik

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