Apache Nutch è un crawler della Apache Software Foundation il cui sviluppo è iniziato nel 2004. È un sistema JVM basato su Hadoop, organizzato come un ciclo e non come un singolo comando in streaming: gli URL iniziali vengono injectati in un database persistente, poi seguono i passaggi generate → fetch → parse → updatedb, con slot plugin per protocollo, parser, filtro URL e scoring. L’output tipico alimenta un indice di ricerca come Solr o Elasticsearch, non un CSV.
Ho eseguito Nutch 1.22 su un sito di test locale controllato — uno che registra ogni richiesta lato server, così i risultati vengono giudicati da ciò che il server ha davvero visto e non da ciò che il crawler dichiara. Quattro confini hanno determinato l’esecuzione: la versione del JDK, http.agent.name, l’ambito del crawl e la presenza di parse-js in plugin.includes. Il ciclo completo è stato eseguito più volte con la configurazione testata; basta cambiare il JDK o lasciare l’identità dell’agente non impostata e tutto si ferma prima di recuperare pagine utili.
Il limite del JDK emerge prima ancora che inizi il crawl. Nutch 1.22 non è partito qui su JDK 26.0.1: il primo job Hadoop è morto dentro Subject.getSubject() dopo che Java ha rimosso il percorso dello SecurityManager. Nutch include Hadoop 3.4.2, mentre la correzione è arrivata in Hadoop 3.4.3 sette giorni dopo il rilascio di Nutch 1.22. Separatamente, parse-js ha fatto passare il recupero di due literal JavaScript da 0/2 a 2/2 senza eseguire alcun browser.
A cosa serve Nutch, e a cosa no
Nutch non è uno scraper. L’estrazione strutturata dei campi non è il suo compito: scopre e recupera URL su larga scala, mantiene un database persistente di quegli URL e dei loro stati (il crawldb) e ti consegna segmenti che qualcos’altro trasforma in un indice. Se lo punti a un catalogo aspettandoti una tabella con nomi e prezzi, otterrai invece un crawldb.
Questa architettura spiega quasi tutto quello che segue. Nutch precede di circa vent’anni l’era dei crawler monobinary, ed è costruito per il problema per cui è stato costruito Hadoop: fare crawling di più pagine di quante ne possano stare su una singola macchina. Eseguirlo su un laptop contro un fixture da 12 pagine è come noleggiare un treno merci per spostare una libreria — utile per capire il treno, ma ingiusto aspettarsi l’ergonomia di una bicicletta.
L’ultima release è 1.22, annunciata il 17 febbraio 2026. È sotto licenza Apache-2.0, il repository contava 3.272 stelle e 8 issue aperte quando ho verificato il 27 luglio 2026, e il branch master era stato aggiornato quattro giorni prima. Si tratta di un progetto mantenuto, non abbandonato — ed è la lente giusta per leggere il problema del JDK: una finestra di packaging chiusa una settimana troppo presto, non trascuratezza.
La matrice delle versioni: JDK 24+, Hadoop 3.4.2 e una correzione di due righe
Il blocco è il risultato di un’interazione tra tre versioni, e l’unica parte davvero sotto il tuo controllo è il JDK su cui gira Nutch. Il primissimo job Hadoop, usando il JDK predefinito dell’host, è morto durante l’inizializzazione:
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)
Codice di uscita 255. Zero pagine recuperate. bin/nutch inject non arriva nemmeno alla rete — inizializza un LocalJobRunner di Hadoop, che chiede chi sia l’utente corrente, il che chiama Subject.getSubject(), che JEP 486 ha trasformato in un’eccezione obbligatoria quando JDK 24 ha rimosso in modo definitivo lo SecurityManager. Il mio JDK host era OpenJDK 26.0.1, ben oltre quella soglia.
Nemmeno la via di fuga tradizionale funziona. Aggiungere -Djava.security.manager=allow, il flag che un tempo riattivava il vecchio comportamento, viene rifiutato dalla VM prima ancora che il codice di Nutch venga caricato:
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.
Questo produce codice di uscita 1, ed è un vicolo cieco per scelta — il flag è stato rimosso insieme alla funzione.
La causa di fondo è nella versione di Hadoop inclusa in Nutch 1.22. Il problema di getSubject è tracciato come HADOOP-19212 e corretto in Hadoop 3.4.3 e 3.5.0; Nutch 1.22 include hadoop-common-3.4.2. Nutch 1.22 è uscito il 17 febbraio 2026 e Hadoop 3.4.3 è arrivato circa una settimana dopo.
Non è nemmeno un problema di dipendenza da Solr o da un cluster Hadoop. Si pensa spesso che Nutch richieda un cluster Hadoop e un Solr attivo per fare qualsiasi cosa. Non è così. La modalità locale usa il LocalJobRunner in-process di Hadoop — niente demone HDFS, niente YARN, niente cluster. L’intero ciclo inject → generate → fetch → parse → updatedb gira su una singola macchina senza installare altro. Il muro del JDK è puramente una questione di versione di una libreria inclusa, e ti blocca prima ancora che entri in gioco la questione dell’infrastruttura.
La matrice pratica delle versioni, con tutti e tre i casi misurati:
| JDK usato | Comando | Risultato |
|---|---|---|
| OpenJDK 26.0.1 | bin/nutch inject | Fallisce, rc=255 — UnsupportedOperationException: getSubject is not supported |
| OpenJDK 26.0.1 | bin/nutch inject + -Djava.security.manager=allow | Fallisce, rc=1 — la VM rifiuta l’avvio |
| OpenJDK 17.0.20 (LTS) | bin/nutch inject | Funziona, rc=0 — Total new urls injected: 1 |
La correzione richiede due comandi. Installa un JDK LTS e punta Nutch lì:
brew install openjdk@17
export NUTCH_JAVA_HOME=/opt/homebrew/opt/openjdk@17
Essendo keg-only, non tocca il JDK di sistema. La CI di Nutch punta già a Java 17 e il progetto ha annunciato pubblicamente che la 1.22 è l’ultima release eseguibile su Java 11 e che la 1.23 richiederà Java 17. Quindi un JDK LTS non è un workaround: è la configurazione supportata. Il disallineamento è tra ciò che Nutch supporta e ciò che brew install openjdk ti consegna nel 2026, e sono due domande diverse che si scontrano proprio al primo comando.
Da qui in poi tutto è stato eseguito su OpenJDK 17.0.20, dove l’intero ciclo è pulito.
Setup misurato: 396 MB e una proprietà che blocca tutto
“Pesante” è l’aggettivo che tutti usano, ma senza una misura non serve a nulla. Ecco cosa contiene davvero la distribuzione binaria unpacked di Nutch 1.22:
| Elemento | Distribuzione binaria di Nutch 1.22 |
|---|---|
| Dimensione unpacked | ≈396 MB |
Jar in lib/ | 188 (≈113 MB) |
| — di cui lo stack Hadoop incluso | 13 |
| Directory plugin | 78 |
| Jar dentro quelle directory plugin | 533 |
| File di configurazione | 35 |
Script in bin/ | 2 — crawl e nutch |
Per dare un’idea della scala, un crawler Go moderno come katana viene distribuito come un unico binario da circa 50 MB, senza JVM e senza jar esterni.
Poi c’è il gate di cui nessuno ti avverte. Il nutch-site.xml fornito è vuoto e http.agent.name ha come default una stringa vuota. Con quel valore non impostato, il mio primo crawl ha recuperato zero percorsi e ha registrato:
ERROR Fetcher: No agents listed in 'http.agent.name' property.
Impostare quella sola proprietà — nient’altro — ha sbloccato il fetch. Con la proprietà vuota, il comando si è concluso senza recuperare pagine e il log ha riportato l’errore sull’agent name qui sopra; non è stato silenzioso.
La configurazione minima funzionante si è rivelata composta da tre elementi: conf/nutch-site.xml (nome agente, set di plugin, scope), conf/regex-urlfilter.txt (scoping per host) e un file con gli URL seed. Non è un numero eccessivo. Sono solo tre file in più rispetto a crawler run <url>.
Cosa ha trovato: il toggle del plugin che conta davvero

