Scraping avanzato: rate limit, sessioni, retry e rotazione senza sovraccaricare i siti
Pubblicato il · 6 min di lettura
Uno scraper che funziona su dieci pagine spesso si inceppa su diecimila: arrivano i 429, i captcha, le pagine vuote che rispondono 200. Quasi sempre il problema non è l'IP ma il modo in cui le richieste arrivano al sito. Questo articolo riprende le basi di [Web scraping con i proxy](/blog/web-scraping-proxy) e va un passo oltre: come costruire una raccolta dati che regge nel tempo e resta leggera per i siti che visita.
Leggere i segnali del sito
Un sito comunica i suoi limiti in modi diversi, e uno scraper robusto li riconosce tutti:
- 429 Too Many Requests: hai superato il ritmo accettato. Spesso arriva con l'intestazione Retry-After, che indica quanto aspettare: un numero di secondi oppure una data. Vedi anche errore 429.
- 503 Service Unavailable: il server è sovraccarico o in manutenzione. Anche qui può esserci Retry-After.
- 403 Forbidden: l'accesso è negato. Ripetere la stessa richiesta di solito non serve: controlla intestazioni, sessione e ritmo.
- Intestazioni di quota: alcune API e alcuni siti indicano le richieste rimaste con intestazioni come X-RateLimit-Remaining. Se ci sono, usale per rallentare prima del limite.
- Blocchi silenziosi: la risposta è 200, ma contiene un captcha, una pagina di consenso o un elenco vuoto. Si riconoscono solo controllando il contenuto.
Concorrenza per dominio, non richieste al secondo
Il carico che un sito sente dipende da quante richieste hai aperte nello stesso momento verso di lui, non dal totale che fai in un'ora. Per questo il primo parametro da regolare è la concorrenza per dominio: quante richieste parallele verso lo stesso sito.
- Parti basso: una o due richieste parallele per dominio, con pause variabili tra una e l'altra.
- Adatta il ritmo ai tempi di risposta: se le pagine iniziano a rispondere più lentamente, il server è sotto carico e conviene rallentare.
- Rispetta robots.txt: le regole di accesso sono standard (RFC 9309). La direttiva Crawl-delay non fa parte dello standard e Google la ignora, ma se un sito la indica è un'indicazione chiara del ritmo gradito.
- Distribuisci nel tempo: meglio un giro lento e costante durante la notte che una raffica all'ora di punta del sito.
In Scrapy questo comportamento si ottiene con l'estensione AutoThrottle (AUTOTHROTTLE_ENABLED), che adatta il ritardo alla latenza del sito, insieme a CONCURRENT_REQUESTS_PER_DOMAIN, DOWNLOAD_DELAY e ROBOTSTXT_OBEY.
Sessioni: quando tenere lo stesso IP
Per un sito una sessione è un insieme coerente: lo stesso IP, gli stessi cookie, lo stesso user agent e la stessa lingua. Se uno di questi cambia a metà, la sessione sembra passata a un'altra persona.
- Tieni lo stesso IP quando il sito usa login, carrello, filtri salvati o paginazione con token: è una sessione sticky.
- Cambia IP tra una sessione e l'altra, non durante: chiudi la sessione, ruota l'IP, riparti con cookie nuovi.
- Un proxy per flusso: se raccogli dati da più siti in parallelo, dai a ogni flusso il suo proxy, così una rotazione non interrompe gli altri.
Il ragionamento completo su quando ruotare e quando no è in Rotazione IP.
Retry fatti bene: backoff, jitter e un tetto
- Riprova solo quello che ha senso: timeout, errori di rete, 429, 502, 503 e 504. Un 404 o un 403 ripetuti restano tali.
- Rispetta Retry-After quando c'è: è il sito che ti dice quanto aspettare.
- Altrimenti backoff esponenziale con jitter: attese che crescono (5, 10, 20, 40 secondi) con una parte casuale, così più processi non riprovano tutti nello stesso istante.
- Metti un tetto: un numero massimo di tentativi e un'attesa massima. Oltre, salva l'URL e passa avanti.
- Pausa per dominio: se gli errori su un sito superano una soglia (per esempio il 10% nelle ultime cento richieste), ferma tutto il lavoro su quel sito per qualche minuto invece di insistere.
Rotazione con criterio
Con ProxyHub cambi IP dal link di rotazione, dall'API o con la rotazione automatica. Il link e l'API rispondono quando il cambio è completo, con il nuovo IP, e un proxy può cambiare IP al massimo una volta ogni 60 secondi.
- Ruota tra un giro e l'altro, non a ogni richiesta: ogni sessione nuova parte da un IP nuovo.
- Per volumi alti usa più proxy in parallelo: ognuno ha il suo IP dedicato, e mentre uno cambia gli altri continuano.
- Dopo un limite, rallenta prima di ruotare: se un sito ti limita, aspetta quanto indica e riparti più piano. Cambiare IP e riprendere allo stesso ritmo porta allo stesso risultato.
Meno carico per il sito, meno lavoro per te
- Richieste condizionali: salva ETag e Last-Modified e invia If-None-Match o If-Modified-Since. Se la pagina non è cambiata il server risponde 304, senza corpo.
- Sitemap: per scoprire le pagine usa la sitemap del sito invece di seguire tutti i link.
- Compressione: accetta gzip o br nell'intestazione Accept-Encoding.
- Solo quello che serve: nei browser automatizzati blocca immagini, font e video. Spesso i dati arrivano da una chiamata JSON che puoi leggere direttamente.
- Raccolta incrementale: riprendi solo le pagine nuove o cambiate, non tutto il sito a ogni giro.
Con Playwright, bloccare le risorse pesanti richiede una riga:
page.route("**/*.{png,jpg,jpeg,gif,webp,woff,woff2,mp4}", lambda route: route.abort())La configurazione del proxy in Playwright è spiegata nella guida Playwright.
Esempio in Python: Retry-After, backoff e rotazione
Uno scheletro che rispetta Retry-After, usa backoff con jitter e cambia IP solo dopo un limite ripetuto, tenendo conto dei 60 secondi tra un cambio e l'altro:
import random, time, requests
from email.utils import parsedate_to_datetime
PROXY = "http://UTENTE:PASSWORD@HOST:PORTA"
ROTATE = "LINK_DI_ROTAZIONE"
EXPECTED = 'class="price"' # elemento che la pagina deve contenere
session = requests.Session()
session.proxies = {"http": PROXY, "https": PROXY}
last_rotation = 0.0
def retry_after(r):
v = r.headers.get("Retry-After", "")
if v.isdigit():
return int(v)
try:
return max(0, parsedate_to_datetime(v).timestamp() - time.time())
except (TypeError, ValueError):
return None
def rotate():
global last_rotation
if time.time() - last_rotation >= 60: # un cambio al minuto per proxy
requests.get(ROTATE, timeout=30) # risponde con il nuovo IP
last_rotation = time.time()
session.cookies.clear() # nuova sessione, nuovi cookie
def fetch(url, tries=5):
for attempt in range(tries):
try:
r = session.get(url, timeout=30)
except (requests.ConnectionError, requests.Timeout):
time.sleep(min(60, 2 ** attempt) + random.random())
continue
if r.status_code == 200 and EXPECTED in r.text:
return r.text
if r.status_code == 200: # blocco silenzioso (captcha, pagina vuota)
wait = min(120, 10 * 2 ** attempt)
elif r.status_code in (429, 502, 503, 504):
wait = retry_after(r) or min(120, 5 * 2 ** attempt)
else:
r.raise_for_status() # 403, 404…: inutile riprovare
return r.text
if attempt >= 1:
rotate() # limite ripetuto: nuova sessione
time.sleep(wait + random.uniform(0, 3)) # jitter
raise RuntimeError(f"Troppi tentativi: {url}")Lo stesso schema funziona in Node.js e negli strumenti no-code: cambiano la libreria e la sintassi, non le regole. Se il tuo lavoro gira in automatico, trovi altri consigli nella pagina Proxy per automazioni e bot.
Domande frequenti
Quante richieste al secondo posso fare?
Non esiste un numero valido per tutti i siti. Parti con una o due richieste parallele per dominio e pause di qualche secondo, poi aumenta solo finché errori e tempi di risposta restano stabili. Se il sito indica Retry-After o Crawl-delay, segui quei valori.
Devo cambiare IP a ogni richiesta?
No: cambiare IP a metà sessione rompe login, carrelli e paginazione, e non riduce il carico sul sito. Cambia IP tra una sessione e l'altra; con ProxyHub ogni proxy può farlo una volta ogni 60 secondi, e per volumi alti conviene usare più proxy in parallelo.
Come capisco se il sito mi limita anche quando risponde 200?
Controlla il contenuto: se manca l'elemento che cerchi, se compare un captcha o se la pagina è molto più corta del solito, trattala come un errore. Registra questi casi a parte: sono il primo segnale che il ritmo è troppo alto.
Prova un proxy mobile 5G
Smartphone dedicato, traffico illimitato, IP reali di operatori. Attivo in pochi secondi.
Scopri i pianiOppure scegli il paese:
