Cómo usar proxies en Python Requests: configuración y rotación de IP
Aprende a configurar proxies en Python Requests, incluyendo autenticación, SOCKS5, variables de entorno y rotación avanzada de IP con lógica de reintentos para un web scraping resistente.
Por qué importa configurar un proxy
Al hacer scraping web o acceder a contenido con restricciones geográficas, tu dirección IP a menudo determina el éxito o el fracaso. Los proxies te permiten enrutar las solicitudes a través de un servidor intermediario, enmascarar tu origen y repartir la carga. La biblioteca requests de Python facilita la integración de proxies, pero el uso real exige más que un único proxy estático. Este artículo te lleva desde la configuración básica hasta un sistema de proxies rotativos y resistente.
Configuración básica de proxy con el diccionario proxies
La forma más sencilla de usar un proxy es pasar un diccionario al parámetro proxies. Las claves son los protocolos (http, https) y los valores son las URL de los proxies.
import requests
proxies = {
'http': 'http://proxy.example.com:8080',
'https': 'http://proxy.example.com:8080',
}
response = requests.get('http://httpbin.org/ip', proxies=proxies)
print(response.json())Si solo necesitas un proxy para un protocolo, omite el otro. Requests recurrirá al proxy http para https si no se especifica https, pero eso a menudo falla con errores de HTTPS; especifica siempre ambos.
Proxies con autenticación
Muchos proxies de pago o privados requieren un nombre de usuario y una contraseña. Inclúyelos directamente en la URL:
proxies = {
'http': 'http://user:pass@proxy.example.com:8080',
'https': 'http://user:pass@proxy.example.com:8080',
}Requests gestiona automáticamente la cabecera Proxy-Authorization. Para autenticación más compleja (p. ej., NTLM), considera la biblioteca requests-ntlm.
SOCKS5 frente a SOCKS5h
Los proxies SOCKS suelen ser más rápidos para el tráfico TCP, pero requieren el paquete PySocks (pip install PySocks). Existen dos variantes: socks5 resuelve el DNS localmente (en el cliente), mientras que socks5h lo resuelve de forma remota (en el proxy).
# DNS remoto (recomendado para la privacidad)
proxies = {
'http': 'socks5h://proxy.example.com:1080',
'https': 'socks5h://proxy.example.com:1080',
}Usa socks5h para evitar que las consultas DNS se filtren a tu ISP o a tu red local. Si el proxy proporciona DNS, también puede almacenar en caché o filtrar los resultados; ten en cuenta esa contrapartida.
Variables de entorno
Requests también respeta las variables de entorno estándar HTTP_PROXY, HTTPS_PROXY y NO_PROXY. Esto resulta útil para aplicar un proxy de forma global sin modificar el código.
import os
os.environ['HTTP_PROXY'] = 'http://proxy.example.com:8080'
os.environ['HTTPS_PROXY'] = 'http://proxy.example.com:8080'
os.environ['NO_PROXY'] = 'localhost,127.0.0.1'Ten en cuenta que el diccionario proxies tiene prioridad sobre las variables de entorno cuando ambas opciones están configuradas.
Usar sesiones para conservar la configuración de proxy
Si haces varias solicitudes, un objeto Session conserva la configuración del proxy, los grupos de conexiones y las cookies. Configura session.proxies una vez y reutiliza la sesión.
session = requests.Session()
session.proxies = proxies
response = session.get('http://httpbin.org/ip')Esto evita volver a autenticarse en cada solicitud y mejora el rendimiento.
Rotación avanzada de IP: grupos de proxies rotativos
Los proxies estáticos se bloquean con rapidez. Rotar entre un grupo reparte las solicitudes entre varias IP. Usa itertools.cycle para repetir el ciclo sin fin.
import itertools
proxy_pool = itertools.cycle([
'http://proxy1.com:8080',
'http://proxy2.com:8080',
'http://proxy3.com:8080',
])
for _ in range(10):
proxy = next(proxy_pool)
response = requests.get('http://httpbin.org/ip', proxies={'http': proxy})Para grupos más grandes, lee los proxies desde un archivo o consulta una fuente dinámica como la lista de proxies gratuitos de ProxyVerity. Valida siempre los proxies antes de usarlos de forma intensiva: una prueba rápida con un endpoint conocido evita fallos silenciosos.
Lógica de reintentos con backoff exponencial
Los fallos transitorios (tiempos de espera agotados, errores 5xx) son inevitables. Requests puede reintentar automáticamente mediante un HTTPAdapter con una política de Retry.
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
session = requests.Session()
retries = Retry(total=5, backoff_factor=1, status_forcelist=[500, 502, 503, 504])
session.mount('http://', HTTPAdapter(max_retries=retries))
session.mount('https://', HTTPAdapter(max_retries=retries))El backoff_factor hace que se espere 0,5 s, 1 s, 2 s, 4 s y 8 s tras fallos sucesivos; repartir las solicitudes ayuda a evitar que se activen los límites de frecuencia.
Gestión de tiempos de espera y errores
Define siempre un tiempo de espera para evitar que la solicitud se quede colgada. Captura las excepciones específicas de proxy para gestionar de forma controlada los proxies dañados o que no responden.
try:
response = requests.get('http://example.com', proxies=proxies, timeout=10)
response.raise_for_status()
except requests.exceptions.Timeout:
print('Request timed out')
except requests.exceptions.ProxyError:
print('Proxy error – remove this proxy')
except requests.exceptions.RequestException as e:
print(e)Usa timeout como una tupla para separar los tiempos de espera de conexión y de lectura: timeout=(3, 8).
Cómo construir un scraper resistente
Combina la rotación de IP, los reintentos y el manejo de errores en una función de descarga reutilizable.
import itertools
import time
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
proxy_list = ['http://proxy1.com:8080', 'http://proxy2.com:8080']
proxy_cycle = itertools.cycle(proxy_list)
session = requests.Session()
retries = Retry(total=3, backoff_factor=0.5, status_forcelist=[500, 502, 503])
session.mount('http://', HTTPAdapter(max_retries=retries))
def fetch(url):
for _ in range(len(proxy_list)):
proxy = next(proxy_cycle)
try:
response = session.get(url, proxies={'http': proxy}, timeout=5)
return response
except (requests.exceptions.ProxyError, requests.exceptions.Timeout):
continue
return NoneEsta función prueba cada proxy una vez y luego desiste. Para mayor robustez, registra los fallos, elimina los proxies muertos del grupo e intégrate con el verificador de ProxyVerity para actualizar la lista.
Cómo elegir los proxies adecuados
No todos los proxies son iguales. Los proxies públicos gratuitos suelen tener una vida útil corta, poca velocidad o exponer tus datos. Para uso en producción, considera proveedores de confianza o crea tu propio grupo a partir de proxies gratuitos verificados filtrados por ubicación y nivel de anonimato. Nuestra herramienta de detección de IP ayuda a confirmar que el proxy funciona correctamente.
Seguridad y legalidad
Los proxies hacen pasar tu tráfico por un tercero. Los proxies públicos pueden registrar, modificar o robar datos: nunca envíes información sensible a través de ellos. Usa siempre HTTPS de extremo a extremo para cifrar la carga útil, aunque el proxy sigue viendo la IP de destino y el handshake. A efectos legales, el scraping debe respetar robots.txt y los términos del servicio del sitio. La rotación de IPs para eludir los límites de frecuencia puede infringir estas condiciones. Usa los proxies de forma responsable y solo con fines éticos.