Volver al blog
Guías
Raluca PenciucLast updated on May 8, 202611 min read

Cómo rotar proxies en Python

Cómo rotar proxies en Python
En resumen: Esta guía explica cómo rotar proxies en Python de principio a fin: elegir el tipo de proxy adecuado, crear y validar un grupo de proxies y, a continuación, rotarlos secuencialmente con itertools.cycle, aleatoriamente con random.choiceo de forma asíncrona con aiohttp. También combinamos la rotación de IP con la rotación de User-Agent y añadimos reintentos que tienen en cuenta el estado, para que un solo proxy defectuoso no arruine tu rastreo.

Si tu rastreador de Python ha empezado a devolver errores 403, 429 o páginas vacías después de funcionar bien ayer, es casi seguro que te están limitando el ancho de banda o bloqueando por IP. La solución a la que recurren la mayoría de los equipos es la rotación de proxies, y aprender a rotar proxies en Python es un rito de iniciación para cualquiera que quiera ir más allá de un script de aficionado.

La rotación de proxies en Python consiste en cambiar la IP de salida por cada solicitud, ya sea de forma programada o aleatoria, para que cada solicitud parezca provenir de una máquina diferente. Si se hace bien, distribuye la carga entre muchas IP, elude los límites de velocidad por IP y dificulta que los sistemas antibots identifiquen el tráfico del scraper. Si se hace mal, con una lista de IP libres desactualizada y una try/except, simplemente convierte una IP bloqueada en un conjunto de IP bloqueadas.

Este artículo es la versión práctica de cómo rotar proxies en Python. Elegiremos tipos de proxy, crearemos un conjunto validado, enviaremos una solicitud a través de Requests y luego repasaremos tres estrategias de rotación (secuencial, aleatoria y asíncrona). Combinaremos la rotación de IP con la rotación de encabezados, añadiremos un manejo de errores real y terminaremos con una comparación honesta entre comprar y crear.

Qué es la rotación de proxies y por qué tu rastreador de Python la necesita

Un proxy oculta tu IP real detrás de una intermedia, pero un único proxy estático sigue siendo una IP que un destino puede limitar en cuanto a la tasa de solicitudes y bloquear. La rotación de proxies cambia la IP de salida por solicitud o por sesión, de modo que el mismo scraper parece provenir de muchos orígenes.

Esto es importante porque los sistemas antibots se basan en gran medida en la limitación de velocidad, limitando las solicitudes por IP en un intervalo determinado antes de responder con códigos 429. La rotación a través de un conjunto adecuado mantiene cada IP por debajo de esos umbrales y evita que un solo bloqueo arruine todo el trabajo.

Elige el tipo de proxy adecuado antes de rotar

La rotación solo es tan buena como las IP que se rotan. Elegir el tipo incorrecto es la razón por la que los equipos pierden semanas ajustando la lógica contra un objetivo que nunca aceptaría su tráfico.

Tipo de proxy

Velocidad

Riesgo de bloqueo

Coste

Ideal para

Centro de datos

Más rápido

Excelente en sitios protegidos

Más bajo

API públicas, defensas ligeras

Residencial

Medio

Bajo

Medio-alto

Comercio electrónico, SERP, páginas con segmentación geográfica

Móvil (4G/5G)

Más lento

Más bajo

Más alto

Redes sociales, API de aplicaciones, objetivos fijos

ISP (residencial estático)

Rápido

Bajo

Medio-alto

Sesiones largas, scraping de cuentas

La primera decisión a la hora de rotar proxies en Python no es el algoritmo, sino hacer coincidir el conjunto de proxies con la defensa.

Configura tu entorno de Python para la rotación de proxies

Utiliza Python 3.8+ en un virtualenv. Instala Requests y aiohttp, y guarda los proxies en un archivo de texto plano para que el rotador pueda recargarlos sobre la marcha.

mkdir proxy_rotator && cd proxy_rotator
python -m venv .venv && source .venv/bin/activate
pip install requests aiohttp
touch app.py proxies.txt

Crea y valida una lista de proxies que funcione

Puedes armar una proxies.txt a partir de fuentes públicas (agregadores de proxies gratuitos, mirrors de GitHub) o cargar credenciales de un conjunto de pago. En cualquier caso, es de esperar que una parte significativa ya no funcione antes de tu primera solicitud, especialmente en las listas gratuitas, donde la mayoría de las entradas pueden estar ya bloqueadas por destinos populares.

Utiliza una entrada por línea, con el formato http://host:port o http://user:pass@host:port, y luego valida la lista con un punto final de eco de IP:

import requests

def validate(proxy, timeout=5):
    try:
        r = requests.get("https://httpbin.io/ip",
                         proxies={"http": proxy, "https": proxy},
                         timeout=timeout)
        return r.ok and proxy.split("@")[-1].split(":")[0] in r.text
    except requests.RequestException:
        return False

