Skip to content

Il problema, inquadrato sul caso reale

Apri Playwright, chiami page.goto() sulla scheda prodotto di un e-commerce che vuoi monitorare per prezzo e disponibilità, e quello che torna non è il prodotto: è <title>Just a moment...</title>. È l’interstitial di Cloudflare. La pagina esegue JavaScript per cinque-quindici secondi, valuta una serie di segnali, e nel caso peggiore chiude con un 403. Il tuo scraper non ha mai visto lo SKU.

Questo articolo parte da lì e non si muove più da lì. L’esempio ricorrente è sempre lo stesso: monitorare prezzo e disponibilità di una scheda prodotto protetta da Cloudflare, fino al Turnstile, con un secondo bersaglio “enterprise duro” — un listing dietro DataDome — usato come contrasto. Lo stesso target affrontato con ogni libreria, mostrando dove ciascuna passa e dove cade.

La domanda che la maggior parte degli articoli “top 10 librerie scraping” sbaglia è quale problema stanno risolvendo. Cambiare libreria non è cambiare arma: è cambiare quale strato di detection stai attaccando. E gli strati sono sette, non uno. La tesi che regge tutto il pezzo è questa: scegliere la libreria giusta risolve due o tre strati su sette. IP, coerenza del fingerprint e comportamento non li decide la libreria. E la frontiera del 2026 — il fingerprint dell’hardware reale — sposta il problema da “mentire meglio” a “hardware reale in location reali”.

Premessa d’uso lecito, non opzionale. Tutto ciò che segue serve a testare la propria infrastruttura di scraping contro la detection e a interrogare target per cui si è autorizzati. Prima di puntare uno di questi strumenti su un sito di terzi: rispetta robots.txt, i Termini di Servizio e i rate limit del target; interroga solo proprietà tue, ambienti di test o siti per cui hai mandato o consenso; tratta gli eventuali dati personali secondo il GDPR (base giuridica, minimizzazione, retention); non aggirare autenticazione o paywall e non arrecare danno o sovraccarico. La detection non è il nemico: è la prospettiva opposta del lavoro che facciamo quando vogliamo, al contrario, gestire i crawler AI e i bot indesiderati sui nostri siti. Conoscere entrambi i lati è ciò che separa l’analisi tecnica dal trucchetto.

Come funziona DAVVERO la detection nel 2026 — il modello a 7 strati

Un sistema anti-bot moderno (Cloudflare Bot Management, DataDome, Akamai Bot Manager) non prende una decisione: ne prende sette, in cascata, e le fonde in uno score. La maggior parte falla prima che il tuo JavaScript venga eseguito. Vale la pena smontare la pipeline strato per strato, perché è l’unico modo per capire cosa una libreria può e — soprattutto — cosa non può fare per te.

Strato 1 — Reputazione IP (pre-JS)

Il primo filtro è la rete, prima di qualsiasi rendering. Il sistema valuta ASN e tipo di IP: datacenter (AWS, Hetzner, OVH) parte con trust degradato; residenziale, mobile e ISP partono meglio. Cloudflare documenta variabili di bot management calcolate dalla telemetria globale della sua rete e ha descritto pubblicamente un modello ML dedicato a riconoscere l’abuso di proxy residenziali (Cloudflare, Bot Management variables; Cloudflare blog, residential proxy detection).

Non è un cancello binario — i vendor lo mescolano in un punteggio per non bloccare il traffico cloud legittimo — ma è lo strato più impattante in assoluto e l’unico che nessuna libreria può toccare. È deciso dal tuo IP. Per questo, in tutti i miei test, la variabile proxy è quella che muove di più i verdetti, e va fissata prima di confrontare qualsiasi cosa.

Strato 2 — Fingerprint TLS: da JA3 a JA4

Quando il client apre la connessione TLS, il ClientHello (cipher suite, estensioni, curve, ALPN) produce un’impronta. JA3 (Salesforce, hash MD5, sensibile all’ordine) è stato di fatto neutralizzato dalla randomizzazione dell’ordine delle estensioni TLS introdotta da Chrome intorno alla versione 110, inizio 2023: un ClientHello con 16 estensioni genera fino a 16! hash JA3 diversi per lo stesso identico client. La risposta è JA4 (FoxIO, 2023), che ordina cipher ed estensioni prima di calcolare l’hash, rendendo la randomizzazione irrilevante. Cloudflare ha messo JA4 in produzione (FoxIO, JA4 spec; Cloudflare, JA4 Signals).

Il segnale chiave non è il fingerprint in sé, è l’incoerenza: uno User-Agent che dichiara Chrome con un fingerprint TLS che sa di urllib3 o python-requests è un bot ad alta confidenza, e lo si stabilisce a livello di rete, prima del JavaScript. JA3 non è morto — resta utile per client non-browser (malware, librerie) che non randomizzano — ma per i browser moderni JA4 lo supera.

Strato 3 — Fingerprint HTTP/2 (formato Akamai)

