Scrapy viene spesso bollato come uno strumento che “non sa stare dietro ai siti moderni” perché non esegue JavaScript. In realtà, è una lettura al contrario della sua filosofia. Il fatto di non renderizzare la pagina è proprio il cuore del progetto, e quando lo vedi all’opera smette subito di sembrare un difetto.
Me ne sono convinto con una sola prova. Ho creato un catalogo di test renderizzato in JavaScript, ho puntato Scrapy sulla pagina che avrebbe visto un browser e ho ottenuto 0 schede prodotto. Poi ho indirizzato lo stesso spider verso l’endpoint JSON che la pagina chiamava in silenzio in background e ho raccolto 8/8 elementi, senza sporcare nulla. Stesso strumento, stessa sessione, risultati opposti: il divario tra questi due numeri è il punto centrale di tutta questa recensione.
Cos'è davvero Scrapy (e cosa non è)

Scrapy è un framework Python per esplorare siti e fare web scraping di dati strutturati. È esattamente così che lo descrivono i maintainer nella documentazione introduttiva, e dopo averlo usato posso dire che è una definizione precisa — senza bisogno di marketing da copertina. È abbastanza maturo e consolidato da essere la risposta quasi automatica quando uno sviluppatore Python chiede con cosa lavorano i professionisti, e il repository lo conferma: circa 62.981 stelle GitHub al 2026-07-07 (scrapy/scrapy), con 11.773 fork e 590 issue aperte nello stesso giorno. Licenza BSD-3-Clause, Python 3.10 o superiore, e la versione che ho testato è stata la 2.17.0, uscita proprio la mattina in cui ho eseguito queste prove — quindi niente asterischi da versione vecchia.
Ecco la linea che lo separa dalla nuova generazione di crawler AI: per impostazione predefinita Scrapy lavora solo via HTTP. Niente browser. Niente motore di rendering. Scarica l'HTML via rete, lo passa a un parser e ti lascia estrarre i campi con selettori CSS o XPath. Chiamarlo limite è solo in parte corretto, ma rischia di far perdere di vista il progetto nel suo insieme. Il presupposto di Scrapy è che avviare un Chrome headless per una semplice estrazione sia spesso la scelta sbagliata: la strada più furba è trovare la richiesta dati che la pagina fa già e interrogarla direttamente.
Non è una mia interpretazione del tool: la documentazione ufficiale sui contenuti dinamici lo dice chiaramente. Prima si individua e si replica la richiesta dati sottostante, e solo come ripiego si ricorre a un browser headless quando riprodurre quella richiesta non è pratico. La maggior parte degli scraper apre prima il browser e non pensa mai all'API. Scrapy ribalta il comportamento di default.
Funzioni principali e le scelte progettuali dietro ognuna
Sotto il cofano, Scrapy è un insieme di componenti costruiti attorno a un’idea chiara: chi lo usa è uno sviluppatore che vuole controllo, non una procedura guidata a un clic.
Spider. Scrivi una classe, le passi gli URL iniziali e definisci una callback parse che restituisce elementi o segue altri link. È più verboso di un estrattore no-code — le regole di estrazione le scrivi tu — ma in cambio hai il controllo preciso su ciò che viene catturato e su dove continua la scansione.
Selettori. L’analisi si appoggia a parsel, che a sua volta usa lxml. CSS e XPath sono cittadini di prima classe, non aggiunte messe lì dopo. Il supporto di lxml è il motivo per cui la selezione resta veloce e per cui il codice di estrazione è leggibile, come un’intenzione chiara e non come un groviglio di slicing di stringhe.
Export dei feed. Punta uno spider a un file e Scrapy serializza i dati in JSON, JSON Lines, CSV o XML senza dover aggiungere collegamenti extra. Nel mio test, uno spider sul catalogo statico ha prodotto JSON e CSV senza che scrivessi una sola riga di codice per l’export: la parte sugli feed export è reale e fa davvero quello che promette.
AutoThrottle e controlli di crawling. Le richieste vengono pianificate in modo asincrono su Twisted, e hai a disposizione limiti di concorrenza, ritardi di download, restrizioni di profondità, AutoThrottle per il rate limiting adattivo e il rispetto di robots.txt. Sono i controlli che evitano che una scansione ampia si trasformi in un assalto al server.
Solo HTTP, riscritto come vantaggio. Niente browser significa meno memoria, più throughput e nessun motore di rendering da gestire — a patto che i dati siano raggiungibili via HTTP standard. E, più spesso di quanto pensi se vieni dal mondo browser-first, lo sono.
Setup: lo stack di dipendenze che nessuno mette negli screenshot