with open("proxies.txt") as f:
    pool = [p.strip() for p in f if p.strip() and validate(p.strip())]

La comprobación de coincidencia de IP detecta los proxies transparentes que dejan pasar tu dirección real. Para comprobaciones más exhaustivas, haz ping a una página de destino real en lugar de solo httpbin.io/ip.

Enviar una sola solicitud a través de un proxy con Requests

Antes de rotar nada, asegúrate de que un proxy funciona de extremo a extremo. Requests acepta un proxies diccionario en get() o en un Session; la misma URL suele funcionar para ambos http y https .

import requests

proxy = "http://user:pass@host:port"   # auth is embedded in the URL
proxies = {"http": proxy, "https": proxy}

with requests.Session() as s:
    s.proxies.update(proxies)
    r = s.get("https://httpbin.io/ip", timeout=10)
    print(r.status_code, r.json())

Si prefieres mantener la configuración del proxy fuera del código, establece el HTTP_PROXY y HTTPS_PROXY ; Requests las lee automáticamente. Los proxies gratuitos suelen generar SSLError: CERTIFICATE_VERIFY_FAILED porque interceptan TLS. Como solución temporal, puedes pasar verify=False, pero considéralo una herramienta de depuración, no una configuración de producción, ya que desactiva por completo la validación de certificados.

Cómo rotar proxies en Python: tres estrategias (secuencial, aleatoria y asíncrona)

Una vez que una sola solicitud funciona, la cuestión de cómo rotar proxies en Python se convierte en un equilibrio entre previsibilidad, sigilo y rendimiento. Los tres patrones que se describen a continuación cubren casi todos los casos reales de scraping.

Rotación secuencial con itertools.cycle

La rotación secuencial recorre el grupo en orden y vuelve al principio, distribuyendo el tráfico de manera uniforme. Es el patrón más fácil de entender porque siempre se sabe cuál es la siguiente IP.

import itertools, requests

with open("proxies.txt") as f:
    proxies = [p.strip() for p in f if p.strip()]

pool = itertools.cycle(proxies)

for _ in range(8):
    proxy = next(pool)
    r = requests.get("https://httpbin.io/ip",
                     proxies={"http": proxy, "https": proxy},
                     timeout=10)
    print(proxy, r.status_code)

La desventaja es que un orden determinista es en sí mismo una huella digital. Si un defensor ve las IP A, B, C, D, A, B, C, D procedentes de la misma huella digital del navegador en cuestión de segundos, puede marcar todo el conjunto. La rotación secuencial funciona mejor en conjuntos más grandes con retrasos más largos por IP.

Rotación aleatoria con random.choice

La rotación aleatoria rompe el patrón al elegir un proxy arbitrario en cada solicitud, lo que dificulta la correlación del tráfico.

import random, requests

with open("proxies.txt") as f:
    proxies = [p.strip() for p in f if p.strip()]

for _ in range(8):
    proxy = random.choice(proxies)
    r = requests.get("https://httpbin.io/ip",
                     proxies={"http": proxy, "https": proxy},
                     timeout=10)
    print(proxy, r.status_code)

El inconveniente es un uso desigual: un grupo pequeño sobreutilizará algunas direcciones IP y dejará otras inactivas. Para un mejor equilibrio, seleccione sin repeticiones hasta que se agote el grupo utilizando random.sample(proxies, len(proxies)) y, a continuación, vuelve a barajar. Esto mantiene las solicitudes impredecibles sin dejar de distribuir la carga.

Rotación asíncrona con aiohttp y asyncio

Cuando tu grupo supera unas pocas docenas de IP, validarlas en serie se convierte en el cuello de botella. La rotación asíncrona ejecuta muchas solicitudes simultáneamente en un solo subproceso, lo que reduce drásticamente el tiempo de validación y permite que un grupo de trabajadores se encargue de una lista de tareas sin bloquearse en proxies lentos.

import asyncio, aiohttp

CONCURRENCY = 20
TIMEOUT = aiohttp.ClientTimeout(total=10)

async def check_proxy(session, proxy, sem):
    async with sem:
        try:
            async with session.get("https://httpbin.io/ip",
                                   proxy=proxy, timeout=TIMEOUT) as r:
                return proxy, r.status, await r.text()
        except (aiohttp.ClientError, asyncio.TimeoutError) as e:
            return proxy, None, str(e)

async def main(proxies):
    sem = asyncio.Semaphore(CONCURRENCY)
    async with aiohttp.ClientSession() as session:
        tasks = [check_proxy(session, p, sem) for p in proxies]
        return await asyncio.gather(*tasks)

with open("proxies.txt") as f:
    proxies = [p.strip() for p in f if p.strip()]
results = asyncio.run(main(proxies))

