← Torna al blog

Logica di retry del parser: come le richieste ripetute consumano fino al 40% del traffico e come risolvere il problema

Le richieste ripetute possono consumare fino al 40% del traffico del proxy. Mostriamo come calcolare le perdite reali e ridurle attraverso un corretto backoff, un circuito di interruzione e una rotazione intelligente dei proxy.

📅27 settembre 2026

Se il costo per i proxy cresce più velocemente della quantità di dati raccolti, il problema è quasi sempre nella logica di retry. Il parser ripete silenziosamente le richieste non riuscite più volte, sprecando traffico per timeout e captcha, mentre lo sviluppatore non vede nemmeno queste spese nei log. Analizziamo come calcolare le perdite reali e ridurle senza compromettere la qualità dei dati.

Perché la logica di retry consuma traffico

La maggior parte dei parser è scritta con una logica di retry ingenua: se una richiesta fallisce, si ripete, e così via per 3-5 volte. Il problema è che ogni richiesta ripetuta non è solo una nuova richiesta HTTP, ma un ciclo completo: handshake TCP, negoziazione TLS, caricamento dell'intera pagina (anche se è necessario solo un blocco di dati), e a volte anche il ricaricamento di immagini o file JS, se il parser utilizza un browser headless invece di un semplice client HTTP.

I retry sono particolarmente costosi quando si lavora attraverso proxy residenziali, dove il traffico è tariffato in base al volume, e non al numero di richieste. Una richiesta fallita a una pagina prodotto di Wildberries con immagini e script può costare 300-500 KB. Se il parser fa 3 retry in caso di timeout, paghi per la stessa richiesta fallita quattro volte di seguito — e questo senza garanzia che il quarto tentativo avrà successo.

La seconda ragione è il retry per errori che non possono essere risolti con un nuovo tentativo. Se il sito restituisce 403 a causa della rilevazione di un bot, una richiesta ripetuta con lo stesso fingerprint e la stessa sessione di cookie quasi sicuramente riceverà la stessa risposta. Il parser spende traffico per tentativi che matematicamente non possono avere successo, finché non cambia l'indirizzo IP o il fingerprint del browser.

Quanto traffico va realmente ai retry

Per comprendere l'entità del problema, prendiamo un semplice esempio. Il parser raccoglie schede prodotto da un marketplace, la dimensione media della risposta è di 250 KB (HTML + JSON API + parte della statica). In condizioni di lavoro stabili senza blocchi, la percentuale di richieste non riuscite si attesta intorno al 5-8%. Ma durante un parsing aggressivo attraverso proxy economici dei data center, questa percentuale può salire al 25-35%, poiché il provider target riconosce rapidamente il pattern e inizia a restituire captcha o ban temporanei per IP.

Calcoliamo con i numeri. Supponiamo di dover raccogliere 100.000 schede prodotto:

Percentuale di richieste non riuscite Retry per 1 richiesta (in media) Traffico totale Spreco
5% 0.15 28.75 GB +15%
15% 0.45 36.25 GB +45%
30% 0.90 47.5 GB +90%

Come si può vedere, con una percentuale di fallimenti del 30% e una strategia di retry "ripeti fino a 3 volte", il traffico reale quasi raddoppia rispetto al minimo teorico di 25 GB. Questi oltre 20 GB in più rappresentano perdite dirette nel budget per i proxy, che possono essere ridotte se si rivede la logica dei retry.

Errori comuni nella logica di retry dei parser

Prima di correggere la logica di retry, è utile riconoscere i tipici antipattern che si trovano nel 90% dei parser scritti a mano:

  • Retry senza analizzare il codice di errore. Il retry si attiva per qualsiasi situazione anomala — 403, 429, 500, timeout, interruzione della connessione — mentre la strategia di gestione per essi dovrebbe essere diversa.
  • Ritardo fisso tra i retry. Ad esempio, 2 secondi tra i tentativi indipendentemente dal fatto che sia il primo o il quinto tentativo — è troppo aggressivo per il sito o troppo lento per grandi volumi.
  • Retry con lo stesso IP e la stessa sessione. Se il sito ha bloccato la richiesta per fingerprint, un retry con parametri identici non cambia l'esito, ma consuma traffico.
  • Assenza di un limite massimo ai tentativi. Alcuni parser si bloccano su URL "morti" e fanno decine di retry prima di arrendersi.
  • Assenza di distinzione tra errori temporanei e permanenti. 404 (pagina non esiste) e 503 (server temporaneamente non disponibile) richiedono logiche diverse — ma spesso vengono gestiti allo stesso modo.