Anche il modo in cui parli HTTP/2 è un’impronta. Il frame SETTINGS, l’incremento WINDOW_UPDATE, i campi dei frame PRIORITY e l’ordine degli pseudo-header (:method :authority :scheme :path) compongono il cosiddetto “Akamai HTTP/2 fingerprint”, formalizzato nel whitepaper di Akamai a Black Hat EU 2017 (Shuster, Passive Fingerprinting of HTTP/2 Clients). La forma canonica è del tipo 1:65536;2:0;4:6291456;6:262144|15663105|0|m,a,s,p. Akamai lo usa nativamente; Cloudflare e DataDome lo combinano con il TLS. Anche qui: un’impronta HTTP/2 da libreria Python sotto uno User-Agent Chrome è una contraddizione che costa cara.

Strato 4 — Fingerprint del protocollo di automazione (CDP / Runtime.enable)

Questo è lo strato che separa i vincitori del 2026 dal resto, ed è anche il meno compreso. Puppeteer e Playwright pilotano Chrome via Chrome DevTools Protocol (CDP) e, per ottenere gli ID dei contesti di esecuzione, chiamano Runtime.enable. Una volta abilitato, ogni console.* fa costruire all’inspector V8 un preview interattivo degli oggetti, enumerandone le proprietà — un effetto collaterale osservabile dal JavaScript di pagina. Rebrowser, che ha reso pratico il fix, ha verificato che disabilitando Runtime.enable le richieste di challenge di Cloudflare Turnstile e DataDome sparivano: prova diretta che entrambi lo usano (Rebrowser, Runtime.enable CDP detection; rebrowser-patches; DataDome, CDP signal).

navigator.webdriver === true è il controllo di prima generazione, ormai banale; il vero spartiacque è chi evita del tutto l’auto-Runtime.enable. È esattamente la ragione per cui esistono patchright, rebrowser-patches e le librerie “no-CDP”: creano i contesti via Runtime.executionContextCreated senza accendere la spia.

Strato 5 — Browser fingerprinting (JS)

Qui entra in gioco il fingerprint classico lato JavaScript: canvas, WebGL (stringa vendor/renderer), AudioContext, enumerazione font, risoluzione schermo, entropia di navigator, combinati in un identificativo stabile. Gli ambienti headless e automatizzati producono spesso fingerprint incoerenti — GPU/renderer che non combaciano con la piattaforma dichiarata, font mancanti — ed è precisamente ciò che strumenti come CreepJS vanno a cercare (DataDome, CreepJS).

Il punto controintuitivo, e quello che distingue chi scrive scraper da anni: la detection moderna penalizza l’incoerenza e la randomizzazione rumorosa più del fingerprint grezzo. Un anti-detect tool che randomizza ogni chiamata è più facile da prendere di un profilo stabile e internamente coerente. La coerenza batte l’aggressività.

Strato 6 — Comportamentale e managed challenge

L’ultimo strato “classico” è il comportamento: naturalezza della traiettoria del mouse, cadenza e timing, scroll, entropia dell’interazione. DataDome modella esplicitamente i pattern di interazione e navigazione e segnala input lineari, a scatti o con precisione al millisecondo (DataDome, behavioral classification). Cloudflare Turnstile è l’alternativa al CAPTCHA che raccoglie in background segnali browser e comportamentali: ha tre modalità — managed (default, può mostrare una checkbox se sospetta), non-interactive (spinner, nessuna checkbox) e invisible (Cloudflare, Turnstile). Da notare: il segnale comportamentale è prevalentemente challenge-time, non si raccoglie su una richiesta nuda pre-JS.

Lo strato 7, la frontiera. Oltre i sei strati consolidati si profila un settimo, ancora in larga parte di ricerca: il fingerprint dell’hardware via WebAssembly e SIMD. WASM con timing ad alta risoluzione può sondare comportamenti micro-architetturali della CPU che le API JavaScript non lasciano falsificare facilmente. Esiste lavoro accademico che lo dimostra — “Browser Fingerprinting Using WebAssembly” riporta meno dell’1% di falsi positivi nel distinguere browser Chromium su CPU Intel/AMD/ARM e su VM, anche con User-Agent falsificato (arXiv 2506.00719, giugno 2025; CISPA, Browser-based CPU Fingerprinting). Attenzione però all’onestà intellettuale: non esiste prova primaria che Cloudflare, DataDome o Akamai lo abbiano in produzione su larga scala — è una tecnica dimostrata in laboratorio, non un fatto di produzione verificabile. Lo riprendo, opportunamente cauto, in conclusione: è dove la detection sta andando, non necessariamente dove è già.

Il modello di detection anti-bot a 7 strati nel 2026: reputazione IP, TLS JA3/JA4, HTTP/2, protocollo CDP, fingerprint JS, comportamentale, fingerprint hardware WASM/SIMD
Il modello di detection a 7 strati: la libreria copre 2–3 strati, gli altri li decidono IP, comportamento e hardware.

Tieni a mente la mappa: gli strati 1, 2, 3 e 6 (IP, TLS, HTTP/2, comportamento) dipendono dalla rete, dallo stack di trasporto e dalla tua logica di automazione. Gli strati 4 e 5 (protocollo di automazione e fingerprint JS) sono quelli su cui una libreria fa davvero la differenza. Ecco perché la libreria, da sola, vale due-tre strati su sette.

Tassonomia delle librerie per architettura