El semáforo limita el número de solicitudes que se envían a la vez, para que no se agoten los descriptores de archivo ni se superen los límites de ráfaga del destino. aiohttp expone un argumento por solicitud proxy= , que se trata en detalle en la documentación avanzada del cliente aiohttp junto con el comportamiento de la autenticación y el entorno de confianza.

Combina la rotación de proxies con la rotación de User-Agent y encabezados

La rotación de IP por sí sola sigue revelando una huella digital. Si 200 IP diferentes envían el mismo python-requests/2.31.0 , un sistema antibots puede correlacionarlas al instante.

Rota los encabezados junto con los proxies y mantén las cookies vinculadas a la identidad que las estableció:

import random

UAS = [
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 ...",
    "Mozilla/5.0 (Macintosh; Intel Mac OS X 13_5) AppleWebKit/605.1.15 ...",
    "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 ...",
]
LANGS = ["en-US,en;q=0.9", "en-GB,en;q=0.8", "de-DE,de;q=0.9,en;q=0.8"]

def rotated_headers():
    return {"User-Agent": random.choice(UAS),
            "Accept-Language": random.choice(LANGS),
            "Referer": "https://www.google.com/"}

Vincula un User-Agent y un conjunto de cookies a un proxy durante la vida útil de una sesión lógica, y luego rótalos juntos cuando cambies de identidad.

Gestión de errores de nivel de producción y comprobaciones de estado de los proxies

La mayoría de los principiantes en rotación descartan un proxy ante cualquier error. Eso desperdicia direcciones IP que simplemente tenían una limitación de velocidad y trata un proxy averiado igual que un destino que te pide que reduzcas la velocidad.

Trata el código de respuesta como una señal. Según el RFC 6585, el 429 significa que hay demasiadas solicitudes, no que el proxy esté inactivo: retrocede e inténtalo de nuevo con la misma IP. Descarta los 407 o los errores de conexión repetidos, y pon en cuarentena los proxies defectuosos para poder volver a comprobarlos tras un periodo de espera.

import time, random
from collections import defaultdict

class ProxyManager:
    def __init__(self, proxies, max_fail=3, cooldown=300):
        self.live, self.dead = list(proxies), {}
        self.fails = defaultdict(int)
        self.max_fail, self.cooldown = max_fail, cooldown

    def get(self):
        self._revive()
        return random.choice(self.live) if self.live else None

    def report(self, proxy, status=None, error=None):
        if status == 429 or (status and 500 <= status < 600):
            time.sleep(min(2 ** self.fails[proxy], 30))   # keep, back off
        elif status == 407 or error:
            self.fails[proxy] += 1
            if self.fails[proxy] >= self.max_fail:
                self.live.remove(proxy)
                self.dead[proxy] = time.time() + self.cooldown

    def _revive(self):
        now = time.time()
        for p, t in list(self.dead.items()):
            if now >= t:
                self.live.append(p); self.dead.pop(p); self.fails[p] = 0

Ajusta max_fail y el retraso base a tu perfil de tráfico en lugar de copiar ciegamente los valores predeterminados.

Rotación manual frente a rotación gestionada: elige tu camino

Crear tu propio rotador está bien para aprender y para trabajos pequeños. A gran escala, se convierte en un segundo producto: rotación de proxies, validadores, reintentos y estar de guardia cuando un destino actualiza su pila.

Un proxy rotativo gestionado o una API de scraper oculta todo eso detrás de un único punto de acceso y factura por cada solicitud exitosa.

Signal

DIY ágil

Gestión ágil

Tamaño del grupo

< 100 IP

Más de mil

Dificultad del objetivo

Poco defendido

Marketplaces, SERP, redes sociales

Requisitos del SLA

Máximo esfuerzo

Tasa de éxito predecible

El objetivo de aprender a rotar proxies en Python no es mantener un rotador para siempre, sino saber cuándo basta con la rotación manual y cuándo delegar.

Conclusiones clave

  • Adapta el tipo de proxy al destino antes de ajustar la lógica de rotación; rotar IP de centros de datos baratas contra un sitio reforzado es una batalla perdida.
  • Una configuración fiable de rotación de proxies en Python comienza con un conjunto de proxies validado, no con una lista aleatoria, y vuelve a comprobar los proxies inactivos tras un periodo de espera, ya que los conjuntos libres oscilan entre estados funcionales y no funcionales.
  • Utiliza itertools.cycle para una distribución predecible, random.choice para el sigilo, y aiohttp con asyncio para una validación de alto rendimiento y recuperaciones simultáneas.
  • Rota los valores de User-Agent y los encabezados junto con las direcciones IP para no filtrar una huella digital estable detrás de 200 proxies diferentes.
  • Crea un rotador sensible al estado que retroceda ante los códigos 429 y 5xx, descarte ante el 407 o errores de conexión repetidos, y ponga en cuarentena los proxies defectuosos en lugar de tratar todas las excepciones de la misma manera.