Backoff esponenziale con codice in Python

Una soluzione semplice ma efficace è il backoff esponenziale con jitter (variazione casuale), che riduce il numero di retry inutili e distribuisce il carico nel tempo. Invece di una pausa fissa tra i tentativi, il ritardo cresce esponenzialmente, dando al sito il tempo di "raffreddarsi" dopo un blocco, e al parser stesso di non sprecare traffico per richieste che quasi sicuramente falliranno.

import time
import random
import requests

def fetch_with_backoff(url, proxies, max_retries=4, base_delay=1.0):
    retryable_codes = {429, 500, 502, 503, 504}
    non_retryable_codes = {404, 410}

    for attempt in range(max_retries + 1):
        try:
            response = requests.get(url, proxies=proxies, timeout=10)

            if response.status_code == 200:
                return response

            if response.status_code in non_retryable_codes:
                # non ha senso ripetere — la pagina non esiste fisicamente
                return None

            if response.status_code not in retryable_codes:
                return None

        except (requests.exceptions.Timeout,
                requests.exceptions.ConnectionError):
            pass  # errore di rete temporaneo — si può ripetere

        if attempt == max_retries:
            return None

        # backoff esponenziale con jitter
        delay = base_delay * (2 ** attempt) + random.uniform(0, 1)
        time.sleep(delay)

    return None

L'idea chiave di questo codice è la suddivisione degli errori in tre categorie: quelli che non possono essere risolti con un retry (404, 410), quelli che possono essere ripetuti con un ritardo (429, 500-504, timeout), e tutto il resto, che viene considerato un fallimento senza spese per tentativi aggiuntivi. Questa suddivisione riduce di per sé il traffico inutile del 20-30% rispetto al "retry tutto e basta".

Consiglio: aggiungi il Retry-After nell'elaborazione dell'intestazione — molti siti indicano quanti secondi aspettare prima di ripetere. Ignorare questa intestazione è una causa comune di ban e traffico inutili.

Circuit breaker: quando fermarsi

Il backoff esponenziale aiuta a livello di singola richiesta, ma non protegge da situazioni in cui l'intero dominio o un nodo proxy specifico è temporaneamente non disponibile per centinaia di URL consecutivi. Qui serve un pattern di circuit breaker — "interruttore automatico", che monitora la percentuale di errori nell'ultimo periodo e interrompe temporaneamente i tentativi se supera una soglia, invece di continuare a bussare a una porta chiusa.

class CircuitBreaker:
    def __init__(self, failure_threshold=0.5, window_size=50, cooldown=60):
        self.failure_threshold = failure_threshold
        self.window_size = window_size
        self.cooldown = cooldown
        self.results = []
        self.open_until = 0

    def is_open(self):
        return time.time() < self.open_until

    def record(self, success: bool):
        self.results.append(success)
        if len(self.results) > self.window_size:
            self.results.pop(0)

        if len(self.results) == self.window_size:
            failure_rate = 1 - sum(self.results) / self.window_size
            if failure_rate > self.failure_threshold:
                self.open_until = time.time() + self.cooldown
                self.results.clear()

La logica è semplice: se più della metà delle ultime 50 richieste sono fallite, il parser sospende i tentativi su quel dominio o proxy per 60 secondi. Durante questo tempo è possibile cambiare IP, ridurre la velocità delle richieste o passare a un altro pool di proxy. Questo è particolarmente importante quando si lavora con siti target che bloccano temporaneamente un intervallo di IP dopo aver superato la frequenza delle richieste — continuare a bussare a una porta chiusa significa semplicemente bruciare traffico inutilmente.

Rotazione intelligente dei proxy durante i retry

Una delle misure più efficaci contro i retry inutili è non ripetere la richiesta dallo stesso IP che ha già ricevuto un rifiuto. La logica è semplice: se l'errore è legato a un blocco per IP (403, 429, reindirizzamento a captcha), cambiare proxy prima del retry aumenta drasticamente la probabilità di successo e riduce il numero di tentativi.

