Cómo solucionar problemas con cookies a través de proxy
Las cookies son una de las fuentes más frecuentes de errores al trabajar con proxy. Las sesiones se interrumpen, la autorización falla, se pierden datos. En este artículo descubriremos por qué sucede esto y cómo configurar correctamente el manejo de cookies para un funcionamiento estable.
Por qué se pierden las cookies al usar proxy
Cuando envías una solicitud a través de proxy, entre tu cliente y el servidor de destino se interpone un nodo intermedio. Esto crea varios problemas:
- Diferentes direcciones IP para una misma sesión. El servidor puede notar que las solicitudes provienen de diferentes direcciones y rechazar las cookies como sospechosas.
- Pérdida de encabezados Set-Cookie. Una configuración incorrecta del proxy puede no transmitir los encabezados Set-Cookie al cliente.
- Falta de coincidencia de dominio y ruta. Si el proxy reescribe el encabezado Host, las cookies pueden no guardarse debido a una falta de coincidencia de dominio.
- Ausencia de preservación de estado. Si envías cada solicitud por separado sin guardar cookies, la sesión se perderá.
Qué es cookie jar y cómo usarlo
Cookie jar es un almacén de cookies que gestiona automáticamente su envío y recepción. En lugar de agregar manualmente encabezados Cookie en cada solicitud, permites que la biblioteca lo haga automáticamente.
La mayoría de los clientes HTTP tienen soporte integrado para cookie jar:
import requests
from requests.cookies import RequestsCookieJar
# Creamos un jar para almacenar cookies
jar = RequestsCookieJar()
# Primera solicitud — el servidor enviará Set-Cookie
response1 = requests.get(
'https://example.com/login',
cookies=jar,
proxies={'https': 'http://proxy.example.com:8080'}
)
# Las cookies se guardan automáticamente en jar
print(jar)
# Segunda solicitud — las cookies se enviarán automáticamente
response2 = requests.get(
'https://example.com/dashboard',
cookies=jar,
proxies={'https': 'http://proxy.example.com:8080'}
)
Sin jar, tendrías que analizar manualmente Set-Cookie y agregarlos a la siguiente solicitud — esto es poco confiable y engorroso.
Guardando cookies entre solicitudes
Si tu script funciona durante mucho tiempo o necesitas restaurar la sesión después de un reinicio, guarda las cookies en un archivo:
import requests
from http.cookiejar import LWPCookieJar
# Creamos un jar con guardado en archivo
jar = LWPCookieJar('cookies.txt')
# Cargamos cookies antiguas si existen
try:
jar.load(ignore_discard=True, ignore_expires=True)
except FileNotFoundError:
pass
# Usamos jar en solicitudes
response = requests.get(
'https://example.com/login',
cookies=jar,
proxies={'https': 'http://proxy.example.com:8080'}
)
# Guardamos cookies actualizadas
jar.save(ignore_discard=True, ignore_expires=True)
Las banderas ignore_discard=True e ignore_expires=True permiten guardar incluso cookies temporales.
Problemas con la vinculación de dominio de cookies
Las cookies tienen un atributo Domain que determina para qué dominios se enviarán. Los problemas surgen si:
- El proxy reescribe Host. Si el proxy cambia el encabezado Host, cookie jar puede rechazar la cookie como perteneciente a otro dominio.
- Los subdominios no coinciden. Una cookie para
example.compuede no enviarse aapi.example.com. - La ruta no coincide. Una cookie para
/apino se enviará a/admin.
Verifica los atributos de la cookie así:
import requests
response = requests.get(
'https://example.com',
proxies={'https': 'http://proxy.example.com:8080'}
)
# Mostramos todas las cookies
for cookie in response.cookies:
print(f"Name: {cookie.name}")
print(f"Value: {cookie.value}")
print(f"Domain: {cookie.domain}")
print(f"Path: {cookie.path}")
print(f"Secure: {cookie.secure}")
print(f"HttpOnly: {cookie.has_nonstandard_attr('HttpOnly')}")
print("---")
Si Domain es demasiado restrictivo, intenta transmitir explícitamente las cookies en lugar de gestión automática:
headers = {
'Cookie': 'session_id=abc123; user_token=xyz789'
}
response = requests.get(
'https://example.com/api',
headers=headers,
proxies={'https': 'http://proxy.example.com:8080'}
)
Banderas Secure e HttpOnly
La bandera Secure significa que la cookie se envía solo por HTTPS. Si usas un proxy HTTP para acceder a un recurso HTTPS, asegúrate de que la conexión al proxy esté protegida o que el proxy reenvíe correctamente HTTPS.
La bandera HttpOnly prohíbe el acceso a la cookie desde JavaScript. Esto no afecta el envío de la cookie en solicitudes, pero es importante recordar que no podrás leer tales cookies desde el navegador.
Al trabajar con proxies residenciales asegúrate de que:
- El proxy soporta HTTPS (método CONNECT)
- Los certificados son válidos (no uses
verify=Falseen producción) - Los encabezados no se reescriben por el proxy
Ejemplos prácticos con código
Ejemplo 1: Inicio de sesión con preservación de sesión
import requests
from requests.cookies import RequestsCookieJar
jar = RequestsCookieJar()
proxy = 'http://proxy.example.com:8080'
# Inicio de sesión
login_response = requests.post(
'https://example.com/login',
data={'username': 'user', 'password': 'pass'},
cookies=jar,
proxies={'https': proxy}
)
if login_response.status_code == 200:
print("Inicio de sesión exitoso")
# Usamos la sesión guardada
dashboard = requests.get(
'https://example.com/dashboard',
cookies=jar,
proxies={'https': proxy}
)
print(dashboard.text)
Ejemplo 2: Procesamiento de múltiples solicitudes
import requests
from http.cookiejar import LWPCookieJar
import time
jar = LWPCookieJar('session.txt')
try:
jar.load(ignore_discard=True)
except:
pass
proxy = 'http://proxy.example.com:8080'
urls = [
'https://example.com/page1',
'https://example.com/page2',
'https://example.com/page3'
]
for url in urls:
response = requests.get(
url,
cookies=jar,
proxies={'https': proxy},
timeout=10
)
print(f"{url}: {response.status_code}")
jar.save(ignore_discard=True)
time.sleep(1) # No sobrecargues el servidor
Ejemplo 3: Transmisión explícita de cookies en caso de problemas
import requests
proxy = 'http://proxy.example.com:8080'
# Si la gestión automática no funciona
cookies_dict = {
'session_id': 'abc123def456',
'user_pref': 'dark_mode'
}
headers = {
'User-Agent': 'Mozilla/5.0...',
'Cookie': '; '.join([f"{k}={v}" for k, v in cookies_dict.items()])
}
response = requests.get(
'https://example.com/api/data',
headers=headers,
proxies={'https': proxy}
)
print(response.json())
Depuración de problemas con cookies
Si las cookies no funcionan, usa estas herramientas:
| Herramienta | Propósito |
|---|---|
requests.Session |
Gestiona automáticamente cookies para todas las solicitudes en la sesión |
logging |
Habilita DEBUG para requests para ver todos los encabezados |
Fiddler / Charles |
Intercepta el tráfico y observa los encabezados Set-Cookie y Cookie |
curl -v |
Prueba lo mismo a través del proxy desde la línea de comandos |
Habilita el registro para depuración:
import logging
import requests
logging.basicConfig(level=logging.DEBUG)
# Ahora todas las solicitudes mostrarán encabezados y cookies
response = requests.get(
'https://example.com',
proxies={'https': 'http://proxy.example.com:8080'}
)
Verifica que el proxy no bloquee cookies:
curl -v -x http://proxy.example.com:8080 https://example.com
# Observa los encabezados:
# Set-Cookie: ... (deben estar presentes)
# Cookie: ... (deben enviarse en la siguiente solicitud)
Consejo: Si usas proxies residenciales, recuerda que pueden rotar IP entre solicitudes. Asegúrate de que tu lógica de manejo de cookies lo tenga en cuenta — algunos servidores rechazan solicitudes de diferentes IP en la misma sesión.
Resumen
Los problemas con cookies al trabajar a través de proxy se resuelven con la configuración correcta:
- Usa cookie jar para gestión automática de cookies
- Guarda cookies entre solicitudes en un archivo
- Verifica la vinculación de dominio y atributos Path
- Asegúrate del soporte HTTPS del proxy
- Usa depuración para identificar problemas
Para tareas de automatización y scraping donde se requiere un funcionamiento confiable con sesiones a través de proxy, los proxies residenciales con soporte HTTPS y gestión de cookies son adecuados. Comienza con un cookie jar simple y pasa a esquemas más complejos solo si es necesario.