Prima di guardare i singoli nomi, conviene classificarli per architettura: è la tassonomia, non la “classifica”, a dirti cosa una libreria può coprire. Strumenti di categorie diverse attaccano strati diversi del modello qui sopra.

CategoriaCome operaStrati che attaccaEsempi
WebDriver-patchSelenium/WebDriver con patch anti-rilevamento4 (parziale), 5SeleniumBase UC Mode, undetected-chromedriver
CDP-directPilota Chrome via CDP, niente WebDriver4 (forte), 5 (parziale)nodriver, zendriver, DrissionPage
Playwright-forkFork di Playwright che patcha i leak CDP4 (forte), 5patchright
Stealth-pluginInietta patch JS su Playwright/Puppeteer5 (solo)playwright-stealth
Browser ricompilatoBrowser patchato a livello sorgente C++5 (forte), 4camoufox, CloakBrowser (commerciale)
Framework all-in-oneOrchestrazione + browser + HTTP + cachevaria (impacchetta gli altri)Botasaurus, Scrapling
Request-layerNiente browser, impersona TLS/HTTP/22, 3 (solo)curl_cffi

Due osservazioni che cambiano l’approccio. Primo: nessuna categoria copre lo strato 1 (IP) — quello è sempre il tuo proxy. Secondo: le categorie sono componibili, non alternative. Il request-layer copre TLS/HTTP/2 ma è cieco al JavaScript; il browser ricompilato copre il fingerprint JS ma porta con sé un fingerprint TLS Firefox; il CDP-direct chiude il protocollo di automazione ma non ti dà di per sé un IP pulito. La scelta giusta è quella che copre gli strati che il tuo target controlla davvero — e lo scopri solo misurando (sezione 5).

Matrice di copertura: quali strati di detection copre ciascuna categoria di libreria Python anti-detection (curl_cffi, playwright-stealth, nodriver, patchright, camoufox)
Quali strati copre ciascuna categoria di libreria: la combinazione giusta copre gli strati che il tuo target controlla.

Le librerie, una per una

Per ognuna: cosa fa, come si comporta contro l’esempio Cloudflare, snippet minimal max-safety, contro e limiti reali, licenza. Gli snippet sono volutamente minimi: la configurazione max-safety completa di proxy e fingerprint è materia della guida dedicata ai layer complementari (sezione 7). Tutte le firme sono verificate sulle fonti ufficiali (repo/PyPI) a giugno 2026.

nodriver (CDP-direct)

nodriver è il successore ufficiale di undetected-chromedriver, scritto dallo stesso autore: pilota Chrome direttamente via CDP, senza Selenium e senza il binario chromedriver. Eliminando il protocollo WebDriver elimina anche la spia navigator.webdriver — conseguenza architetturale, non flag impostato a mano. È forte proprio sullo strato 4 (protocollo di automazione), il più discriminante.

Sull’esempio Cloudflare: in modalità headful (o con display virtuale Xvfb su server) e con un IP residenziale pulito, supera il managed challenge sulla pagina di test Cloudflare e serve il contenuto reale. In headless puro i punteggi crollano: è documentato e l’ho riscontrato sistematicamente.

"""
nodriver — snippet minimal max-safety.
Successore di undetected-chromedriver: pilota Chrome via CDP custom, niente
WebDriver, niente flag navigator.webdriver. Forte sul fingerprinting di protocollo
di automazione; debole in headless puro (usare display virtuale).

  pip install nodriver
  # serve un Chrome/Chromium installato

Proxy: via create_context (HTTP/HTTPS e SOCKS). Per HTTP autenticato serve
il flusso CDP Fetch; per SOCKS5 autenticato la forma socks://user:pass@host:port.
Licenza: AGPL-3.0 (valutare implicazioni commerciali).
"""

import nodriver as uc


async def main():
    browser = await uc.start(
        headless=False,                 # su server: avvia con xvfb-run
        browser_args=[
            "--lang=it-IT",
            "--window-size=1920,1080",
        ],
        lang="it-IT",
    )
    page = await browser.get("https://nowsecure.nl/")
    await page.sleep(6)                 # lascia risolvere l'eventuale challenge
    html = await page.get_content()
    print("title:", await page.evaluate("document.title"))
    print("len:", len(html))
    browser.stop()


if __name__ == "__main__":
    # asyncio.run non e' affidabile con nodriver: usare il suo loop
    uc.loop().run_until_complete(main())

Contro reali. È async-only, il che obbliga a incapsularlo se il resto del codice è sincrono. La gestione proxy è funzionale ma ancora acerba su alcuni fronti: il proxy si imposta via create_context(proxy_server=...) e supporta HTTP/HTTPS e SOCKS, ma per un proxy HTTP autenticato Chrome non accetta credenziali da riga di comando — serve gestire Fetch.authRequired via il dominio CDP Fetch — mentre per SOCKS5 autenticato si usa la forma socks://utente:password@host:porta. (Da correggere una credenza diffusa, che avevo io stesso: nodriver non è “solo SOCKS5”.) Infine la licenza: AGPL-3.0, copyleft di rete — da valutare con attenzione in un servizio SaaS o hosted, dove può far scattare obblighi di disclosure del codice.

patchright (Playwright-fork)

