Cómo acelerar llamadas a una API con requests.Session
Hacer muchas llamadas a una API con requests.get() abre y cierra una conexión cada vez, desperdiciando tiempo en handshakes TCP y TLS. Con el objeto requests.Session reutilizas la misma conexión y defines cabeceras y autenticación una sola vez, dejando tu código más rápido y más limpio. La diferencia se nota sobre todo cuando repites llamadas al mismo servidor dentro de un bucle o en un servicio que se ejecuta a todas horas.
Requisitos previos
- Python 3.9 o superior instalado.
- La biblioteca
requests(instálala conpip install requests). - Una API REST para probar — usamos la pública
https://httpbin.org, que devuelve JSON. - Saber hacer una petición GET sencilla.
Paso 1: El coste de repetir requests.get()
Cada vez que llamas a requests.get(), la biblioteca crea una nueva conexión con el servidor, negocia TLS (en HTTPS) y solo entonces envía la petición. Una o dos veces no se nota; cientos de veces, el coste se acumula. Este es el patrón habitual, pero poco eficiente:
import requests
for user_id in range(1, 6):
r = requests.get(f"https://httpbin.org/anything/{user_id}")
print(r.status_code)
Para una sola petición esto es perfectamente aceptable — el problema aparece cuando repites la petición muchas veces. En cada vuelta del bucle se abre y se cierra una conexión. Funciona, pero se vuelve lento a medida que crece el número de llamadas a la API.
Paso 2: Crear una Session y reutilizar la conexión
El objeto requests.Session mantiene un conjunto de conexiones abiertas (keep-alive). Al usar la misma sesión para varias peticiones al mismo servidor, evitas repetir los handshakes y ganas velocidad casi gratis:
import requests
with requests.Session() as session:
for user_id in range(1, 6):
r = session.get(f"https://httpbin.org/anything/{user_id}")
print(r.status_code)
El bloque with garantiza que la sesión se cierra al final y libera las conexiones. Para el mismo servidor, este código suele ser más rápido que el del Paso 1, sin ninguna configuración extra.
Regla práctica: crea una sesión por servicio externo y reutilízala en toda la aplicación, en lugar de llamar a requests.get() suelto una y otra vez.
Paso 3: Definir cabeceras y autenticación una sola vez
Con una sesión, defines cabeceras, tokens y parámetros comunes una sola vez, y todas las peticiones los heredan. Así evitas repetir código y reduces errores:
session = requests.Session()
session.headers.update({
"Authorization": "Bearer YOUR_TOKEN",
"Accept": "application/json",
})
# Cada peticion hereda las cabeceras definidas arriba
r = session.get("https://httpbin.org/headers")
print(r.json())
El mismo principio se aplica a session.params, para parámetros de query fijos, y a session.auth, para autenticación básica. Defines una vez, usas en todas partes. Si algún día necesitas cambiar el token, lo cambias en un único sitio.
Paso 4: Ajustar el pool de conexiones
Por defecto, requests mantiene un pool pequeño de conexiones. Si haces muchas peticiones al mismo servidor, puedes aumentar ese pool montando un HTTPAdapter en la sesión:
from requests.adapters import HTTPAdapter
adapter = HTTPAdapter(pool_connections=10, pool_maxsize=20)
session.mount("https://", adapter)
session.mount("http://", adapter)
pool_maxsize controla cuántas conexiones mantiene el pool por host. Un valor más alto ayuda sobre todo cuando combinas la sesión con threads para hacer llamadas en paralelo. Por defecto pool_maxsize es 10; auméntalo solo si realmente haces llamadas concurrentes.
Verificar el resultado
Para confirmar que la conexión se está reutilizando de verdad, activa el registro de debug. Con logging en el nivel DEBUG, urllib3 muestra cuándo abre una conexión nueva:
import logging
logging.basicConfig(level=logging.DEBUG)
with requests.Session() as session:
for _ in range(3):
session.get("https://httpbin.org/get")
Deberías ver un único mensaje "Starting new HTTPS connection" y, a continuación, las siguientes peticiones reutilizándola — en lugar de una conexión nueva por petición. Esa es la prueba de que la sesión funciona. Si sigues viendo varios mensajes de conexión nueva, comprueba que estás usando session.get() y no requests.get().
Conclusión
Has pasado del requests.get() repetido a una requests.Session que reutiliza conexiones, centraliza cabeceras y permite ajustar el pool — más velocidad y menos código duplicado. El siguiente paso natural es añadir a la sesión retries automáticos y timeouts, para que tus llamadas a la API también sean robustas. ¿Ya has medido cuánto tiempo ahorrarías al reutilizar la conexión en la API que usas hoy?