Vuoi trasformare la raccolta di dati dal web in un processo stabile, scalabile e “ban‑proof”? Con scraping web n8n paginazione puoi costruire workflow resilienti che navigano tra pagine, gestiscono contenuti caricati via JavaScript e riducono i rischi di blocco. In questa guida pratica impari a scegliere quando basta l’HTTP Request e quando serve il rendering lato client per scraping, come implementare la paginazione in n8n con loop su page/offset/cursor, come mantenere uno stato persistente, deduplicare i record estratti e ridurre ban grazie a rate limiting, caching (ETag/Last‑Modified) e rotazione IP. Vedrai snippet pronti all’uso, configurazioni chiave e un framework per qualità dati (selettori, normalizzazione, tracciabilità), oltre alle considerazioni legali/etiche che spesso vengono ignorate. Obiettivo: passare da script fragili a pipeline solide, schedulate con Cron in n8n e monitorate con alert mirati.
[IMG: Canvas n8n con Cron → HTTP Request → Code (extract + nextPage) → IF (hasNext) → HTTP Request (next) → … → DB + Slack alert]
Scegliere lo strumento giusto: HTTP Request, servizi headless o API di terze parti
Non tutti i siti sono uguali e non tutte le strategie di scraping lo sono. La prima decisione è tecnica e strategica.
-
Quando basta HTTP Request
-
La pagina restituisce HTML “statico” o espone un endpoint JSON (spesso usato dal frontend).
-
Paginazione prevedibile tramite query param (page, offset, cursor).
-
Nessuna protezione anti‑bot aggressiva.
-
Quando serve rendering lato client per scraping
-
Contenuti caricati via JavaScript (lazy loading, infinite scroll) senza API pubbliche facili da replicare.
-
Elementi critici generati dopo esecuzione JS (prezzi, disponibilità).
-
In questi casi valuta un servizio headless (browser automatizzato) o un’API di scraping specializzata. Integra in n8n tramite HTTP Request verso il servizio, mantenendo in n8n la logica di orchestrazione, paginazione e salvataggio.
-
Criteri di scelta tra approcci
-
Manutenzione: meno dipendenze esterne = meno costi, ma più fragilità su siti dinamici.
-
Volume e robustezza: siti con protezioni anti‑bot (Cloudflare, fingerprint TLS) richiedono rotazione proxy e IP residenziali, o soluzioni “browser‑like”.
-
Compliance: controlla sempre i termini del sito e le policy robot.txt.
Consiglio operativo: parti con HTTP Request e prova a individuare gli endpoint JSON interni. Se non basta, passa a un servizio di rendering; tieni separata l’estrazione (servizio) dall’orchestrazione (n8n), così il passaggio scala meglio.
Paginazione in n8n: loop su page/offset/cursor con scheduling e rate limiting
La paginazione è il cuore di ogni pipeline di scraping affidabile.
-
Modello con page/offset
-
Costruisci l’URL con query dinamiche (page=1, 2, 3…) o offset (0, 50, 100…).
-
Esegui la richiesta, estrai i risultati, verifica se ci sono più pagine.
-
Modello con cursor/nextPage
-
Alcune API restituiscono un cursore o un link next. Gestiscilo in un nodo Code e decidi se proseguire.
-
Scheduling con Cron in n8n
-
Usa un trigger temporizzato (esecuzione ogni 15 minuti/ogni notte) per avviare il job.
-
Esegui solo delta (ultime novità) se l’origine lo consente.
-
Rate limiting per richieste HTTP
-
Inserisci attese brevi tra batch (1–3 s).
-
Usa “Split In Batches” quando processi molte URL per stabilizzare il throughput.
Esempio (estrazione JSON e controllo nextPage, Code node — Run Once For All Items):
// Input atteso dal nodo precedente: response JSON dell'HTTP Request
const res = $input.first().json;
const items = (res.items || []).map((it) => ({
json: {
id: it.id,
title: it.title?.trim() || '',
url: it.url || '',
price: Number(it.price ?? 0),
source: res.source || 'unknown',
fetchedAt: new Date().toISOString(),
}
}));
const hasNext = Boolean(res.nextPage || res.nextCursor);
return [
{ json: { hasNext, next: res.nextPage || res.nextCursor || null } },
...items
];
[IMG: HTTP Request configurato con query page={{$json.page}} e nodo Code che calcola hasNext/next]
Stato persistente, cursori e deduplica: evitare doppioni e “ricominciare da dove hai lasciato”
Quando la raccolta è ricorrente, la gestione dello stato è cruciale.
-
Gestione dello stato nello scraping
-
Conserva l’ultimo cursore o la pagina elaborata in uno storage persistente (DB) o nello stato del workflow.
-
Mantieni l’ultima “data di aggiornamento” per estrarre solo le novità.
-
Stato persistente con getWorkflowStaticData(‘global’)
-
Usa uno storage globale del workflow per salvare cursori/ultima pagina. Esempio (Code node — Run Once For All Items):
// Salvataggio/lettura cursore globale
const state = getWorkflowStaticData('global');
const lastCursor = state.lastCursor || null;
const input = $input.first().json;
if (input.newCursor) {
state.lastCursor = input.newCursor;
}
return [{ json: { lastCursor: state.lastCursor || null } }];
- Deduplica dei record estratti
- Definisci una chiave unica (id, slug, url canonical). Prima di salvare, scarta duplicati visti nell’esecuzione corrente e in DB.
// All-items: dedup in memoria per url
const rows = $input.all().map(i => i.json);
const seen = new Set();
const out = [];
for (const r of rows) {
const key = (r.url || '').trim().toLowerCase();
if (!key || seen.has(key)) continue;
seen.add(key);
out.push(r);
}
return out.map(j => ({ json: j }));
- Tracciabilità
- Aggiungi “source”, “fetchedAt” e, se utile, un “hashContent” per rilevare cambiamenti nel tempo.
Contenuti caricati via JavaScript: strategie operative e infinite scroll
Molti siti popolari caricano i dati lato client: servono tattiche diverse.
-
Individua l’endpoint JSON
-
Apri la rete (DevTools) e cerca richieste XHR/fetch che restituiscono i dati. Spesso basta replicarle in HTTP Request in n8n con gli header corretti (cookie/sessione, user‑agent).
-
Infinite scroll
-
La pagina richiama un endpoint con “cursor/after/offset”. Riproduci lo schema: HTTP Request → Code (next) → IF (hasNext) → loop.
-
Rendering lato client per scraping
-
Se i dati non sono esposti, usa un servizio headless con rotazione proxy e fingerprinting del browser. Integra via HTTP Request e mantieni in n8n paginazione, dedup e salvataggio.
-
Lazy loading di immagini/dettagli
-
Spesso ci sono endpoint di dettaglio per ogni item. Accodali a un “Split In Batches” → HTTP Request (dettaglio) → arricchisci i record con i campi mancanti.
[IMG: Diagramma a due fasi: Catalogo (JSON/HTML) → Lista URL → Dettaglio (JSON/HTML) → Merge + Salva]
Antibot e resilienza: Cloudflare, rotazione IP, fingerprint e limiti
-
Protezioni anti‑bot come Cloudflare
-
Evita burst: imposta rate limiting per richieste HTTP con attese tra batch.
-
Usa proxy pool e IP residenziali; alterna user‑agent plausibili e mantieni header coerenti (Accept‑Language, Accept, sec‑ch‑ua).
-
Riduci parallelismo: serializza le chiamate più sensibili.
-
Fingerprinting del browser
-
Alcune difese controllano TLS fingerprint e comportamenti JS. Se fallisci, passa a servizi “browser‑like”.
-
Retry con backoff esponenziale
-
Sui 429/5xx, attiva retry progressivo (2s → 5s → 10s). Interrompi dopo N tentativi e invia alert.
-
Osservabilità
-
Logga gli status code, la latenza media e il tasso di errore per dominio. Monitora i ban nel tempo per calibrare batch e attese.
Parsing sicuro e robusto: selettori, normalizzazione e validazione
-
Selettori CSS/XPath con estrattori
-
Per HTML semplice, identifica pattern stabili (class, id); evita selettori fragili.
-
Se ottieni JSON, preferiscilo: parsing più stabile e veloce.
-
Normalizzazione schema
-
Definisci uno schema di output con tipi coerenti (string/number/date) e campi opzionali.
-
Valida i campi chiave (url, price, title) e imposta default sicuri.
-
Qualità dati e tracciabilità
-
Aggiungi sourceUrl, timestamp, e un checksum del record. Questo aiuta ad auditare e a identificare update reali vs rumore.
Esempio (Code — per‑item: normalizza e mappa)
const j = $json;
return {
json: {
id: j.id || j.slug || null,
title: String(j.title || '').trim(),
url: String(j.url || '').trim(),
price: Number(j.price ?? 0),
currency: j.currency || 'USD',
fetchedAt: new Date().toISOString(),
source: j.source || 'unknown'
}
};
Cache e conditional requests: ETag, Last‑Modified e riduzione dei costi/ban
Riduci richieste inutili e rispetta i limiti.
-
ETag e Last‑Modified
-
Salva ETag/Last‑Modified dal response precedente.
-
Nelle richieste successive, invia If‑None‑Match / If‑Modified‑Since. Se ricevi 304 Not Modified, salta parsing e passa oltre.
-
Come farlo in n8n
-
HTTP Request: aggiungi header dinamici con espressioni (If‑None‑Match: ={{$json.etag}}).
-
Gestisci la logica in un nodo IF: se statusCode==304, non aggiornare; altrimenti prosegui e aggiorna ETag/Last‑Modified persistenze.
-
Benefici
-
Meno banda, meno load sul sito target, minor probabilità di ban.
[IMG: HTTP Request con Headers If‑None‑Match/If‑Modified‑Since e IF che intercetta 304]
Salvataggio e indicizzazione: database, dedup e scheduling/alerting
-
Database di destinazione
-
MongoDB/Postgres: scegli in base a volumi e query. Mongo è flessibile per documenti JSON; Postgres+JSONB per query strutturate e join.
-
Imposta un indice univoco sulla chiave (id/url) per prevenire duplicati lato DB.
-
Deduplica dei record estratti
-
Dedup in memoria (per esecuzione) + indice univoco (persistenza). Logga conflitti e scarti per audit.
-
Scheduling con Cron in n8n
-
Pianifica finestre orarie “soft” (notte/weekend) per scraping massivo.
-
Aggiungi alert: invia un riepilogo Slack con conteggio record nuovi/aggiornati, errori e durata.
-
Pipeline a due fasi
-
Catalogo (lista) → Dettaglio (arricchimento) → Merge → Salva. Questa separazione migliora debug e controlli qualità.
Resilienza end‑to‑end: retry, limiti di concorrenza e aspetti legali/etici
-
Retry con backoff esponenziale
-
Implementa retry solo su errori temporanei. Limita i tentativi e aumenta l’attesa per ogni retry.
-
Limiti di concorrenza
-
Evita chiamate parallele elevate su domini sensibili. Meglio batch piccoli e costanti.
-
Osservabilità
-
Attiva un workflow con Error Trigger per log centralizzato. Traccia tassi di errore per dominio/source.
-
Aspetti legali/etici
-
Rispetta robots.txt, ToS e privacy. Non raccogliere dati personali senza base legale. Fornisci un meccanismo per eliminare dati se richiesto.
Esempio operativo: paginazione con page e arricchimento dettaglio
Scenario: elenco prodotti con endpoint JSON paginato (page=1..N) e endpoint dettaglio per ogni item.
1) Cron (ogni notte)
2) Code (imposta page iniziale, o leggi cursore persistente)
3) HTTP Request (GET lista?page={{$json.page}})
4) Code (estrai items, nextPage)
5) IF (hasNext) → incrementa page → loop al punto 3; altrimenti prosegui
6) Split In Batches (20)
7) HTTP Request (GET dettaglio per item.url)
8) Code (merge campi, normalizza schema)
9) DB (insert/upsert) con indice unico
10) Slack (report)
Snippet per incrementare page (Code — per‑item):
const j = $json;
const nextPage = Number(j.page || 1) + 1;
return { json: { page: nextPage } };
[IMG: Canvas con ramo Lista (loop page) e ramo Dettaglio (Split In Batches) fino al DB]
Quick Takeaways
- Inizia con HTTP Request e punta agli endpoint JSON; passa al rendering lato client solo quando necessario.
- Implementa la paginazione in n8n con loop su page/offset/cursor, controlli IF e attese tra batch.
- Mantieni stato e cursori (getWorkflowStaticData(‘global’) o DB) e applica dedup su chiave unica.
- Riduci ban con rate limiting, caching via ETag/Last‑Modified e rotazione IP su domini “sensibili”.
- Normalizza e valida i dati prima del salvataggio; traccia source e fetchedAt per audit.
- Schedula con Cron e invia alert/summary: osservabilità prima di tutto.
Conclusione
Portare scraping web n8n paginazione a livello “produzione” richiede una combinazione di scelte strategiche e tattiche: puntare prima agli endpoint JSON, orchestrare la paginazione con loop chiari e stato persistente, assicurare qualità e dedup, e proteggere il ciclo con rate limiting, caching e retry intelligenti. Con un disegno a due fasi (lista → dettaglio), salvataggio su DB con indice unico e un layer di observability (Slack report, Error Trigger), i tuoi workflow diventano affidabili e prevedibili. Per i marketer, significa dati freschi e puliti per campagne, pricing intelligence e analisi competitive, senza il peso di manutenzioni continue. Parti da un MVP con pochi endpoint, misura tempi/ban/errori, poi scala con batching e caching: il salto di qualità è nel processo, non solo nel parser.
FAQ
1) Come gestisco la paginazione in n8n senza rischiare loop infiniti?
Controlla sempre un segnale di uscita (no results/hasNext=false). Incrementa page/offset in un Code node, valida i limiti e usa IF per interrompere quando non ci sono più dati.
2) Come tratto contenuti caricati via JavaScript?
Cerca gli endpoint JSON usati dal frontend. Se non esistono o sono offuscati, integra un servizio di rendering lato client e usa n8n per orchestrazione, paginazione e salvataggio.
3) Come riduco i ban su siti protetti (Cloudflare)?
Diminuisci parallelismo, aggiungi attese tra batch, usa proxy/rotazione IP residenziali e header plausibili. Implementa retry con backoff sui 429/5xx e monitora i tassi di errore per dominio.
4) Posso usare caching con ETag/Last‑Modified in n8n?
Sì. Salva ETag/Last‑Modified e inviali come If‑None‑Match/If‑Modified‑Since negli header dell’HTTP Request. Gestisci i 304 per saltare parsing e ridurre richieste.
5) Qual è il modo migliore per evitare duplicati nel database?
Definisci una chiave unica (id/url canonical) e crea un indice unico nel DB. In n8n, aggiungi anche una dedup in memoria per esecuzione, loggando i record scartati.
Ci dai una mano?
Qual è il tuo prossimo target: stabilizzare la paginazione, ridurre i ban con caching/limiti o arricchire i dati con un passo “dettaglio”? Condividi la tua scelta e questo articolo con il team: confrontiamo pattern e trasformiamo gli scraper in pipeline affidabili!
Scopri la consulenza →