patchright è un fork drop-in di Playwright che patcha i leak CDP: cambi solo l’import. La patch principale è proprio sullo strato 4 — evita l’Runtime.enable automatico eseguendo il JavaScript in ExecutionContext isolati. Effetto collaterale dichiarato: disabilita la Console API, quindi console.log & co. non funzionano dentro patchright. Solo Chromium, niente Firefox o WebKit (repo patchright-python; limitazioni nel repo patchright).

Sull’esempio Cloudflare: con la configurazione “completamente undetected” da docs ufficiali — launch_persistent_context (non launch + new_context), channel="chrome" (Chrome di sistema, non il Chromium bundled), headless=False, no_viewport=True — passa il managed challenge in modo molto solido. Regola sottile dei docs: non impostare user_agent o header del browser custom, perché reintroducono incoerenze.

"""
patchright — snippet minimal max-safety.
Fork drop-in di Playwright che patcha i leak CDP (Runtime.enable eseguito in
ExecutionContext isolati). Cambi solo l'import rispetto a Playwright.

  pip install patchright
  patchright install chromium      # oppure usa channel="chrome" (Chrome di sistema)

Config "completamente undetected" da docs ufficiali:
  - launch_persistent_context (NON launch + new_context)
  - channel="chrome", headless=False, no_viewport=True
NOTA: patchright disabilita la Console API (console JS non funziona).
Solo Chromium: niente Firefox/WebKit.
"""

import tempfile

from patchright.sync_api import sync_playwright

with sync_playwright() as p:
    ctx = p.chromium.launch_persistent_context(
        user_data_dir=tempfile.mkdtemp(prefix="patchright-"),
        channel="chrome",               # Chrome reale > Chromium bundled
        headless=False,                 # su server: xvfb-run
        no_viewport=True,
        locale="it-IT",
        # proxy={"server": "http://host:port", "username": "...", "password": "..."},
    )
    page = ctx.new_page()
    resp = page.goto("https://nowsecure.nl/", wait_until="domcontentloaded", timeout=45000)
    page.wait_for_timeout(6000)
    print("status:", resp.status if resp else None)
    print("title:", page.title())
    print("len:", len(page.content()))
    ctx.close()

Contro reali. La Console API disabilitata è un fastidio concreto in debug. E, parola del repo stesso, restano vettori residui: gli InitScript sono in teoria rilevabili con timing attack (nessun anti-bot oggi lo controlla, ma è documentato), ci sono bug noti sul Route di Playwright, e “passa la maggior parte, non tutti” i test Playwright. Quindi: chiude i leak CDP grossi, ma non è magia — eredita la natura di Playwright e qualche artefatto. Licenza Apache-2.0 (permissiva, ottima per uso commerciale), versione che segue Playwright 1.60.x a giugno 2026.

camoufox (Firefox C++)

camoufox è un Firefox ricompilato con patch anti-fingerprint a livello C++: i dati vengono intercettati nell’implementazione nativa, quindi le modifiche non sono osservabili tramite ispezione JavaScript. Usa l’API di Playwright (camoufox.sync_api). È forte sullo strato 5 (fingerprint JS) in modo strutturale, perché non “mente” da JavaScript: cambia il browser sotto (repo camoufox; docs).

Sull’esempio Cloudflare: con humanize=True, os coerente, block_webrtc=True e geoip=True quando c’è un proxy (allinea timezone, locale e WebRTC all’IP), nei miei test è il più robusto sullo strato fingerprint puro. Ma è anche dove va smontata una leggenda.

"""
camoufox — snippet minimal max-safety.
Firefox ricompilato con patch anti-fingerprint a livello C++: il fingerprint JS
e' modificato nell'implementazione nativa, non osservabile da JavaScript. Usa
l'API Playwright. NB: i docs avvertono che fingerprinting complesso puo' ancora
rilevarlo — la coerenza conta piu' dell'aggressivita'.

  pip install -U "camoufox[geoip]"
  camoufox fetch                   # scarica il binario Firefox modificato (una volta)

Coerenza > aggressivita': geoip allinea timezone/locale/WebRTC al proxy.
Engine = Firefox: valutare i quirk TLS/JA per i propri target.
"""

from camoufox.sync_api import Camoufox

with Camoufox(
    headless="virtual",                 # Xvfb su Linux; "False" headful altrove
    humanize=True,                      # traiettorie cursore realistiche
    os="windows",                       # fingerprint OS coerente
    locale="it-IT",
    block_webrtc=True,                  # evita leak dell'IP reale
    # geoip=True,                       # attiva con un proxy: allinea timezone/locale
    # proxy={"server": "http://host:port", "username": "...", "password": "..."},
) as browser:
    page = browser.new_page()
    resp = page.goto("https://nowsecure.nl/", wait_until="domcontentloaded", timeout=45000)
    page.wait_for_timeout(6000)
    print("status:", resp.status if resp else None)
    print("title:", page.title())
    print("len:", len(page.content()))

