← Volver al blog

Lógica de reintento del parser: cómo las solicitudes repetidas consumen hasta el 40% del tráfico y cómo solucionarlo

Las solicitudes repetidas pueden consumir hasta el 40% del tráfico de proxy. Mostramos cómo calcular las pérdidas reales y reducirlas mediante un backoff adecuado, un circuito de interrupción y una rotación inteligente de proxies.

📅27 de septiembre de 2026

Si la factura de los proxies crece más rápido que el volumen de datos recolectados, el problema casi siempre está en la lógica de reintento. El parser repite en silencio las solicitudes fallidas varias veces, gastando tráfico en timeouts y captchas, y el desarrollador ni siquiera ve estos gastos en los logs. Analizaremos cómo calcular las pérdidas reales y reducirlas sin perder calidad de datos.

Por qué la lógica de reintento consume tráfico

La mayoría de los parsers están escritos con una lógica de reintento ingenua: si la solicitud no pasa, se repite, y así hasta 3-5 veces. El problema es que cada solicitud repetida no solo es una nueva solicitud HTTP, sino también un ciclo completo: handshake TCP, negociación TLS, carga de la página completa (incluso si solo se necesita un bloque de datos), y a veces incluso la recarga de imágenes o archivos JS, si el parser utiliza un navegador sin cabeza en lugar de un simple cliente HTTP.

Los reintentos son especialmente costosos al trabajar a través de proxies residenciales, donde el tráfico se cobra por volumen y no por número de solicitudes. Una solicitud fallida a una página de producto de Wildberries con imágenes y scripts puede costar entre 300-500 KB. Si el parser hace 3 reintentos en caso de timeout, usted paga por la misma solicitud fallida cuatro veces seguidas, y eso sin garantía de que el cuarto intento sea exitoso.

La segunda razón es el reintento por errores que no se pueden corregir repitiendo. Si el sitio devolvió un 403 debido a la detección de un bot, una solicitud repetida con la misma huella digital y con la misma sesión de cookies casi seguramente obtendrá la misma respuesta. El parser gasta tráfico en intentos que matemáticamente no pueden terminar en éxito, hasta que cambie la dirección IP o la huella del navegador.

Cuánto tráfico se destina realmente a los reintentos

Para entender la magnitud del problema, tomemos un ejemplo simple. El parser recolecta tarjetas de productos de un marketplace, el tamaño promedio de la respuesta es de 250 KB (HTML + JSON API + parte de estática). Con un funcionamiento estable sin bloqueos, la proporción de solicitudes fallidas se mantiene entre el 5-8%. Pero con un scraping agresivo a través de proxies de centros de datos baratos, este indicador puede aumentar hasta el 25-35%, porque el proveedor objetivo rápidamente reconoce el patrón y comienza a devolver captchas o bloqueos temporales por IP.

Contemos con cifras. Supongamos que necesitamos recolectar 100,000 tarjetas de productos:

Proporción de solicitudes fallidas Reintentos por solicitud (promedio) Tráfico total Sobrecosto
5% 0.15 28.75 GB +15%
15% 0.45 36.25 GB +45%
30% 0.90 47.5 GB +90%

Como se puede ver, con una proporción de fallos del 30% y una estrategia de reintento de "repetir hasta 3 veces", el tráfico real casi se duplica en comparación con el mínimo teórico de 25 GB. Esos más de 20 GB son pérdidas directas del presupuesto en proxies, que se pueden reducir si se revisa la lógica de los reintentos.

Errores comunes en la lógica de reintento de los parsers