Il sito di test aveva tre classi di endpoint appositamente diverse, e il comportamento di Nutch si è separato in modo netto:
- Classe A — normali link HTML (4 pagine, più una catena profonda 3 link)
- Classe B — endpoint che esistono solo come literal di stringa all’interno di un file JavaScript linkato: uno come argomento di una chiamata,
fetch('/api/js-endpoint-7'), uno come assegnazione,const other = "/api/js-endpoint-8" - Classe C — endpoint che esiste solo dopo l’esecuzione di JavaScript, quando viene inserito nel DOM
Risultati, dai log lato server, ripetuti tre volte:
| Configurazione plugin | Classe A (link HTML) | Classe B (literal in file JS) | Classe C (DOM runtime) |
|---|---|---|---|
Default fornito — parse-(html|tika) | 4/4 (recall 1.0) | 0/2 (recall 0.0) | non raggiunta |
Con parse-js — parse-(html|tika|js) | 4/4 (recall 1.0) | 2/2 (recall 1.0) | non raggiunta |
Identico in tutte e tre le ripetizioni. Deterministico.
Il salto della classe B è quello che tende a essere sottovalutato. Nutch ha trovato entrambi gli endpoint incorporati in JavaScript senza eseguire un browser, usando la scansione regex del contenuto JavaScript fatta dal plugin parse-js. Il file app.js è stato comunque recuperato in entrambe le configurazioni — Nutch tratta <script src> come un outlink a prescindere — quindi l’unica differenza è se qualcuno legge il contenuto del file alla ricerca di stringhe che sembrano URL. Attivando il plugin, entrambi i formati letterali vengono intercettati.
Su questo fixture, Nutch in modalità predefinita e katana in modalità standard hanno raggiunto lo stesso set di classe A, mentre Nutch con parse-js e katana con -jc hanno raggiunto le classi A e B senza browser. La versione di Katana e il comando completo non sono riportati in questo articolo, quindi questo risultato è un confronto di contesto e non un benchmark di prodotto rigoroso.
La classe C è il limite onesto. Nessuna configurazione statica l’ha raggiunta, ed è atteso: recuperare un endpoint che esiste solo dopo l’esecuzione dello script richiede davvero di eseguire lo script. Ho provato anche a sostituire protocol-http con protocol-htmlunit, il protocollo Java puro di Nutch che esegue JavaScript. Si è caricato e avviato senza crash, ma nello stesso harness a quattro round ha completato solo un round, ha recuperato solo la pagina seed e app.js, non ha raggiunto né A né B né C, e il secondo round ha riportato 0 records selected for fetching. Questo indica un probe configurato in modo insufficiente, non un verdetto sulle capacità di HtmlUnit. Quello che stabilisce è più ristretto: sostituire il protocollo con uno che esegue JavaScript non è un cambio plug-and-play, e la classe C è rimasta irraggiungibile in ogni configurazione testata.
Controllo del crawl e comportamento in caso di errore
La profondità non è un flag. In Nutch non esiste --depth 3; la profondità corrisponde a quanti round generate → fetch → parse → updatedb esegui, perché il round R recupera la frontiera scoperta nel round R-1. La mia catena di profondità lo ha confermato con precisione:
| Round eseguiti | Percorso più profondo raggiunto |
|---|---|
| 2 | /depth/1 |
| 3 | /depth/2 |
| 4 | /depth/3 |
Pulito e meccanico, ma significa che la profondità è un conteggio di loop nel tuo script, non un parametro.
Ora la trappola. Il default fornito da Nutch è db.ignore.external.links=false, abbinato a un filtro URL permissivo +. — il che significa che un crawl Nutch predefinito seguirà i link anche fuori dall’host seed. Ho inserito una pagina con un link a un percorso interno e un link verso un hostname diverso, e il crawl ha recuperato l’host esterno. Due segnali indipendenti hanno concordato: il crawldb di Nutch lo segnava come db_fetched, e il contatore server dell’altro host registrava la richiesta.
Restare nel perimetro è una scelta esplicita, e entrambe le soluzioni funzionano in modo verificabile:
| Configurazione | Host esterno nel crawldb | Hit lato server dell’host esterno | Contenuto? |
|---|---|---|---|
db.ignore.external.links=false (default fornito) | db_fetched | +1 | No |
db.ignore.external.links=true | assente | 0 | Sì |
Regola host in regex-urlfilter.txt (+^http://127.0.0.1: poi -.) | assente | 0 | Sì |
Se stai facendo crawling di un solo sito, imposta una di queste opzioni prima del primo run reale. Una nota metodologica: questo test è sensibile al carico sul server locale, quindi quelle tre righe provengono da un’esecuzione in cui nient’altro toccava il fixture. Il comportamento in sé è meccanicamente chiaro e supportato da due segnali indipendenti; i valori specifici delle righe sono il risultato di un run pulito, non la media di molti.
Le sitemap sono un passaggio separato. La gentilezza verso i server è attiva — un crawl normale ha recuperato /robots.txt — ma la sitemap richiede un comando dedicato:
| Approccio | /sitemap.xml richiesto? | Endpoint esistenti solo nella sitemap |
|---|---|---|
| Un crawl normale | mai richiesto | 0/2 |
bin/nutch sitemap, eseguito esplicitamente sul crawldb | recuperato | 2/2 voci iniettate, recall completo |
modalità inline -kf di katana per known files, stesso fixture, su host IP | non registrato | 0/2 |
È un modello diverso rispetto ai crawler che caricano i file noti in linea, e ti costa un comando in più, ma il lavoro viene fatto fino in fondo.
Due comportamenti più piccoli hanno retto bene.
Gestione degli errori: un crawl su una pagina che linkava un 500 e un 404 ha completato tutti i round senza problemi, ha comunque recuperato tutte e quattro le pagine della classe A e ha registrato ogni errore in modo distinto:
| Risposta fallita linkata dalla pagina | stato registrato nel crawldb |
|---|---|
| 500 | db_unfetched (idoneo al retry) |
| 404 | db_gone |
Niente si è inceppato.
Politeness: con un thread per coda, l’intervallo tra i fetch sullo stesso host ha seguito l’impostazione:
fetcher.server.delay | Gap mediano tra fetch sullo stesso host |
|---|---|
| 1.0 secondo | 1.009 s (minimo 1.006 s) |
| 0.0 | 0.002 s |
La manopola fa esattamente ciò che promette. Il default fornito è 5.0 secondi, che è conservativo e, di nuovo, probabilmente corretto per uno strumento progettato per fare crawling su server altrui.
Il costo del batch, in secondi
Ogni comando Nutch avvia una nuova JVM. Questo singolo fatto domina più di qualsiasi altra cosa il profilo temporale, persino più del fetch.
| Fase (per round) | Secondi medi |
|---|---|
inject (una volta) | 1.81 |
generate | 3.93 |
fetch | 2.82 |
parse | 1.78 |
updatedb | 1.81 |
| Un round completo | 12.14 |
Il minimo effettivo per job — avvio JVM più inizializzazione Hadoop, misurato come fase più economica con lavoro banale — è di circa 1.77 secondi. Moltiplicalo per quattro comandi per round, aggiungi l’inject iniziale e il quadro del crawl completo diventa questo:
| Strumento | Crawl depth-4 del fixture da 12 pagine | Processi |
|---|---|---|
| Nutch | circa 45 secondi (ho misurato 45.8 s e 45.0 s in due configurazioni) | circa 17 avvii JVM, quasi nessuno dei quali effettua lavoro di rete |
katana modalità standard, stesso fixture | circa 13 secondi | un processo |
Il divario non riguarda la velocità di fetch; entrambi gli strumenti richiedono più o meno le stesse poche pagine. È un fatto architetturale. Nutch paga un costo fisso di processo per ogni fase perché quelle fasi sono progettate come job MapReduce. Su un crawl locale piccolo, il setup domina. Il costo fisso dovrebbe pesare meno in un job più lungo, ma questo test non ha misurato la scala alla quale Nutch e katana si incrociano, né se il loro rapporto si inverta.
Pro e contro
Pro
- Scoperta statica deterministica: classe HTML 4/4, catena di profondità 3/3, identica in tre esecuzioni ripetute.
parse-jsrecupera endpoint literal nei file JavaScript (2/2) senza browser, intercettando sia la forma con argomento di chiamata sia quella con assegnazione.- Due controlli di scope verificati che contengono completamente un crawl (
db.ignore.external.linkse host rule inregex-urlfilter). - L’ingestione delle sitemap tramite
bin/nutch sitemapha raggiunto un recall completo 2/2 sugli endpoint che un crawl normale perdeva del tutto. - Robusto in presenza di errori: 500 e 404 gestiti con stati distinti nel crawldb, crawl che continua.
- In questa esecuzione locale, l’intervallo osservato sullo stesso host è stato coerente con il delay configurato di 1.0 secondo; il default fornito è 5.0 secondi.
- Apache-2.0, mantenuto attivamente, 78 plugin e un crawldb persistente che traccia lo stato per URL tra i round.
- Funziona in modalità locale senza cluster, senza HDFS e senza richiedere Solr.
Contro
- Non gira su JDK 24 o successivi, dove la rimozione dello SecurityManager si fa sentire (ho misurato il fallimento su 26.0.1) — il Hadoop 3.4.2 incluso precede la correzione upstream e il flag di escape non esiste più, quindi il pin a un JDK LTS è un prerequisito rigido, non una preferenza.
- ≈396 MB unpacked, 188 jar di libreria, 78 directory plugin, 35 file di configurazione.
- Una JVM nuova per comando significa circa ~1.77 s di overhead fisso per fase; ~45 s per un crawl depth-4 di 12 pagine contro ~13 s per un crawler monobinary su terreno identico.
- Il default fornito segue i link verso host esterni; restare su un solo sito è una scelta opt-in.
http.agent.nameè vuoto di default e il fetcher rifiuta di partire finché non lo imposti.- Nessun flag per la profondità — la depth è un conteggio di loop che devi gestire tu.
- Gli endpoint nel DOM a runtime non sono stati raggiunti in nessuna configurazione testata, e sostituire il protocollo con uno che esegue JavaScript non è stato un cambio plug-and-play.
- Ho testato la modalità locale su un singolo host con un fixture piccolo. La modalità distribuita/HDFS, l’indicizzazione Solr, hostdb, resume e la pianificazione del recrawl incrementale erano fuori da questa prova — considerali non testati qui, non approvati.
Chi dovrebbe usarlo e chi dovrebbe lasciar perdere
Nutch dà il meglio quando il crawl in sé è la parte difficile. Se stai costruendo un indice di ricerca, eseguendo un crawl ampio su più domini, hai bisogno di un database persistente di URL con stato per URL e semantica di retry, o prevedi di distribuire il lavoro su più macchine, questa è un’infrastruttura che svolge quel lavoro specifico da prima che esistessero la maggior parte delle alternative. Il sistema di plugin ti permette di modificare il comportamento di protocollo, parser, filtro e scoring senza fare fork di nulla. I default di politeness sono conservativi in un modo che fa pensare che i maintainer abbiano riflettuto seriamente sul comportamento corretto verso server altrui.
Lascia perdere se vuoi dati strutturati da poche pagine. Nutch le recupererà e le analizzerà, poi ti consegnerà un crawldb e dei segmenti e si aspetterà che tu porti un indicizzatore. Lascia perdere se i tuoi target sono single-page app renderizzate lato client — la classe C è rimasta irraggiungibile in tutto ciò che ho eseguito. Lascia perdere se il tuo team non usa una JVM, perché aggiungeresti una toolchain Java, un pin a un JDK LTS e 396 MB di jar a uno stack che al momento non ne ha nessuno. E se il carico è “crawla un sito, quattro livelli in profondità, una volta a settimana”, passerai più tempo sul loop dei round e sui file di configurazione di quanto il crawl meriti.
Per la maggior parte delle persone che stanno cercando uno scraper, quest’ultimo è il caso reale. E non è una critica a Nutch — è un disallineamento tra lo strumento e la commissione. Se vuoi farti un’idea del panorama più ampio, il nostro rassegna degli scraper open source e i migliori progetti di web scraping su GitHub coprono in maggiore dettaglio la fascia più leggera.
Alternative, incluso dove si colloca il nostro stack
Prima la cornice corretta: Nutch è gratuito, con licenza Apache, self-hosted e tuo da eseguire per sempre senza costi per richiesta. È un vantaggio reale, e nulla di quanto segue lo cancella.
Recensione correlata: recensione di Browsertrix Crawler.
Nel mondo open source, il confronto dipende da cosa stai ottimizzando. Se vuoi un framework Python con controllo del crawl e una filosofia request-first, Scrapy è un’analogia più vicina per molti progetti; questo articolo non ne ha misurato il peso di installazione con lo stesso criterio. Se vuoi un crawler Go compatto senza browser, Colly è un’altra forma da valutare. Se il tuo problema è trasformare pagine in contenuti pronti per LLM anziché scoprire URL, Crawl4AI mira a un livello diverso.
Un servizio gestito come Thunderbit sposta fetch, rendering ed estrazione dietro un’API, mentre Nutch mantiene sotto il tuo controllo lo stato del crawl e l’infrastruttura. Thunderbit non è stato eseguito su questo fixture, quindi si tratta di un confronto sul modello di proprietà e non di un’affermazione su recall equivalente o performance sulle pagine dinamiche.
Il compromesso è tra controllo e overhead, e non è sottile. Nutch ti dà controllo totale, un crawldb persistente, scalabilità cluster by design e costo marginale zero — in cambio di una JVM, un pin a un JDK LTS, 396 MB di jar, un loop a round e un layer di indicizzazione tuo. Un’API gestita ti dà output strutturato alla prima chiamata e nessuna infrastruttura — in cambio di pricing per chiamata e meno controllo sulla frontiera del crawl. Se il tuo lavoro è “indicizzare 50 milioni di pagine”, il modello di Nutch è corretto e un’API sarebbe assurda. Se il tuo lavoro è “ottenere record strutturati da 200 pagine prodotto entro giovedì”, vale il contrario.
Prova Thunderbit per l’estrazione di dati web
Verdetto
Apache Nutch vale la pena di essere valutato se stai eseguendo un crawl continuo e multi-dominio e hai già un’infrastruttura JVM operativa. Su questo fixture la scoperta statica è stata deterministica tra le ripetizioni, parse-js ha trovato entrambi gli endpoint JavaScript letterali, i fallimenti sono rimasti rappresentati nel crawldb e la spaziatura delle richieste osservata ha rispettato il delay configurato.
Valuta con onestà il costo di ingresso. Nutch 1.22 qui ha fallito su JDK 26.0.1; OpenJDK 17.0.20 è la configurazione LTS effettivamente verificata in questa recensione, mentre Java 21 non è stato testato. Poi imposta http.agent.name, definisci esplicitamente lo scope e tieni conto del pavimento fisso osservato di circa ~1.77 secondi per fase in questo piccolo run locale. Se questo scambio abbia senso dipende da durata, ampiezza e necessità di stato persistente del crawl.
Prova Thunderbit per l’estrazione di dati web Get Started Free
FAQ
Perché Apache Nutch va in errore con "getSubject is not supported"?
Su JDK 24 o successivi, JEP 486 ha reso Subject.getSubject() un’eccezione obbligatoria, mentre il Hadoop 3.4.2 incluso continuava a chiamarlo. Il primo job Hadoop quindi si blocca prima che venga recuperata qualsiasi pagina, e il vecchio escape hatch -Djava.security.manager=allow non avvia più la VM. Usa la configurazione verificata con Java 17 e imposta NUTCH_JAVA_HOME; Java 21 potrebbe essere supportato, ma questa recensione non ha eseguito il ciclo completo su quella versione.
Su quale versione di Java dovrei eseguire Nutch 1.22?
Java 17 è la risposta più sicura — la CI di Nutch punta a quella versione, e nei miei test ha funzionato perfettamente su OpenJDK 17.0.20. Java 11 resta anch’esso supportato per la 1.22, anche se il progetto ha annunciato che la 1.23 richiederà Java 17. Qualsiasi versione da JDK 24 in su non funzionerà. Un’installazione Homebrew keg-only (brew install openjdk@17) con NUTCH_JAVA_HOME lascia intatto il JDK predefinito di sistema.
Nutch può fare crawling di siti molto ricchi di JavaScript?
In parte, e la distinzione conta. Con il plugin parse-js attivato, Nutch ha trovato entrambi gli endpoint esistenti solo come stringhe letterali all’interno di un file JavaScript linkato — 2/2, senza usare un browser. Con il set di plugin predefinito non ne ha trovato nessuno. Ma un endpoint che appare solo dopo l’esecuzione di JavaScript e la modifica del DOM è rimasto irraggiungibile in ogni configurazione statica che ho testato, e sostituire il protocollo con HtmlUnit non è stato un cambio plug-and-play nella mia esecuzione. Per le app renderizzate lato client, serve un protocollo che esegua JavaScript più una vera attività di configurazione, oppure uno strumento diverso.
Nutch ha bisogno di Hadoop e Solr installati?
No. La modalità locale usa il LocalJobRunner in-process di Hadoop — niente cluster, niente demone HDFS, niente YARN — e l’intero ciclo inject → generate → fetch → parse → updatedb funziona su una sola macchina senza altro installato. Solr è la destinazione tipica per l’indicizzazione, ma il crawl in sé non lo richiede. Detto questo, i jar di Hadoop sono inclusi (13, versione 3.4.2), ed è esattamente per questo che esiste il problema di compatibilità con il JDK.
Come faccio a impedire a Nutch di crawlare altri siti?
Impostalo esplicitamente, perché il default fornito non lo fa. Nutch 1.22 distribuisce db.ignore.external.links=false con un filtro URL permissivo, e nel mio test il crawl di default ha seguito un link verso un host diverso e lo ha recuperato. Puoi impostare db.ignore.external.links=true in nutch-site.xml, oppure aggiungere una regola host in conf/regex-urlfilter.txt (ad esempio +^https://example\.com/ seguito da -.). Entrambe le soluzioni hanno contenuto completamente il crawl nei test, verificato sia dal crawldb di Nutch sia dal log delle richieste dell’altro server.