Contro reali. Primo, la verità sul claim “0% detection / unico open-source”: non è nelle fonti ufficiali, anzi i docs avvertono esplicitamente che camoufox può ancora essere rilevato da metodi di fingerprinting complessi e mettono in guardia sulle incoerenze. Diffida di chi lo vende come invincibile. Secondo, l’engine è Firefox: la mia analisi — non una posizione dei docs camoufox, che anzi sostengono l’opposto (Juggler opera a un livello più basso del CDP, meno soggetto a leak JS) — è che Firefox ha quota di mercato reale minore e un fingerprint TLS diverso da Chrome, quindi su alcuni target il mix può risultare anomalo: va verificato per bersaglio, non dato per scontato. Terzo, attenzione a versioni e licenza, che sono doppie: il wrapper Python camoufox su PyPI è alla 0.4.x (MIT, ultimo rilascio inizio 2025), il binario Firefox patchato viaggia per conto suo (v150.x a maggio 2026, sorgente MPL-2.0 ereditata da Firefox), e la linea attiva 2026 dei fingerprint bleeding-edge è distribuita via il fork cloverlabs-camoufox. Non esiste “una” versione né “una” SPDX: dichiaralo.

curl_cffi (request-layer)

curl_cffi non è un browser: è un binding Python di curl-impersonate che impersona il fingerprint TLS/JA3 e HTTP/2 di Chrome a livello di handshake. Copre gli strati 2 e 3 — e solo quelli — con pochissimo overhead. È la baseline fondamentale: se un target gate-a solo sul TLS, lo passi con una ventina di righe e zero browser (repo lexiforest/curl_cffi; il progetto ha cambiato organizzazione, da yifeikong a lexiforest).

Sull’esempio Cloudflare: utile come sonda diagnostica e per i target leggeri. Sulla scheda prodotto dietro managed challenge cade, e cade per costruzione: niente esecuzione JavaScript significa niente risoluzione dell’interstitial “Just a moment”, del Turnstile o del captcha DataDome. È esattamente questa la sua diagnostica: se curl_cffi passa, il gate era solo-TLS; se cade dove un browser passa, il gate è JS/comportamentale.

"""
curl_cffi — snippet minimal max-safety (request-layer, niente browser).
Impersona il fingerprint TLS/JA3 e HTTP/2 di Chrome a livello di handshake. Se il
target gate-a SOLO sul TLS, questo lo passa con pochissimo overhead. Niente
rendering JS: inutile su challenge interattive (Turnstile, DataDome captcha).

  pip install curl_cffi
"""

from curl_cffi import requests

# impersonate allinea JA3/JA4 + ordine degli header a un Chrome reale
r = requests.get(
    "https://tls.browserleaks.com/json",     # mostra il JA3/JA4 visto dal server
    impersonate="chrome",
    headers={"Accept-Language": "it-IT,it;q=0.9"},
    timeout=30,
    # proxies={"http": "http://user:pass@host:port",
    #          "https": "http://user:pass@host:port"},
)
print("status:", r.status_code)
print(r.text[:500])

# Per sessioni persistenti (cookie + stesso fingerprint su piu' richieste):
# s = requests.Session(impersonate="chrome")
# s.get("https://example.com/")

Contro reali. Nessun JavaScript, nessun DOM: inutile su tutto ciò che è interattivo. Ma per il monitoraggio di prezzo/disponibilità su endpoint o API leggere è imbattibile in efficienza, e si presta a sessioni persistenti (Session(impersonate="chrome")) che mantengono cookie e fingerprint coerenti su più richieste. Licenza MIT, versione 0.15.x a giugno 2026. Se vieni da Python e la libreria requests per estrarre dati dalle pagine, curl_cffi è il passo successivo naturale: stessa ergonomia, ma con un fingerprint che non ti tradisce all’handshake.

Menzioni rapide: quando hanno senso le altre

Non tutto merita una scheda completa, ma diverse librerie hanno una nicchia precisa. Una riga d’uso ciascuna, con licenza e stato a giugno 2026:

  • SeleniumBase UC/CDP Mode (MIT, attivissimo) — ha senso se hai già un’infrastruttura Selenium/pytest e vuoi stealth senza uscirne. Lo UC Mode è il layer storico; il maintainer ora spinge il CDP Mode (activate_cdp_mode()), più forte. Footprint pesante rispetto a una libreria CDP snella.
  • Botasaurus (MIT) — framework all-in-one con decoratori (@browser, @request, @task), cache e parallelizzazione: ha senso se vuoi che ti impalchi l’intero progetto scraper, UI inclusa. I claim “imbattibile / bypassa tutto” sono marketing, da trattare con scetticismo.
  • DrissionPage (BSD-3 con una clausola non standard — verifica legale) — ibrido CDP-direct + request-layer: ha senso quando devi mescolare fluidamente richieste HTTP leggere e controllo browser completo nella stessa sessione (autentichi nel browser, poi scrapi veloce via HTTP). Origine cinese, docs in cinese, cadenza più lenta (ultimo rilascio inizio 2025).
  • Scrapling (BSD-3, attivissimo) — parser “adattivo”: ritrova gli elementi anche dopo che il markup del sito è cambiato, caratteristica unica nel gruppo. I suoi fetcher coprono request-layer con impersonazione TLS, browser stealth e Playwright; ha senso per scraper che si rompono di continuo per restyling.
  • playwright-stealth (MIT, fork mantenuto da Mattwmaster58) — plugin stealth che patcha solo lo strato 5 (fingerprint JS) su Playwright. Lo stesso maintainer lo definisce un “proof-of-concept” che “supera tutto tranne la detection più semplice”. Ha senso come patch leggera se piloti già Playwright e il target è morbido — non per Cloudflare/DataDome.
  • zendriver (AGPL-3.0, attivo) — fork community di nodriver, nato perché nodriver limitava i contributi: stessa architettura CDP-direct, ma con i bugfix mergiati, CI e issue tracker aperti. Ha senso se vuoi l’approccio di nodriver con un progetto più reattivo. Stessa licenza copyleft.
  • CloakBrowser — qui un avviso, non una raccomandazione. È un prodotto commerciale closed-source: il Chromium patchato è un binario proprietario (le patch C++ non sono pubblicate), con un wrapper MIT come “foglia di fico”, versioni v148+ a pagamento e una costellazione di repo-cloni con descrizioni SEO-spam che puzzano di astroturfing. I conteggi di stelle e i “passa ogni test” sono marketing non verificabile. Lo cito per completezza e per metterti in guardia: non metterlo nello stesso paniere delle librerie open-source auditabili.

