Rotar proxies en Python: requests, httpx y aiohttp (Guía 2026)

Publicado el 2 de junio de 2026 · ≈10 min de lectura

Si haces scraping, rastreo o automatizas cualquier cosa a escala en Python, tarde o temprano el sitio objetivo nota que todas las solicitudes provienen de una sola IP y te bloquea. Rotar proxies en Python reparte tu tráfico entre muchas direcciones IP para que ninguna por sí sola active una limitación de tasa ni se gane un baneo. Esta guía muestra el código exacto para requests, httpx y aiohttp, además de cómo elegir entre una puerta de enlace rotativa y un pool de IP gestionado.

Dos decisiones transversales determinan todo lo que viene a continuación. Primera: sesiones rotativas vs. sticky — una IP nueva por solicitud, o una sola IP mantenida durante un flujo de varios pasos. Segunda: IP residenciales vs. de centro de datos — consulta la matriz de decisión por tipo de proxy. Acierta con esas dos y el código es la parte fácil.

Dos formas de rotar

1. Rotación por puerta de enlace (recomendada). Te conectas a un único endpoint y el proveedor te entrega una IP de salida nueva en cada conexión nueva. No hay lista que administrar ni IP muertas que depurar. El pool residencial dinámico de JIBAO funciona así: mismo host y puerto, una IP nueva en cada solicitud.

2. Lista de IP autogestionada. Mantienes una lista de entradas host:port y eliges una por solicitud. Más control, pero te encargas tú del chequeo de salud, los reintentos y el seguimiento de baneos. Útil con IP dedicadas de centro de datos cuando necesitas direcciones conocidas y estables.

Rotar con requests

El caso más sencillo — enrutar una solicitud a través de una puerta de enlace que rota por ti. Usa socks5h:// (la h final significa que el DNS se resuelve del lado del proxy, lo que evita filtrar las resoluciones):

import requests

# JIBAO rotating residential gateway: a new exit IP per connection
PROXY = "socks5h://USERNAME:[email protected]:10001"

proxies = {"http": PROXY, "https": PROXY}

for _ in range(5):
    r = requests.get("https://httpbin.org/ip", proxies=proxies, timeout=30)
    print(r.json()["origin"])   # a different IP each loop

¿Necesitas que requests hable SOCKS5? Instala el extra: pip install "requests[socks]". Si prefieres un endpoint de proxy HTTP, cambia el esquema a http:// — el resto es idéntico.

Rotar desde tu propia lista de IP

import random
import requests

PROXY_POOL = [
    "socks5h://USERNAME-country-us:[email protected]:10001",
    "socks5h://USERNAME-country-uk:[email protected]:10001",
    "socks5h://USERNAME-country-de:[email protected]:10001",
]

def fetch(url):
    proxy = random.choice(PROXY_POOL)
    return requests.get(url, proxies={"http": proxy, "https": proxy}, timeout=30)

resp = fetch("https://example.com")
print(resp.status_code)

Sesiones sticky cuando debes mantener una sola IP

Los flujos de inicio de sesión, los carritos y los resultados paginados se rompen si la IP cambia a mitad de la tarea. Fija una IP añadiendo un token de sesión al nombre de usuario; reutiliza el mismo token para conservar la misma IP de salida durante toda su vida útil:

import requests

SESSION_ID = "task-0001"
PROXY = f"socks5h://USERNAME-session-{SESSION_ID}:[email protected]:10001"

s = requests.Session()
s.proxies = {"http": PROXY, "https": PROXY}

s.post("https://example.com/login", data={"u": "me", "p": "secret"})
s.get("https://example.com/dashboard")   # same IP, session intact

Rotar con httpx

httpx te ofrece un cliente moderno con HTTP/2 y async nativo. Ten en cuenta que las versiones más recientes aceptan un único argumento proxy=:

import httpx

PROXY = "socks5h://USERNAME:[email protected]:10001"

with httpx.Client(proxy=PROXY, timeout=30) as client:
    for _ in range(5):
        print(client.get("https://httpbin.org/ip").json()["origin"])

El soporte de SOCKS en httpx requiere pip install "httpx[socks]". Para HTTP/2, añade http2=True al cliente — hace que tu tráfico se parezca más al de un navegador real, lo que combina bien con la coincidencia de huella TLS.

Rotación concurrente con aiohttp

Para un alto rendimiento, lanza muchas solicitudes a la vez. Cada conexión a través de la puerta de enlace obtiene su propia IP de salida, así que la concurrencia y la rotación van de la mano:

import asyncio
import aiohttp
from aiohttp_socks import ProxyConnector

PROXY = "socks5://USERNAME:[email protected]:10001"

async def fetch(url):
    connector = ProxyConnector.from_url(PROXY)
    async with aiohttp.ClientSession(connector=connector) as session:
        async with session.get(url, timeout=aiohttp.ClientTimeout(total=30)) as r:
            return await r.text()

async def main():
    urls = ["https://httpbin.org/ip"] * 20
    results = await asyncio.gather(*(fetch(u) for u in urls))
    print(f"fetched {len(results)} pages")

asyncio.run(main())

Instala el conector SOCKS con pip install aiohttp_socks. Construye un conector nuevo por tarea para que cada solicitud abra una conexión proxificada nueva.

Lógica de reintentos que realmente ayuda

La rotación solo da fruto si reintentas los fallos en una IP nueva. Aplica retroceso exponencial y rota el token de sesión en cada intento:

import requests
from time import sleep

def fetch_with_retry(url, max_retries=4):
    for attempt in range(max_retries):
        proxy = f"socks5h://USERNAME-session-r{attempt}:[email protected]:10001"
        try:
            r = requests.get(url, proxies={"http": proxy, "https": proxy}, timeout=30)
            if r.status_code in (403, 429):
                raise requests.HTTPError(f"blocked: {r.status_code}")
            r.raise_for_status()
            return r.text
        except requests.RequestException:
            sleep(2 ** attempt)        # 1s, 2s, 4s, 8s
    raise RuntimeError(f"failed after {max_retries} tries: {url}")

Verifica que tu rotación funciona

Antes de una ejecución grande, confirma que la IP realmente cambia. Consulta un endpoint de eco unas cuantas veces y comprueba que las IP difieren. Para confirmar además que tu huella TLS no te delata, lanza la solicitud contra el verificador gratuito de huella JA3/TLS de JIBAO — una IP rotativa con una huella de Python que te delata a la primera igual termina bloqueada.

Buenas prácticas

Una vez que la rotación es sólida, el siguiente muro con el que sueles chocar es el fingerprinting, no las IP. Si las IP residenciales limpias siguen recibiendo 403, lee cómo eludir el fingerprinting TLS con curl_cffi y la receta completa para eludir Cloudflare.

Consigue proxies residenciales rotativos

Obtén 500MB de tráfico gratis y una puerta de enlace residencial rotativa que te entrega una IP nueva en cada solicitud.

Empezar prueba gratuita

Para todos los productos IP · un enorme pool de nodos disponibles en cualquier momento

Regístrate ahora y obtén hasta un 100% de reembolso en tu recarga

Los nuevos usuarios reciben 500MB al registrarse, más un bono en la primera recarga. Oferta por tiempo limitado.