Selenium è uno strumento di automazione del browser, nato in origine per il testing delle applicazioni web. Ma, proprio perché pilota un browser vero, da tempo viene usato in modo intensivo per lo scraping di siti, soprattutto quelli che servono i contenuti tramite JavaScript e non si aprono con una semplice richiesta HTTP.
In questo articolo vediamo come è fatto Selenium, come si usa nei vari linguaggi, quali sono i suoi punti di forza e di debolezza e perché i sistemi di protezione anti-bot lo rilevano con facilità.
Se stai ancora scegliendo l’approccio allo scraping, parti dalle nostre panoramiche «In quale linguaggio scrivere uno scraper? Panoramica delle soluzioni» e «Librerie per il web scraping» — lì confrontiamo gli strumenti ad alto livello. Questo articolo è l’analisi approfondita di uno di essi.
Che cos’è Selenium e come funziona
Selenium non controlla il browser «dall’interno», ma attraverso un driver separato tramite il protocollo WebDriver (uno standard W3C). Lo schema è sempre lo stesso:
Il tuo script ──▶ Binding di Selenium ──▶ Driver (chromedriver / geckodriver / …) ──▶ Browser- Il binding è la libreria nel tuo linguaggio (Python, Java, ecc.) che traduce chiamate come
driver.get(url)in comandi WebDriver. - Il driver è un eseguibile che fa da intermediario per un browser specifico:
chromedriverper Chrome,geckodriverper Firefox,msedgedriverper Edge. - Il browser è un Chrome/Firefox/Edge reale, che renderizza la pagina esattamente come per un utente normale.
Un tempo i driver andavano scaricati e messi nel PATH a mano, controllando la compatibilità tra le versioni del driver e del browser. Dalla versione 4.6 Selenium integra Selenium Manager: individua da solo il browser, sceglie e scarica il driver giusto. Al momento della stesura di questo articolo la versione corrente è Selenium 4.45 (giugno 2026). In pratica significa che oggi lo script minimo funzionante sta letteralmente in tre righe, senza dover armeggiare a mano con i driver.
La differenza principale rispetto agli scraper HTTP
Le librerie tradizionali (requests + BeautifulSoup, Scrapy ecc.) si limitano a scaricare l’HTML che il server ha restituito alla richiesta. Se il contenuto viene caricato da JavaScript già nel browser, in quell’HTML non ci sarà.
Selenium invece avvia un browser completo: il JS viene eseguito, le richieste XHR/fetch vanno a buon fine, si costruisce il DOM finale. Lo scraper vede esattamente ciò che vede una persona. È questa la ragione principale per scegliere Selenium — ma si paga in risorse e velocità (ne parliamo più avanti).
Selenium nei vari linguaggi
Uno dei principali vantaggi di Selenium sono i binding ufficiali per più linguaggi contemporaneamente. L’API è quasi identica ovunque; cambia solo la sintassi. È comodo: il team può scrivere lo scraper nello stesso linguaggio del resto del progetto.
Sono supportati ufficialmente Python, Java, JavaScript (Node.js), C# (.NET) e Ruby. Per PHP, Go, Rust e altri linguaggi esistono binding o wrapper della community, mantenuti però dalla community e non dal team principale di Selenium.
Python
Il linguaggio più popolare per lo scraping, e per Selenium in particolare: barriera d’ingresso bassa, un ecosistema enorme (pandas, lxml, BeautifulSoup per la post-elaborazione) e una marea di esempi pronti.
from selenium import webdriver
from selenium.webdriver.common.by import By
driver = webdriver.Chrome()
driver.get("https://example.com")
title = driver.find_element(By.TAG_NAME, "h1").text
print(title)
driver.quit()Pro: la community più grande, soluzioni anti-rilevamento già pronte (undetected-chromedriver, selenium-stealth, SeleniumBase), sviluppo rapido. Contro: il GIL limita il parallelismo reale — per scalare di solito si lanciano più processi o si usa Selenium Grid.
Java
Java è il linguaggio «di casa» di Selenium (il progetto è cresciuto storicamente attorno a esso) ed è lo standard nei grandi team QA aziendali.
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
public class Scraper {
public static void main(String[] args) {
WebDriver driver = new ChromeDriver();
driver.get("https://example.com");
String title = driver.findElement(By.tagName("h1")).getText();
System.out.println(title);
driver.quit();
}
}Pro: multithreading vero, prestazioni elevate, strumenti di build maturi (Maven/Gradle), comodo per sistemi grandi e longevi. Contro: sintassi prolissa; scrivere e prototipare richiede più tempo che in Python.
JavaScript (Node.js)
La scelta logica se il backend è già su Node. Il modello asincrono (async/await) si sposa bene con l’attesa del caricamento degli elementi.
const { Builder, By } = require("selenium-webdriver");
(async () => {
const driver = await new Builder().forBrowser("chrome").build();
await driver.get("https://example.com");
const title = await driver.findElement(By.css("h1")).getText();
console.log(title);
await driver.quit();
})();Pro: un unico linguaggio per frontend e backend, asincronia nativa. Contro: nella nicchia dell’automazione del browser su Node, Selenium ha concorrenti più forti — Puppeteer e Playwright, che molti preferiscono proprio nell’ecosistema JS.
C# (.NET)
Popolare negli ambienti enterprise su stack Microsoft.
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
var driver = new ChromeDriver();
driver.Navigate().GoToUrl("https://example.com");
var title = driver.FindElement(By.TagName("h1")).Text;
Console.WriteLine(title);
driver.Quit();Pro: tipizzazione rigorosa, buone prestazioni, integrazione eccellente con l’ecosistema .NET. Contro: meno esempi orientati allo scraping e meno librerie anti-rilevamento di terze parti rispetto a Python.
Ruby
require "selenium-webdriver"
driver = Selenium::WebDriver.for :chrome
driver.get "https://example.com"
title = driver.find_element(tag_name: "h1").text
puts title
driver.quitPro: sintassi concisa ed espressiva. Contro: una community relativamente piccola nelle attività di scraping, meno soluzioni pronte.
PHP, Go, Rust e altri
Per PHP c’è php-webdriver/php-webdriver; per Go e Rust, wrapper della community. Funzionano, ma: li mantiene la community, restano indietro rispetto ai binding ufficiali quanto a novità e sono documentati peggio proprio nel contesto dello scraping. Se il linguaggio del tuo progetto è uno di questi, spesso conviene valutare un’alternativa (per esempio un browser headless via CDP o uno scraper HTTP) invece di trascinarti dietro Selenium.
I vantaggi di Selenium
- Funziona con i siti dinamici. Esegue JavaScript e vede il DOM finale — ciò che gli scraper HTTP non possono ottenere senza emulare un browser.
- Imitazione di un utente reale. Clic, digitazione, scroll, hover, cambio di scheda, gestione dei cookie — tutto come una persona in carne e ossa.
- Multilinguaggio. Lo stesso approccio in Python, Java, JS, C#, Ruby — puoi restare nello stack del progetto.
- Multibrowser. Chrome, Firefox, Edge, Safari attraverso un’unica API.
- Maturità e documentazione. Il progetto ha più di 15 anni, una community gigantesca e la risposta a quasi ogni domanda è già su Stack Overflow.
- Controllo totale del browser. Screenshot, esecuzione di JS arbitrario, accesso al Chrome DevTools Protocol, intercettazione della rete.
Gli svantaggi di Selenium
- Lento e pesante. Avviare un browser completo a ogni sessione divora CPU e RAM. Su grandi volumi costa decine — a volte centinaia — di volte più risorse di una richiesta HTTP.
- Scala male «di forza bruta». Per elaborare migliaia di pagine in parallelo servono Selenium Grid, un pool di container o il cloud — un’infrastruttura a parte.
- Fragilità. Lo scraper dipende dalla struttura della pagina e dai tempi di caricamento. Se cambia il layout o slittano i ritardi, servono attese esplicite (
WebDriverWait), altrimenti si rompe tutto. - Più difficile da gestire in produzione. Le versioni di browser e driver devono coincidere (Selenium Manager toglie parte del fastidio, ma non tutto) e il browser in Docker richiede una configurazione accurata.
- E, soprattutto, si rileva con facilità. È il tema della prossima sezione.
Perché Selenium si rileva facilmente
È forse il problema pratico più importante. I moderni sistemi anti-bot (Cloudflare, DataDome, Imperva/Incapsula, PerimeterX e altri) sanno riconoscere un browser automatizzato da una moltitudine di indizi. E «di serie» Selenium lascia decine di tracce di questo tipo.
Le principali tracce che tradiscono Selenium
1. Il flag navigator.webdriver. Il marcatore più noto. All’avvio tramite WebDriver il browser imposta navigator.webdriver = true. Per un utente normale questa proprietà è false o undefined. Al sito basta una riga di JavaScript per marcare la visita come opera di un bot.
2. Le variabili $cdc_ e $wdc_. ChromeDriver inietta nel documento variabili di servizio (per esempio quelle che iniziano con $cdc_). Al rilevatore basta cercarne la presenza nell’oggetto document/window — e le trova.
3. Le tracce del Chrome DevTools Protocol (CDP). Selenium comunica con Chrome via CDP. L’attivazione del dominio Runtime (Runtime.Enable) viene rilevata a parte — è il cosiddetto «rilevamento di seconda generazione», e la maggior parte delle librerie anti-rilevamento più semplici non lo copre.
4. Le incoerenze in navigator. Se falsifichi lo User-Agent facendolo passare per un iPhone, ma navigator.platform resta Win32, il numero di core (hardwareConcurrency) è atipico per il dispositivo dichiarato e l’elenco di plugin e lingue appare «sterile», l’antifrode coglie l’incongruenza logica all’istante.
5. Le firme degli stessi comandi WebDriver. Le chiamate execute_script/execute_async_script lasciano tracce riconoscibili nello stack delle chiamate JS, dalle quali si può a sua volta riconoscere l’automazione.
6. Gli indizi comportamentali e di rete. Una velocità perfettamente uniforme, l’assenza di movimenti del mouse, cronologia e cookie a zero, oltre a un fingerprint TLS (JA3/JA4) e a un ordine degli header diversi da quelli di un browser vero. È la «terza generazione» del rilevamento.
Le «generazioni» del rilevamento: per capire con che cosa hai a che fare
Utile tenere a mente questa gradazione:
- Generazione 1 — controlli a livello di API.
navigator.webdriver, le variabili$cdc_e simili. Si copre con le librerie anti-rilevamento. - Generazione 2 — rilevamento a livello del protocollo CDP. Per esempio il monitoraggio di
Runtime.Enable. La maggior parte delle patch più diffuse ormai non lo risolve. - Generazione 3 — fingerprinting TLS, analisi comportamentale, modelli ML tarati sul singolo cliente. Non si chiude con patch lato client — qui servono proxy, rotazione, imitazione del comportamento e fingerprint di qualità.
Gli strumenti per «nascondere» Selenium
Eliminare del tutto il rilevamento è impossibile, ma ridurre la probabilità di blocco sì. Gli strumenti più usati:
undetected-chromedriver(Python) — patcha il binario del driver (rimuove la stringacdc_), nascondenavigator.webdriver, sistema le opzioni. A lungo considerato il «gold standard», ma copre soprattutto i problemi di prima generazione.selenium-stealth(Python) — un insieme di patch JS: falsificanavigator.webdriver,plugins,languages, il vendor WebGL ecc. Mantenuto meno attivamente di UC.SeleniumBaseUC Mode — aggiunge la tecnica del disconnect/reconnect: durante le azioni delicate scollega temporaneamente ChromeDriver dal browser, aggirando parte del rilevamento CDP.nodriver— il successore diundetected-chromedriver, dello stesso autore. Lavora direttamente via CDP, senza chromedriver né lo strato WebDriver, il che elimina una serie di marcatori. Non è più esattamente «Selenium», ma un approccio a sé.- Tecniche manuali — il flag
--disable-blink-features=AutomationControlled, la disattivazione dienable-automation, la sostituzione dinavigator.webdrivertramitePage.addScriptToEvaluateOnNewDocument, l’allineamento dello User-Agent con le proprietà reali di navigator.
Puoi verificare quanto bene si è «nascosto» il tuo browser su banchi di prova pubblici come bot.sannysoft.com o nei servizi di fingerprinting.
Un avvertimento importante
Nessuna di queste librerie è una pallottola d’argento. Le aziende anti-bot studiano le elusioni open source: quali patch applichi esattamente undetected-chromedriver si vede direttamente nel suo repository. Ciò che oggi supera una protezione può smettere di funzionare al prossimo aggiornamento — senza preavviso. Per questo, nello scraping serio, a Selenium si affiancano quasi sempre proxy di qualità con rotazione, ritardi ragionevoli, profili «riscaldati» con i cookie e l’imitazione del comportamento umano. E anche così, contro le protezioni di terza generazione il Selenium «nudo» spesso non basta.
Quando scegliere Selenium e quando no
Selenium è giustificato quando:
- il sito è costruito interamente in JavaScript e senza browser il contenuto non si ottiene;
- serve imitare uno scenario utente complesso (login, moduli in più passaggi, scroll infinito);
- i volumi sono moderati, non milioni di pagine all’ora;
- hai già uno stack Java/C#/Python e vuoi restarci.
Meglio cercare un’alternativa quando:
- i dati sono accessibili via HTTP/API normali — in quel caso
requests/Scrapy/httpxsaranno molte volte più veloci ed economici; - servono la massima scala e la massima velocità;
- l’obiettivo è superare una protezione anti-bot seria: qui spesso vincono Playwright o Puppeteer (più moderni, con un controllo migliore del browser e comodi plugin stealth) e, a volte,
nodrivero API specializzate.
Conclusione
Selenium è uno strumento potente e versatile: funziona con i siti dinamici, supporta molti linguaggi e browser, ha una community enorme e un’ottima documentazione. Tutto questo lo rende una buona scelta per lo scraping di pagine JS complesse e di scenari che imitano un utente reale.
Ma i pedaggi da pagare sono due, ed entrambi seri: il consumo di risorse (quindi problemi di velocità e di scala) e la facilità di rilevamento. «Di serie» Selenium lascia decine di tracce di automazione e, anche se in parte si possono mascherare, contro le protezioni anti-bot moderne spesso non è abbastanza.
La conclusione pratica è semplice: se i dati si possono ottenere con una richiesta HTTP, usa uno scraper HTTP. Se senza browser non se ne esce, Selenium andrà benissimo, ma metti in conto nel progetto proxy, rotazione, comportamento umano e anti-rilevamento; e per gli obiettivi più protetti confrontalo onestamente con Playwright, Puppeteer e le soluzioni più recenti.