Benchmark: la mia metodologia riproducibile + i miei numeri

A questo punto la domanda giusta non è “qual è la libreria migliore”, ma “qual è la migliore contro il mio target, dal mio IP, oggi“. Per rispondere serve un benchmark riproducibile e datato, non una classifica copiata. Ho messo insieme un piccolo harness — eve-detection-bench — proprio per produrre dati primari sul mio ambiente.

Tassonomia dei verdetti. Quattro stati deterministici, con la regola che in caso di parità tra run vince il verdetto più pessimistico:

  • OK — contenuto reale servito, nessun marker di challenge. Se il target ha un expected_marker noto (lo SKU, il prezzo), deve comparire: difende dalle honeypot generative, perché Cloudflare nel 2026 può servire pagine fake con status 200.
  • SOFT — challenge intermedia: interstitial “Just a moment”, widget Turnstile, captcha DataDome/PerimeterX. Servito ma non superato.
  • BLOCK — blocco netto: 403/429/503, “Access denied”, “you have been blocked”, errore 1020.
  • ERROR — errore motore, rete o timeout.

Questa separazione tra soft-challenge e hard-block non è cosmetica: sono segnali diversi e vanno contati separatamente. È lo stesso impianto ok/gated/blocked usato dai benchmark indipendenti più seri (per esempio Paterson, Anti-detect browser benchmark 2026).

Il protocollo, per numeri pubblicabili. Sei regole, in ordine di impatto:

  1. Un solo IP residenziale pulito, fisso per tutta la sessione. È la singola variabile che muove di più i verdetti.
  2. N run per cella (3–5) per assorbire la variabilità di stato dei challenge.
  3. Stessa finestra temporale per tutti gli engine: la matrice è uno snapshot, un vendor può cambiare stato (o vendor) tra una sessione e l’altra.
  4. Display virtuale (xvfb-run) per gli engine browser su server Linux: l’headless puro penalizza i punteggi.
  5. Chrome di sistema dove possibile (channel="chrome"): la versione deve coincidere con quella che gli utenti hanno davvero installata.
  6. Data e versioni annotate: i risultati invecchiano in fretta.

Il cuore del classificatore è una funzione deterministica che traduce la risposta grezza (status, URL finale, title, HTML) in un verdetto, con ordine di precedenza dal segnale più forte al più debole:

def classify(raw, expected_marker=None):
    if raw.error:
        return Verdict.ERROR
    if raw.status in (403, 429, 503):
        return Verdict.HARD_BLOCK
    haystack = " ".join(filter(None, [raw.title or "", raw.html or ""]))
    if _HARD_RE.search(haystack):       # "access denied", "error 1020", ...
        return Verdict.HARD_BLOCK
    if _SOFT_RE.search(haystack):       # "just a moment", "turnstile", "datadome", ...
        return Verdict.SOFT_CHALLENGE
    if expected_marker and expected_marker.lower() not in haystack.lower():
        return Verdict.SOFT_CHALLENGE   # contenuto servito ma senza prova del reale
    return Verdict.OK

I marker testuali ("just a moment", "turnstile", "datadome", "error 1020", …) sono pattern osservati sui principali vendor: gli anti-bot cambiano i template, quindi vanno verificati sui propri target prima di pubblicare, aggiornando la data del test. Il runner esegue engine × target × N run, classifica, e scrive un report Markdown con la matrice e l’OK-rate per engine.

I miei numeri sull’esempio ricorrente (scheda prodotto Cloudflare + contrasto DataDome) vanno qui, prodotti eseguendo l’harness, non inventati:

[[MATRICE — inserire report-*.md generato dall'harness]]

Riempire questa matrice è il punto di tutto l’impianto: sono dati primari, datati, sul mio ambiente — l’opposto di una classifica copiata.

Perché NON fidarsi dei benchmark altrui alla cieca

Ecco il punto E-E-A-T forte, ed è anche la ragione per cui l’harness esiste. I benchmark pubblici di queste librerie si contraddicono apertamente. Paterson (2026) — 7 strumenti, 31 target Cloudflare, 651 verdetti da un singolo IP residenziale in modalità headful — mette nodriver al primo posto (28 OK, 0 bloccati), con patchright e camoufox a metà gruppo. Il benchmark techinz/browsers-benchmark, su un mix di Cloudflare/DataDome/Akamai/Kasada, mette patchright al primo posto (100% di bypass), con nodriver più in basso.

Non è che uno dei due sbagli: misurano cose diverse, in condizioni diverse. IP residenziale singolo contro proxy, headful contro headless, target live contro pannelli di detection. Il ranking è uno snapshot dipendente da target, IP e stato — esattamente ciò che la mia tassonomia mette in conto. La lezione operativa: qualsiasi numero (incluso il mio) va legato alla sua configurazione esatta, altrimenti è folklore. Se un articolo ti dà “la classifica definitiva” senza dirti IP, modalità e data, sta vendendo, non misurando.

Configurazione max-safety: i principi trasversali

Indipendentemente dalla libreria, sei principi spostano i verdetti più di qualsiasi scelta di nome. Sono incorporati negli adapter del mio harness, ma valgono universalmente:

  1. Headful o display virtuale, mai headless puro. Su server, xvfb-run. L’headless “nuovo” è migliore di un tempo, ma in benchmark perde ancora punti.
  2. Chrome di sistema, non il Chromium bundled. channel="chrome" dove la libreria lo permette: i vendor sanno distinguere Chrome reale da Chromium.
  3. Coerenza del fingerprint sopra tutto. Locale, timezone, WebRTC e geo devono combaciare con l’IP del proxy (geoip=True in camoufox quando c’è un proxy). Un Chrome italiano da un IP tedesco con timezone americana è un bot. La coerenza batte la randomizzazione.
  4. Rate realistico. Un minimo di attesa tra le richieste, non una raffica al millisecondo. È cortesia verso il target ed è anti-detection sullo strato comportamentale.
  5. Stabilità nel tempo. Un profilo stabile e coerente regge meglio di uno che cambia identità a ogni richiesta.
  6. Non sovradimensionare l’arma. Se il gate è solo-TLS, non lanciare un browser ricompilato con Xvfb: usa curl_cffi. Più overhead = più superficie d’errore.

Da qui una tabella decisionale che uso come prima euristica, da validare sempre con l’harness:

Natura del gate del targetStrato dominanteStrumento di prima scelta
Solo TLS / HTTP/2 (niente JS richiesto)2–3curl_cffi
Solo fingerprint JS, target morbido5playwright-stealth su Playwright
Rilevamento del protocollo di automazione (CDP)4nodriver / patchright
Fingerprint duro + managed challenge4–5camoufox (o patchright headful)
Serve un IP credibile (qualsiasi gate)1proxy residenziale/ISP — nessuna libreria basta

L’ultima riga è la più importante e introduce la sezione successiva.

I layer complementari (la guida dedicata)

La libreria copre due-tre strati. Gli altri richiedono un livello che è fuori dallo scope di qualsiasi pacchetto pip, e che merita una guida a parte. In sintesi, cosa resta da governare:

  • Proxy residenziali / ISP (strato 1). È la leva singola più potente. Su managed challenge e Turnstile, nella pratica, gli IP datacenter vengono filtrati e i residenziali alzano in modo netto il tasso di superamento — è consenso operativo diffuso, non una policy ufficiale dichiarata da Cloudflare, ma è ciò che si misura sul campo.
  • Spoofing TLS/JA4 coerente (strati 2–3). Quando usi un browser, il TLS te lo dà il browser; quando usi il request-layer, lo dà impersonate. Il problema è tenerli coerenti con tutto il resto.
  • CAPTCHA solving (strato 6). Per il Turnstile, nella pratica servono IP residenziali e, dove serve, servizi di solving. È l’ultima miglia, ed è la più costosa.
  • Orchestrazione (trasversale). Per volumi seri servono Scrapy o Crawlee, code, retry, gestione dello stato — e integrazioni come scrapy-nodriver. Qui la disciplina di ingegneria conta più della scelta della libreria.

In arrivo: una guida dedicata ai layer complementari (proxy, fingerprint, CAPTCHA, orchestrazione). Se lavori su rendering e accesso ai contenuti, intanto sono utili SSR vs CSR: server o client rendering e fare SEO da terminale con i comandi CLI.

Chiudiamo la tesi

Torniamo alla scheda prodotto dietro Cloudflare. curl_cffi ci dice in un colpo se il gate è solo-TLS — e se lo è, abbiamo finito con venti righe. Se cade dove un browser passa, sappiamo che il gate è JavaScript o comportamentale, e allora nodriver o patchright chiudono lo strato del protocollo di automazione, mentre camoufox è la scelta quando il fingerprint JS è il muro più alto. Ma in tutti questi scenari, il fattore che ha deciso il verdetto più spesso non è stato il nome della libreria: è stato l’IP. La libreria ha coperto due-tre strati su sette; gli altri — reputazione IP, coerenza del fingerprint, comportamento — li ha decisi tutto ciò che sta intorno alla libreria.

Questa è la lezione che i post “top 10 librerie scraping” non danno: non esiste la libreria che vince, esiste la combinazione che copre gli strati che il tuo target controlla davvero, misurata sul tuo ambiente, datata. Per questo l’harness vale più di qualsiasi classifica.

E la frontiera sposta ulteriormente il baricentro. Lo strato 7 — il fingerprint dell’hardware via WebAssembly e SIMD — è, a oggi, una tecnica dimostrata in ricerca accademica più che un fatto di produzione verificabile presso i grandi vendor: il lavoro esiste e funziona in laboratorio (distinguere la micro-architettura della CPU dal browser, con User-Agent falsificato, sotto l’1% di falsi positivi), ma chi te lo racconta come “già deployato ovunque” sta citando blog di vendor, non documentazione primaria. Detto questo, la direzione è chiara, ed è la chiusura onesta di questo pezzo: man mano che la detection scende verso l’hardware, lo stealth diventa meno una questione di mentire meglio e più una questione di hardware reale in location reali. Quando il segnale è la CPU fisica, nessuna patch software la falsifica: serve davvero un dispositivo vero su un IP vero. Il futuro dello scraping anti-detection assomiglia meno a una gara di travestimenti e più a una questione di infrastruttura.

Nota metodologica e fonti

Tutte le firme delle librerie sono verificate sulle fonti ufficiali (repo GitHub, PyPI, docs) a giugno 2026; le librerie si muovono in fretta, ricontrolla prima di una run seria. Le affermazioni sul modello di detection si appoggiano a fonti primarie e autorevoli, non a blog di terzi:

  • Cloudflare — Bot Management variables; Residential proxy detection (ML); JA4 Signals; Turnstile / challenge types.
  • FoxIO — specifica JA4. Akamai/Shuster — Passive Fingerprinting of HTTP/2 Clients (Black Hat EU 2017).
  • Rebrowser — meccanismo e fix del leak Runtime.enable; rebrowser-patches. DataDome — CDP signal, behavioral classification, CreepJS.
  • Ricerca sul fingerprint hardware — arXiv 2506.00719 (giugno 2025); CISPA, Browser-based CPU Fingerprinting.
  • Benchmark indipendenti (contraddittori per costruzione) — Paterson 2026 (ianlpaterson.com + repo); techinz/browsers-benchmark.
  • Repo/PyPI delle librerie — nodriver, patchright, camoufox, curl_cffi, SeleniumBase, Botasaurus, DrissionPage, Scrapling, playwright-stealth, zendriver.

Articolo di Giovanni Sacheli — chi sono. Se ti interessa il lato Python di questo lavoro, parto da Python, io e la SEO e dall’analisi log con Python e Regex.

Articoli correlati

8 min lettura

Sviluppare tool custom per la SEO utilizzando Python: dalla gestione della sintassi all'implementazione web tramite framework Django. Un'analisi pratica sull'automazione dei task, l'estrazione dati dalle SERP e la creazione di script operativi per professionisti del search marketing.
19 mi piace
9 min lettura

L'algoritmo Word2Vec trasforma le parole in vettori numerici densi sfruttando la semantica distribuzionale tramite modelli CBOW e Skip-Gram. Sebbene superato da embedding contestuali come BERT, resta il layer architetturale fondamentale per comprendere la ricerca vettoriale.
12 mi piace
16 min lettura

Gli embedding trasformano il testo in vettori numerici per elaborare la semantica testuale. Analisi tecnica su come estrarre vector embedding per la SEO tramite le API di GPT e Screaming Frog, sfruttando la dimensionalità dei modelli per il clustering avanzato dei contenuti.
5 mi piace
7 min lettura

La gestione dei 404 durante le migrazioni richiede automazione per preservare la link equity. migTool è uno script Python progettato per automatizzare la mappatura dei redirect 301 intelligenti, ottimizzando il processo di reindirizzamento ed eliminando le inefficienze manuali.
5 mi piace

Autore

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *

Ultimi articoli aggiornati

7 min lettura

La gestione dei 404 durante le migrazioni richiede automazione per preservare la link equity. migTool è uno script Python progettato per automatizzare la mappatura dei redirect 301 intelligenti, ottimizzando il processo di reindirizzamento ed eliminando le inefficienze manuali.
5 mi piace
13 min lettura

Script Python per la clusterizzazione avanzata di keyword tramite NLP, stemming e topic modeling con BERTopic o GPT. L'analisi statistica dei dataset permette ai SEO technical di estrarre l'intento di ricerca e scalare l'ottimizzazione dell'architettura informativa.
4 mi piace

Richiedi un preventivo SEO e Google Ads

Porta il tuo sito web al livello successivo con l’esperienza di EVE Milano. La nostra agenzia di Search Marketing ha ricevuto oltre

User Access Addon Required

This shortcode requires the CF7 Database User Access addon to display data.

Please purchase and install the User Access addon to enable this feature.

Purchase User Access Addon

richieste di preventivo, un segnale chiaro della fiducia che imprenditori e manager, come te, ripongono nella nostra specializzazione tecnica e verticale nella SEO e PPC. Se la tua organizzazione cerca competenze specifiche per emergere nei risultati di Google, noi siamo pronti a fornire quel valore aggiunto. Richiedi un preventivo ora e scopri la differenza tra noi e gli altri.
Richiedi un preventivo

Vuoi ricevere un avviso al mese con le nuove guide pubblicate?

Iscriviti alla newsletter!