Antes de corregir la lógica de reintento, es importante reconocer los patrones antipatrones comunes que se encuentran en el 90% de los parsers hechos a mano:

  • Reintento sin analizar el código de error. Se repite en cualquier situación anómala: 403, 429, 500, timeout, desconexión — aunque la estrategia de manejo para ellos debería ser diferente.
  • Retraso fijo entre reintentos. Por ejemplo, 2 segundos entre intentos independientemente de si es el primer intento o el quinto — esto es demasiado agresivo para el sitio o demasiado lento para grandes volúmenes.
  • Reintento con la misma IP y la misma sesión. Si el sitio bloqueó la solicitud por huella digital, repetir con parámetros idénticos no cambia el resultado, pero gasta tráfico.
  • No hay un límite superior en los intentos. Algunos parsers se quedan atrapados en URL "muertas" y hacen decenas de reintentos antes de rendirse.
  • Falta de distinción entre errores temporales y permanentes. 404 (página no existe) y 503 (servidor temporalmente no disponible) requieren lógica diferente — pero a menudo se manejan de la misma manera.

Backoff exponencial con código en Python

Una solución simple pero efectiva es el retraso exponencial con jitter (variación aleatoria), que reduce el número de reintentos innecesarios y distribuye la carga en el tiempo. En lugar de una pausa fija entre intentos, el retraso crece exponencialmente, lo que le da al sitio tiempo para "enfriarse" después de un bloqueo, y al parser no gastar tráfico en solicitudes que casi seguramente fallarán.

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:
                # no tiene sentido repetir — la página no existe físicamente
                return None

            if response.status_code not in retryable_codes:
                return None

        except (requests.exceptions.Timeout,
                requests.exceptions.ConnectionError):
            pass  # error de red temporal — se puede repetir

        if attempt == max_retries:
            return None

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

    return None

La idea clave de este código es la división de errores en tres categorías: aquellos que no se pueden corregir repitiendo (404, 410), aquellos que se pueden repetir con un retraso (429, 500-504, timeouts), y todo lo demás, que se considera un fracaso inmediato sin gastos en intentos adicionales. Esta división por sí misma reduce el tráfico innecesario en un 20-30% en comparación con el ingenuo "repetir todo".

Consejo: agregue el encabezado Retry-After en el manejo — muchos sitios indican cuántos segundos esperar antes de reintentar. Ignorar este encabezado es una causa común de bloqueos y tráfico innecesario.

Circuito de interrupción: cuándo detenerse

El backoff exponencial ayuda a nivel de una solicitud, pero no protege contra situaciones en las que todo el dominio o un proxy específico están temporalmente no disponibles para cientos de URL consecutivas. Aquí se necesita el patrón de circuito de interrupción — un "interruptor automático" que rastrea la proporción de errores durante un período reciente y detiene temporalmente los intentos si supera un umbral, en lugar de seguir golpeando una puerta cerrada.

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 lógica es simple: si más de la mitad de las últimas 50 solicitudes fallaron, el parser suspende los intentos en ese dominio o proxy durante 60 segundos. Durante este tiempo, se puede cambiar la IP, reducir la velocidad de las solicitudes o cambiar a otro grupo de proxies. Esto es especialmente importante al trabajar con sitios objetivo que bloquean temporalmente un rango de IP después de exceder la frecuencia de solicitudes; seguir golpeando una puerta cerrada significa simplemente quemar tráfico en vano.

Rotación inteligente de proxies en los reintentos

Una de las medidas más efectivas contra los reintentos innecesarios es no repetir la solicitud desde la misma IP que ya recibió un rechazo. La lógica es simple: si el error está relacionado con un bloqueo por IP (403, 429, redirección a captcha), cambiar de proxy antes de reintentar aumenta drásticamente la probabilidad de éxito y reduce el número de intentos.

Para el scraping de marketplaces como Wildberries, Ozon o Avito, funciona bien la combinación: las solicitudes normales se realizan a través de proxies de centros de datos — son más rápidos y baratos, y tan pronto como el detector de bloqueos se activa varias veces seguidas, el parser cambia a proxies residenciales, que son menos propensos a ser filtrados por sistemas anti-bots. Este enfoque híbrido reduce el consumo total de tráfico, ya que las costosas IP residenciales se utilizan solo donde realmente se necesitan, y no para todas las solicitudes consecutivas.

