Gerenciamento Avançado de Sessões, Cookies e Cabeçalhos HTTP em Python

Manipulação de Cabeçalhos HTTP (Headers)

Ao utilizar a biblioteca requests do Python, é fundamental compreender como interagir com os cabeçalhos das requisições. Ao instanciar uma sessão, podemos inspecionar e modificar as configurações padrão de forma centralizada.


import requests

# Inicializando a sessão
http_client = requests.Session()

# Inspecionando cabeçalhos padrão
print(http_client.headers)
# Saída esperada: {'User-Agent': 'python-requests/2.x.x', 'Accept-Encoding': 'gzip, deflate', ...}

# Iterando sobre as chaves e valores
for header_name in http_client.headers.keys():
    print(f"Chave: {header_name}")

# Removendo e atualizando cabeçalhos
http_client.headers.pop('User-Agent', None)
custom_headers = {
    'Origin': 'https://api.exemplo.com',
    'Host': 'api.exemplo.com',
    'Referer': 'https://exemplo.com/',
    'User-Agent': 'CustomApp/1.0'
}
http_client.headers.update(custom_headers)

É importante notar que atualizar os cabeçalhos diretamente no objeto de sessão torna as alterações permanentes para todas as requisições subsequentes. Em contrapartida, passar o parâmetro headers no método de requisição afeta apenas aquela chamada específica.

Extração e Processamento de Cookies

A obtenção de cookies pode ser feita de várias formas, dependendo de como o servidor os retorna. O objeto de sessão armazena automaticamente os cookies, mas em alguns cenários, é necessário processar o cabeçalho Set-Cookie manualmente.


import json
import requests

class AuthManager:
    def __init__(self):
        self._session = requests.Session()
        self._parsed_cookies = {}
        self._base_headers = {'User-Agent': 'Mozilla/5.0'}

    def perform_login(self, endpoint, credentials):
        response = self._session.post(
            endpoint,
            data=json.dumps(credentials),
            headers=self._base_headers
        )

        # Tentativa de obtenção via cookie jar da sessão
        jar_cookies = self._session.cookies.get_dict()

        # Fallback: parsing manual do cabeçalho Set-Cookie
        set_cookie_header = response.headers.get("Set-Cookie", "")
        if set_cookie_header and not jar_cookies:
            for cookie_part in set_cookie_header.split(";"):
                if "=" in cookie_part:
                    k, v = cookie_part.strip().split("=", 1)
                    self._parsed_cookies[k] = v
            return self._parsed_cookies

        return jar_cookies

# Uso
manager = AuthManager()
user_cookies = manager.perform_login(
    "https://api.exemplo.com/auth",
    {"user": "admin", "pass": "hash_senha"}
)
print(user_cookies)

Após extrair os cookies, frequentemente precisamos convertê-los para formatos específicos, como dicionários ou strings formatadas, para utilizá-los em requisições subsequentes.


import requests
from requests.utils import dict_from_cookiejar

def fetch_and_format_cookies(login_url, payload):
    resp = requests.post(login_url, json=payload)

    # Método A: Converter CookieJar para dicionário
    cookie_dict = dict_from_cookiejar(resp.cookies)

    # Método B: Concatenar em formato de string HTTP
    cookie_str = "; ".join([f"{k}={v}" for k, v in resp.cookies.items()])

    return cookie_dict, cookie_str

# Utilizando os cookies formatados
def access_protected_resource(data_url, cookies_dict, cookies_string):
    # Uso via parâmetro cookies (aceita dict)
    resp1 = requests.get(data_url, cookies=cookies_dict)

    # Uso via cabeçalho manual
    headers = {"Cookie": cookies_string}
    resp2 = requests.get(data_url, headers=headers)

    return resp1.text, resp2.text

Persistência de Estado e Reutilização de Sessões

Chamadas diretas com requests.get() ou requests.post() não mantêm o estado entre requisições. Para fluxos que exigem autenticação prévia, como operações financeiras ou consultas protegidas, é necessário gerenciar a sessão de forma adequada.


import logging
import requests

class ApiSessionManager:
    def __init__(self):
        self._http_session = requests.Session()

    def execute(self, method, url, payload=None, timeout=15):
        method = method.lower()
        logging.info(f"Executando {method.upper()} em {url}")

        if method == 'get':
            result = self._http_session.get(url, params=payload, timeout=timeout)
        elif method == 'post':
            result = self._http_session.post(url, json=payload, timeout=timeout)
        else:
            raise ValueError("Método HTTP não suportado")

        return result.json()

# Fluxo de autenticação e ação protegida
if __name__ == "__main__":
    api = ApiSessionManager()

    # 1. Login (a sessão armazena o cookie automaticamente)
    api.execute('post', 'https://api.exemplo.com/v1/login', {'phone': '123456789', 'pwd': 'secret'})

    # 2. Ação protegida (o cookie é enviado automaticamente pela sessão)
    recharge_response = api.execute('post', 'https://api.exemplo.com/v1/recharge', {'amount': 50})
    print(recharge_response)

Estratégias de Passagem de Sessão em Testes de API

Ao escrever testes de integração ou automação de APIs, é comum precisar passar o contexto de autenticação entre diferentes funções. Existem duas abordagens principais para lidar com esse cenário.

Abordagem 1: Extração e Injeção Manual de Cookies

Nesta abordagem, extraímos o dicionário de cookies da resposta de login e o injetamos explicitamente em cada requisição subsequente. A principal desvantagem é a verbosidade e a necessidade de re-executar o login ou gerenciar o token manualmente em cada chamada de função.


import json
import requests

def authenticate_user(base_url):
    headers = {'Content-Type': 'application/json'}
    body = json.dumps({"username": "tester", "password": "12345"})
    response = requests.post(f"{base_url}/login", data=body, headers=headers)
    return response.cookies.get_dict()

def fetch_user_profile(base_url, auth_cookies):
    headers = {'Content-Type': 'application/json'}
    body = json.dumps({"page": 1, "limit": 10})
    # Injeção manual dos cookies
    response = requests.post(f"{base_url}/profile", data=body, headers=headers, cookies=auth_cookies)
    return response.json()

Abordagem 2: Compartilhamento do Objeto Session

A abordagem mais eficiente consiste em instanciar um objeto requests.Session() e compartilhá-lo entre as funções. Isso não apenas gerencia os cookies autoamticamente, mas também reutiliza a conexão TCP subjacente (Keep-Alive), resultando em ganhos significativos de performance ao enviar múltiplas requisições para o mesmo host.


import json
import requests

def authenticate_session(base_url, session_obj):
    headers = {'Content-Type': 'application/json'}
    body = json.dumps({"username": "tester", "password": "12345"})
    response = session_obj.post(f"{base_url}/login", data=body, headers=headers)
    return session_obj # Retorna a sessão já autenticada

def fetch_user_profile_with_session(base_url, session_obj):
    headers = {'Content-Type': 'application/json'}
    body = json.dumps({"page": 1, "limit": 10})
    # A sessão cuida dos cookies automaticamente
    response = session_obj.post(f"{base_url}/profile", data=body, headers=headers)
    return response.json()

Tags: Python Requests http-session cookies API-Testing

Publicado em 7-6 20:15