Preguntas frecuentes

¿Cuál es la diferencia entre rotar los proxies por mi cuenta y utilizar una pasarela de proxies rotativos o una API de scraping?

Crear tu propio rotador significa que eres dueño de la lista de proxies, la validación, la lógica de reintentos y el enrutamiento geográfico. Una puerta de enlace de proxies rotativos expone un único punto final que elige una IP por ti en cada solicitud, mientras que una API de scraping también se encarga de la representación del navegador, los CAPTCHAs y el desbloqueo. El «hazlo tú mismo» te ofrece el máximo control; las puertas de enlace y las API ceden algo de control a cambio de mucho menos código de infraestructura.

¿Cuántos proxies necesito en mi grupo de rotación para un trabajo de scraping típico?

Una regla empírica útil para empezar es una IP en buen estado por cada trabajador simultáneo, más entre 5 y 10 veces más en reserva para absorber la rotación, los bloqueos y los proxies inactivos. Los trabajos pequeños de unos pocos miles de solicitudes pueden ejecutarse con entre 20 y 50 IP residenciales verificadas; los scrapes que se enfrentan a objetivos reforzados o a millones de páginas suelen necesitar miles de IP rotativas para mantener bajas las tasas de solicitudes por IP.

¿Por qué los proxies gratuitos siguen siendo bloqueados incluso cuando los roto en cada solicitud?

Los proxies gratuitos son compartidos por muchos desconocidos que ejecutan sus propios rastreadores, por lo que las IP suelen estar ya en la lista negra de los objetivos más populares incluso antes de que las utilices. Además, tienen fugas evidentes, enviando encabezados como Via o X-Forwarded-For, no coinciden con la IP que afirman tener o rompen el TLS. La rotación no puede solucionar una IP que ya está en la lista de denegados.

¿Debo rotar los proxies en cada solicitud o mantener una sesión persistente por sitio de destino?

Utiliza sesiones persistentes siempre que el sitio de destino vincule el estado a una IP, como en páginas de inicio de sesión, procesos de pago en varios pasos o flujos con mucho JavaScript que emiten muchas sub-solicitudes. Rota por solicitud cuando raspes listados sin estado, páginas de búsqueda o feeds de productos. Un patrón común es una IP por sesión lógica, y luego una IP nueva para la siguiente sesión.

¿Puedo reutilizar este patrón de rotación con Selenium o Playwright en lugar de Requests?

Sí, con algunos ajustes. Ambas herramientas de automatización de navegadores admiten configuraciones de proxy, pero normalmente hay que iniciar un contexto de navegador por cada proxy, ya que la mayoría de los controladores no permiten cambiar el proxy a mitad de sesión. Crea un grupo de navegadores de trabajo, cada uno vinculado a una IP y un User-Agent, y rota los propios navegadores de trabajo en lugar de la variable de proxy dentro de un único navegador.

Conclusión: de la rotación manual al scraping fiable

Saber cómo rotar proxies en Python es una habilidad fundamental para cualquier desarrollador que quiera ir más allá de un scraper de una sola IP. Ahora tienes los elementos básicos: elige el tipo de proxy adecuado para tu objetivo, valida el grupo antes de confiar en él, rota de forma secuencial, aleatoria o asíncrona dependiendo de tus prioridades, incorpora la rotación de User-Agent y utiliza un gestor que tenga en cuenta el estado para que un solo 429 no arruine una IP en buen estado.

Lo más difícil es mantener todo eso funcionando sin problemas frente a objetivos que cambian sus defensas sin previo aviso. Las listas gratuitas se deterioran, los grupos residenciales necesitan reequilibrarse y las reglas 429 varían. Si prefieres dedicar ese tiempo de ingeniería a los datos y no a la infraestructura, la API de scraping de WebScrapingAPI se encarga de la rotación de proxies, la evasión de antibots y los reintentos detrás de un único punto final, para que puedas mantener tu código Requests o aiohttp código y limitarte a cambiar la capa de obtención de datos. Rota las IP tú mismo para aprender o para trabajos pequeños, y recurre a una capa gestionada cuando el coste de mantenimiento supere el ahorro.

Acerca del autor
Raluca Penciuc, Desarrollador full-stack @ WebScrapingAPI
Raluca PenciucDesarrollador full-stack

Raluca Penciuc es desarrolladora full stack en WebScrapingAPI, donde se dedica a crear rastreadores, mejorar las técnicas de evasión y buscar formas fiables de reducir la detección en los sitios web de destino.

Empieza a crear

¿Estás listo para ampliar tu recopilación de datos?

Únete a más de 2000 empresas que utilizan WebScrapingAPI para extraer datos de la web a escala empresarial sin ningún gasto de infraestructura.