Tipo de error Estrategia de reintento ¿Cambio de IP necesario?
Timeout de conexión Backoff, 1-2 reintentos No
403 / captcha Rotación inmediata Sí, obligatorio
429 (límite de tasa) Backoff según Retry-After Deseable
500-503 Backoff, 2-3 reintentos No
404 / 410 Sin reintentos —

Para los parsers que emulan tráfico móvil (por ejemplo, la recolección de datos de versiones móviles de aplicaciones de marketplaces o redes sociales), tiene sentido utilizar proxies móviles — son menos sospechosos para los sistemas de protección precisamente porque los operadores de telecomunicaciones asignan las mismas IP a miles de usuarios reales al mismo tiempo, y el bloqueo puntual se vuelve poco práctico para el sitio objetivo.

Monitoreo de métricas de reintento

Sin métricas, la optimización de la lógica de reintento se convierte en una conjetura. El conjunto mínimo de indicadores que vale la pena registrar en cada solicitud:

  • Tasa de reintento — proporción de solicitudes que requirieron al menos un reintento.
  • Éxito después del reintento — qué porcentaje de reintentos finalmente tuvo éxito (si este indicador es bajo, los reintentos simplemente queman tráfico).
  • Tráfico en resultado exitoso — volumen total de datos transmitidos dividido por el número de registros recolectados con éxito. Esta es la métrica clave de efectividad.
  • Distribución de errores por códigos — ayuda a entender dónde ocurre la principal fuga de tráfico: timeouts, 403, 429 o algo más.
  • Tasa de reintento por nodos de proxy específicos — si una IP tiene una tasa de reintento del 80%, mientras que las demás tienen un 10%, el problema es local y se resuelve cambiando un nodo específico, no toda la lógica.

Incluso una simple tabla en Google Sheets o un log en CSV con estas cinco métricas, actualizada cada hora, proporciona suficientes datos para ver anomalías y ajustar la estrategia a tiempo — por ejemplo, reducir la frecuencia de solicitudes a una sección específica del sitio o aumentar la proporción de IP residenciales en el grupo.

Lista de verificación para la optimización del tráfico en reintentos

  1. Divida los códigos de error en reintentables y no reintentables — no repita 404/410.
  2. Implemente un backoff exponencial con jitter en lugar de un retraso fijo.
  3. Respete el encabezado Retry-After, si el sitio lo envía.
  4. Cambie la IP antes de reintentar en caso de 403 y sospecha de detección de bot.
  5. Establezca un límite estricto en el número de intentos (generalmente 3-4 es suficiente).
  6. Implemente un circuito de interrupción para dominios y nodos de proxy con alta tasa de fallos.
  7. Registre la tasa de reintento y el tráfico en resultados exitosos — sin métricas, la optimización es imposible.
  8. Divida el grupo de proxies: centros de datos baratos para áreas estables, IP residenciales o móviles para áreas problemáticas.

Conclusión

La lógica de reintento no es un detalle menor del parser, sino uno de los principales factores que influyen en el costo de la recolección de datos. Una estrategia ingenua de "repetir todo" puede aumentar el tráfico real en un 40-90% en comparación con el mínimo teórico, mientras que la mayor parte de los reintentos termina en el mismo fracaso que el primer intento. La división de errores por tipos, el backoff exponencial, el circuito de interrupción y la rotación inteligente de IP permiten reducir estas pérdidas drásticamente sin disminuir la integridad de los datos recolectados.

Si su parser trabaja con sitios que detectan agresivamente bots — marketplaces, redes sociales, plataformas publicitarias — es recomendable combinar varios tipos de proxies según la tarea. Para operaciones básicas, son adecuados los proxies de centros de datos, y donde se necesita la máxima resistencia a bloqueos, proxies residenciales con direcciones IP reales de usuarios comunes. Este enfoque híbrido, combinado con una lógica de reintento adecuada, proporciona una reducción notable en el consumo de tráfico manteniendo el mismo volumen de datos recolectados.