Per il parsing di marketplace come Wildberries, Ozon o Avito, funziona bene una combinazione: le richieste normali vengono effettuate tramite proxy dei data center — sono più veloci e più economici, e non appena il rilevatore di blocco scatta più volte di seguito, il parser passa a proxy residenziali, che raramente vengono filtrati dai sistemi anti-bot. Questo approccio ibrido riduce il consumo totale di traffico, poiché gli IP residenziali costosi vengono utilizzati solo dove è realmente necessario, e non per tutte le richieste consecutive.

Tipo di errore Strategia di retry Cambio IP necessario?
Timeout di connessione Backoff, 1-2 retry No
403 / captcha Rotazione immediata Sì, obbligatorio
429 (limite di frequenza) Backoff secondo Retry-After Desiderabile
500-503 Backoff, 2-3 retry No
404 / 410 Senza retry —

Per i parser che emulano il traffico mobile (ad esempio, raccogliendo dati dalle versioni mobili delle applicazioni dei marketplace o dei social media), ha senso utilizzare proxy mobili — essi suscitano meno sospetti nei sistemi di protezione proprio perché gli operatori di rete assegnano gli stessi IP a migliaia di utenti reali contemporaneamente, e il blocco mirato diventa poco pratico per il sito target.

Monitoraggio delle metriche di retry

Senza metriche, l'ottimizzazione della logica di retry diventa una congettura. Il set minimo di indicatori che vale la pena registrare ad ogni richiesta:

  • Retry rate — percentuale di richieste che hanno richiesto almeno un retry.
  • Successo dopo retry — quale percentuale di retry ha avuto successo alla fine (se questo indicatore è basso, i retry bruciano semplicemente traffico).
  • Traffico per risultato riuscito — volume totale di dati trasmessi diviso per il numero di record raccolti con successo. Questa è la metrica chiave di efficienza.
  • Distribuzione degli errori per codice — aiuta a capire dove si verifica la principale perdita di traffico: timeout, 403, 429 o altro.
  • Retry rate per nodi proxy specifici — se un IP ha un retry rate dell'80%, mentre gli altri del 10%, il problema è locale e può essere risolto cambiando il nodo specifico, non tutta la logica.

Anche una semplice tabella in Google Sheets o un log in CSV con queste cinque metriche, aggiornato ogni ora, fornisce dati sufficienti per vedere anomalie e correggere tempestivamente la strategia — ad esempio, ridurre la frequenza delle richieste a una specifica sezione del sito o aumentare la percentuale di IP residenziali nel pool.

Checklist per l'ottimizzazione del traffico sui retry

  1. Dividi i codici di errore in retryable e non-retryable — non ripetere 404/410.
  2. Implementa un backoff esponenziale con jitter invece di un ritardo fisso.
  3. Rispetta l'intestazione Retry-After, se il sito la invia.
  4. Cambia IP prima del retry in caso di 403 e sospetto di rilevamento del bot.
  5. Imposta un limite rigido sul numero di tentativi (di solito 3-4 sono sufficienti).
  6. Implementa un circuit breaker per domini e nodi proxy con un alto tasso di fallimento.
  7. Registra il retry rate e il traffico per risultato riuscito — senza metriche l'ottimizzazione è impossibile.
  8. Dividi il pool di proxy: proxy economici dei data center per sezioni stabili, IP residenziali o mobili per sezioni problematiche.

Conclusione

La logica di retry non è un dettaglio secondario del parser, ma uno dei principali fattori che influenzano il costo della raccolta dati. Una strategia ingenua di "ripetere tutto" può aumentare il traffico reale del 40-90% rispetto al minimo teorico, mentre gran parte dei retry termina con lo stesso fallimento del primo tentativo. La suddivisione degli errori per tipo, il backoff esponenziale, il circuit breaker e la rotazione intelligente degli IP consentono di ridurre queste perdite di molto senza compromettere la completezza dei dati raccolti.

Se il tuo parser lavora con siti che rilevano aggressivamente i bot — marketplace, social media, piattaforme pubblicitarie — è utile combinare diversi tipi di proxy a seconda del compito. Per operazioni di base, sono adatti i proxy dei data center, mentre dove è necessaria la massima resistenza ai blocchi, si possono utilizzare proxy residenziali con indirizzi IP reali di utenti comuni. Questo approccio ibrido, insieme a una logica di retry ben progettata, porta a una significativa riduzione del consumo di traffico mantenendo lo stesso volume di dati raccolti.