L’installazione è stata quasi banale, e per un framework di queste dimensioni vale la pena dirlo chiaro. pip install Scrapy==2.17.0 è andato a buon fine in un virtual environment nuovo su macOS arm64, scaricando wheel binarie e senza alcuna compilazione problematica. Nulla di drammatico da segnalare — ed è proprio questo il punto.
Guardando però cosa è stato installato, il quadro cambia. scrapy version -v ha mostrato Scrapy 2.17.0 appoggiato su lxml 6.1.1, Twisted 26.4.0, pyOpenSSL 26.3.0 e cryptography 49.0.0, con parsel, cssselect e tldextract a completare il quadro. È un’impronta importante: un intero framework di crawling, non un semplice parser HTML in un file. Su questa macchina esistevano wheel per tutto e l’installazione è rimasta semplice. Su altri ambienti, però, la documentazione ufficiale avverte ancora di attriti legati alla piattaforma, e storicamente è la parte dello stack collegata a cryptography e Twisted a creare più problemi. Quindi, se lavori su qualcosa di insolito, tienilo presente. Qui il setup è stato fluido; la quantità di ciò che viene installato resta comunque un dato importante prima di impegnarti, perché stai portando dentro un framework e pesa come un framework.
Prova pratica: cosa ha retto davvero

Una volta installato, il percorso statico è stato pulito. Recupero completo, nessun elemento perso.
| Test | Risultato | Tempo di esecuzione |
|---|---|---|
| Catalogo statico locale + paginazione | 12/12 prodotti | 0.557s |
| Export CSV del catalogo statico | 12 righe scritte | (stessa esecuzione) |
| Estrazione articolo | titolo + 3/3 paragrafi del corpo | 0.416s |
| Grafo di crawling, DEPTH_LIMIT=2 | 11 pagine tra i livelli 0/1/2 | 0.904s |
| Pagina locale 500 | stato 500 acquisito, nessun crash | 0.424s |
| Books to Scrape (pubblico) | 20 prodotti | 2.053s |
| Spider Quotes to Scrape (pubblico) | 12 elementi citazione | 3.465s |
Lo spider sul catalogo statico ha attraversato la paginazione dalla prima alla seconda pagina e ha catturato 12/12 record attesi, poi li ha esportati in JSON e CSV nello stesso passaggio. Il fixture dell’articolo è quello che merita più attenzione. Scrapy non ha provato a ripulire automaticamente la pagina trasformandola in un Markdown ordinato: invece mi ha lasciato definire con selettori espliciti i campi article, isolando nav e footer in campi separati, così ho ottenuto 3/3 paragrafi del corpo mentre il testo di contorno restava confinato e non mescolato ai risultati. Questo è il compromesso: scrivi tu i selettori e ottieni esattamente ciò che hai chiesto, senza extra indesiderati.
Il controllo del crawling ha funzionato bene anche su piccola scala. Con DEPTH_LIMIT=2, un ritardo di download breve, concorrenza per dominio e robots.txt attivo, il grafo ha visto 11 pagine nei livelli 0, 1 e 2, e il conteggio della profondità si è comportato correttamente. Anche la gestione dei fallimenti è stata altrettanto lineare. La pagina 500 intenzionale è tornata come elemento strutturato con status 500 esposto tramite handle_httpstatus_list — nessuna eccezione, nessuna esecuzione morta. Scrapy tratta uno stato di errore come qualcosa da gestire nella logica dello spider, non come una sorpresa che fa crollare il crawl.
Prova pratica: il muro di JavaScript e la porta accanto

