Como acelerar chamadas a uma API com requests.Session
Fazer muitas chamadas a uma API com requests.get() abre e fecha uma ligação de cada vez, desperdiçando tempo em handshakes TCP e TLS. Com o objeto requests.Session reutilizas a mesma ligação e defines cabeçalhos e autenticação uma só vez, deixando o teu código mais rápido e mais limpo. A diferença nota-se sobretudo quando repetes chamadas ao mesmo servidor dentro de um ciclo ou num serviço que corre a toda a hora.
Pré-requisitos
- Python 3.9 ou superior instalado.
- A biblioteca
requests(instala compip install requests). - Uma API REST para testar — usamos a pública
https://httpbin.org, que devolve JSON. - Saber fazer um pedido GET simples.
Passo 1: O custo de repetir requests.get()
Sempre que chamas requests.get(), a biblioteca cria uma nova ligação ao servidor, negoceia o TLS (em HTTPS) e só depois envia o pedido. Uma ou duas vezes não se nota; centenas de vezes, o custo acumula. Este é o padrão comum, mas pouco 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 um único pedido isto é perfeitamente aceitável — o problema surge quando repetes o pedido muitas vezes. Em cada volta do ciclo abre-se e fecha-se uma ligação. Funciona, mas torna-se lento à medida que o número de chamadas à API cresce.
Passo 2: Criar uma Session e reutilizar a ligação
O objeto requests.Session mantém um conjunto de ligações abertas (keep-alive). Ao usar a mesma sessão para vários pedidos ao mesmo servidor, evitas repetir os handshakes e ganhas velocidade quase de graça:
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)
O bloco with garante que a sessão é fechada no fim e liberta as ligações. Para o mesmo servidor, este código é tipicamente mais rápido do que o do Passo 1, sem qualquer configuração extra.
Regra prática: cria uma sessão por serviço externo e reutiliza-a em toda a aplicação, em vez de chamar requests.get() solto vezes sem conta.
Passo 3: Definir cabeçalhos e autenticação uma só vez
Com uma sessão, defines cabeçalhos, tokens e parâmetros comuns apenas uma vez, e todos os pedidos os herdam. Assim evitas repetir código e reduzes erros:
session = requests.Session()
session.headers.update({
"Authorization": "Bearer YOUR_TOKEN",
"Accept": "application/json",
})
# Todos os pedidos herdam os cabecalhos definidos acima
r = session.get("https://httpbin.org/headers")
print(r.json())
O mesmo princípio aplica-se a session.params, para parâmetros de query fixos, e a session.auth, para autenticação básica. Defines uma vez, usas em todo o lado. Se um dia precisares de mudar o token, alteras num único sítio.
Passo 4: Afinar o pool de ligações
Por omissão, o requests guarda um pool pequeno de ligações. Se fazes muitos pedidos ao mesmo servidor, podes aumentar esse pool montando um HTTPAdapter na sessão:
from requests.adapters import HTTPAdapter
adapter = HTTPAdapter(pool_connections=10, pool_maxsize=20)
session.mount("https://", adapter)
session.mount("http://", adapter)
O pool_maxsize controla quantas ligações o pool mantém para cada host. Um valor mais alto ajuda sobretudo quando combinas a sessão com threads para fazer chamadas em paralelo. Por omissão, o pool_maxsize é 10; aumenta-o apenas se realmente fizeres chamadas concorrentes.
Verificar o resultado
Para confirmar que a ligação está mesmo a ser reutilizada, ativa o registo de debug. Com o logging no nível DEBUG, o urllib3 mostra quando abre uma ligação nova:
import logging
logging.basicConfig(level=logging.DEBUG)
with requests.Session() as session:
for _ in range(3):
session.get("https://httpbin.org/get")
Deves ver uma única mensagem "Starting new HTTPS connection" e, a seguir, os pedidos seguintes a reutilizá-la — em vez de uma ligação nova por cada pedido. É a prova de que a sessão está a funcionar. Se continuares a ver várias mensagens de ligação nova, confirma que estás a usar session.get() e não requests.get().
Conclusão
Passaste do requests.get() repetido para uma requests.Session que reutiliza ligações, centraliza cabeçalhos e deixa afinar o pool — mais velocidade e menos código duplicado. O passo seguinte natural é juntar à sessão retries automáticos e timeouts, para que as chamadas à tua API fiquem também robustas. Já mediste quanto tempo ganharias ao reutilizar a ligação na API que usas hoje?