Ed eccoci al risultato attorno a cui ruota questa recensione.
Ho puntato il fetcher HTTP di Scrapy su un catalogo renderizzato in JavaScript. Ha scaricato l’HTML sorgente, ha trovato 0 nodi .product-card e ha proseguito — perché non ha mai eseguito lo script che avrebbe creato quelle schede. Anche la pagina pubblica Quotes to Scrape JS ha raccontato la stessa storia: 0 nodi di citazione renderizzati. Se ti fermassi qui, liquideresti Scrapy come inadatto a qualsiasi cosa costruita in questo decennio.
Ma non bisogna fermarsi lì. Quel catalogo JS era popolato in background da un’API JSON, come succede nella maggior parte dei casi. Ho indirizzato lo stesso spider Scrapy verso quell’endpoint e ho ottenuto 8/8 prodotti in 0.416s — niente browser, niente rendering, solo una richiesta all’URL che la pagina stava già chiamando e il parsing del JSON restituito.
Il confronto diretto sintetizza alla perfezione la filosofia del “riprodurre la richiesta”. La pagina renderizzata è un diversivo: i dati erano dietro un’API per tutto il tempo, e il design di Scrapy ti spinge a raggiungerli direttamente invece di pagare un browser headless per guardare una pagina comporsi da sola. È più veloce, più leggero e si rompe meno: un contratto API è molto più stabile di un DOM costruito lato client. Il punto critico è che è un processo manuale. Devi aprire la scheda Network, trovare la richiesta e riprodurne header e parametri da solo. Scrapy non scopre l’API al posto tuo; rende però facilissimo colpirla una volta trovata.
Due limiti, detti chiaro e tondo. Quando non esiste davvero alcuna richiesta sottostante da riprodurre — per esempio dati costruiti solo lato client, senza nessuna API dietro — Scrapy ha bisogno di un’integrazione con browser headless che devi collegare tu, e in questa prova non ho testato quel percorso. Inoltre, tutto ciò che ho descritto sopra è stato eseguito su fixture di piccole dimensioni e pagine demo pubbliche. Non ho eseguito un crawl da 100 a 1.000 pagine, quindi non sto facendo alcuna affermazione su memoria, throughput o comportamento dei retry su scala: il core asincrono e i controlli di crawling sono segnali solidi, ma un segnale non è una misurazione.
Pro e contro
Pro:
- Il design HTTP-only è veloce e leggero: recupero 12/12 statico in circa mezzo secondo, 8/8 da un’API JSON in 0.416s, senza overhead del browser.
- L’approccio “riproduci la richiesta” funziona davvero: una pagina JS che restituiva 0 elementi ha poi fornito tutti e 8 i dati tramite la sua API.
- I selettori CSS e XPath basati su
lxmlmantengono il codice di estrazione leggibile e rapido. - Export in JSON/CSV/XML senza dover scrivere logica aggiuntiva per l’esportazione.
- Gestione esplicita degli errori: un 500 torna come stato intercettabile, non come crash.
- Controlli di crawling maturi: concorrenza, ritardi, limiti di profondità, AutoThrottle, robots.txt.
- Licenza BSD-3-Clause permissiva; installazione pulita su una macchina moderna.
Contro:
- Per design non renderizza JavaScript: su una pagina renderizzata lato client ottieni 0 nodi finché non trovi tu l’API.
- Individuare la richiesta sottostante è un lavoro manuale; Scrapy non ti indica l’endpoint.
- Stack di dipendenze piuttosto corposo (
Twisted,lxml,cryptography,pyOpenSSL,parsel,tldextract) — semplice qui, ma storicamente fonte di attriti su piattaforme insolite. - Più codice rispetto agli strumenti no-code o di auto-estrazione; gli spider li scrivi e li mantieni tu.
- I test hanno coperto fixture piccole e siti demo, non crawl di grandi dimensioni: l’affidabilità su scala non è stata verificata in questa prova.
A chi è adatto e chi può passare oltre

Scrapy è pensato per sviluppatori che vogliono controllo a livello di codice e ragionano in termini di richieste, non di pagine. Se davanti a un sito JavaScript lento il tuo primo pensiero è “da qualche parte qui sotto c’è un’API”, questo strumento è fatto esattamente per quell’istinto. Premia chi sa scrivere selettori, leggere la scheda Network e gestire end-to-end la propria logica di estrazione. Per siti statici, cataloghi paginati e qualunque cosa abbia un endpoint JSON individuabile, è veloce e preciso.
Puoi anche lasciarlo stare — o quantomeno affiancarlo ad altro — se scrivere e mantenere codice per spider non è il modo in cui vuoi investire il tuo tempo, oppure se i tuoi target renderizzano i dati solo lato client senza una richiesta riproducibile e non vuoi integrare da solo un browser headless. E se il sogno era puntare un URL a uno strumento e ottenere output strutturato pulito senza scrivere regole di estrazione, quello non è mai stato il compito di Scrapy, e non ha mai fatto finta del contrario.
Alternative e dove si inserisce Thunderbit
Prova Thunderbit per l'estrazione di dati web
Parti da ciò a cui ti stai davvero impegnando: un framework libero e open source che esegui e mantieni da solo. Ti fai carico degli spider, dello stack di dipendenze e del lavoro necessario per trovare la richiesta dati di ogni sito. In cambio non paghi nulla per richiesta, tieni tutto in casa e ottieni un controllo totale. Per molti team è la scelta giusta, e questa recensione non vuole convincere nessuno del contrario.
Il compromesso riguarda il problema del rendering e del drift, e la risposta di Scrapy è che lo risolvi tu: trovi l’API, replichi la richiesta e gestisci i casi senza API collegando un browser. Un’API di scraping AI gestita, invece, ti solleva da questo livello. È qui che si colloca lo stack per sviluppatori di Thunderbit per chi ha un profilo tecnico: un’API di scraping AI più un server MCP e una CLI, non l’estensione browser usata da chi lavora in sales e operations. POST /distill trasforma una pagina in Markdown pulito, pronto per LLM; POST /extract restituisce JSON strutturato in base a uno schema che definisci tu; entrambi gestiscono rendering JavaScript, anti-bot e contenuti dinamici lato server — incluso il caso in cui, per una pagina renderizzata dal client, Scrapy ti chiederebbe di passare a un browser. C’è anche un server MCP per agenti AI e assistenti di programmazione (con thunderbit_suggest_fields gratuito per definire il perimetro di una pagina prima di spendere qualcosa), oltre a una CLI tramite npx @thunderbit/thunderbit-cli per terminale, CI o job pianificati.
La differenza non è la qualità, ma la proprietà del processo. Scrapy è un framework ingegneristico esplicito: gestisci spider, pipeline e strategia JavaScript, e ottieni il massimo controllo senza costi per chiamata. Lo stack di Thunderbit ti toglie di mano il livello di render ed estrazione come servizio gestito, così eviti la caccia nella scheda Network e paghi per chiamata. Piccolo, code-first, e vuoi controllare ogni passaggio? Il controllo di Scrapy è più adatto. Devi scalare su cento siti e preferisci non ricostruire a mano una richiesta per ciascuno? Il percorso gestito elimina proprio quella categoria di lavoro.
Per il quadro più ampio, questi confronti coprono i vicini di categoria: la comparativa completa sugli scraper open source, la recensione di Colly come crawler Go senza browser e la recensione di Scrapling e dei suoi selettori adattivi.
Verdetto
Conviene usare Scrapy? Sì — se sei uno sviluppatore che vuole controllo e condividi la sua visione: non renderizzare la pagina, trova la richiesta dietro di essa. Nei test, questa filosofia ha funzionato esattamente come promesso. Un catalogo JavaScript ha consegnato 0 schede al fetcher HTTP; l’API JSON che lo alimentava ha invece restituito tutti gli 8 elementi allo stesso spider. L’estrazione statica ha raggiunto 12/12, i selettori dell’articolo hanno tenuto i 3/3 paragrafi puliti dal boilerplate, il grafo di crawling ha rispettato il limite di profondità su 11 pagine e un 500 è tornato come stato gestito invece che come crash.
Bisogna però tenere le cose nel giusto perimetro. Scrapy non renderizza JavaScript e non trova l’API al posto tuo: quel riflesso devi costruirtelo. Lo stack di dipendenze è quello di un vero framework e può creare problemi su piattaforme particolari, anche se qui è andato tutto liscio. E ho testato fixture e pagine demo, non un crawl di mille pagine, quindi considera la questione della scalabilità promettente ma non ancora dimostrata in questa prova. Dentro questi confini, Scrapy è lo strumento che abbraccia meglio un’idea piuttosto radicale: spesso il modo più rapido per attraversare una pagina web è non passare affatto dalla pagina stessa.
Prova Thunderbit per l'estrazione di dati web Get Started Free
FAQ
Scrapy può estrarre pagine renderizzate in JavaScript?
Non con il suo fetcher HTTP predefinito: nei test ha restituito 0 nodi sia su un fixture JS sia sulla pagina pubblica Quotes JS, perché scarica l’HTML senza avviare un browser. Il percorso previsto è trovare la richiesta dati sottostante e interrogarla direttamente; nel mio test, l’API JSON dietro un catalogo JS ha restituito tutti e 8 gli elementi. Per pagine senza una richiesta riproducibile, devi collegare tu un browser headless.
Cosa significa davvero “riprodurre la richiesta”?
La maggior parte delle pagine dinamiche carica i dati da un’API JSON in background e poi li renderizza lato client. Invece di aprire un browser per osservare quel processo, apri la scheda Network, trovi la chiamata API e indirizzi Scrapy direttamente lì. È più veloce e più stabile del rendering — un contratto API si rompe meno facilmente di un DOM — ma è un lavoro manuale e Scrapy non individua l’endpoint per te.
Scrapy è difficile da installare?
Nel mio caso no: pip install Scrapy==2.17.0 è terminato senza errori di compilazione in un venv nuovo su macOS, usando wheel binarie. Però porta con sé uno stack consistente (Twisted, lxml, cryptography, pyOpenSSL, parsel, tldextract) e la documentazione ufficiale avverte ancora di possibili attriti dipendenti dalla piattaforma su alcuni sistemi, quindi conviene metterlo in conto se usi un ambiente particolare.
Quali formati di output supporta Scrapy?
L’export dei feed include nativamente JSON, JSON Lines, CSV e XML: basta puntare uno spider a un file e i dati vengono serializzati senza codice aggiuntivo. Nel mio test, uno spider ha prodotto sia JSON sia CSV in un solo passaggio. Nota che esporta i campi che hai selezionato; non ripulisce automaticamente la pagina trasformandola in Markdown.
Scrapy è gratuito per uso commerciale?
Sì, è sotto licenza BSD-3-Clause, quindi permissiva e adatta anche all’uso commerciale. Come sempre, verifica la licenza aggiornata nel repository prima di costruirci sopra, e usa user-agent, proxy e rate limit in modo responsabile: poter fare qualcosa non significa avere il permesso di farlo.


