Requisições HTTP Eficientes com a Biblioteca Requests em Python

A biblioteca requests é uma ferramenta fundamental no ecossistema Python para a execução de requisições HTTP. Projetada para ser acessível e intuitiva, ela abstrai as complexidades subjacentes do protocolo HTTP, permitnido que desenvolvedores interajam com serviços web e APIs de forma simplificada e robusta. A requests suporta o padrão HTTP/1.1 e oferece funcionalidades como gerenciamento de sessões, persistência de conexão e manipulação de cookies.

Instalação

Para começar a utilizar a requests, instale-a através do gerenciador de pacotes pip:

pip install requests

Realizando Requisições Básicas

A maneira mais direta de enviar uma requisição é utilizando as funções dedicadas a cada método HTTP, como requests.get() para obter dados ou requests.post() para enviar dados.

import requests

# Exemplo de requisição GET
url_get = 'https://jsonplaceholder.typicode.com/posts/1'
resposta_get = requests.get(url_get)
print(f"Status GET: {resposta_get.status_code}")

# Exemplo de requisição POST
url_post = 'https://jsonplaceholder.typicode.com/posts'
dados_post = {'titulo': 'Meu Novo Post', 'corpo': 'Conteúdo da postagem.', 'userId': 1}
resposta_post = requests.post(url_post, json=dados_post) # Usando json= para dict -> JSON
print(f"Status POST: {resposta_post.status_code}")
print(resposta_post.json()) # Imprime o JSON retornado

A biblioteca também suporta outros métodos HTTP, incluindo PUT, DELETE, HEAD, PATCH e OPTIONS.

Parâmetros de Requisição

Para requisições GET, os parâmetros de consulta (query string) podem ser especificdaos com o argumento params, que aceita um dicionário:

parametros_get = {'chave_a': 'valor_a', 'chave_b': 'valor_b'}
url_com_parametros = 'https://httpbin.org/get'
resposta_parametros = requests.get(url_com_parametros, params=parametros_get)
print(f"URL completa: {resposta_parametros.url}") # Exibe a URL com os parâmetros codificados

Para requisições POST que enviam dados de formulário (application/x-www-form-urlencoded), use o argumento data:

dados_formulario = {'nome_usuario': 'exemplo', 'senha': '123'}
url_post_form = "https://httpbin.org/post"
resposta_form = requests.post(url_post_form, data=dados_formulario)
print(resposta_form.json())

Configurando Cabeçalhos (Headers)

Cabeçalhos HTTP personalizados podem ser enviados em um dicionário através do argumento headers:

headers_personalizados = {
    'User-Agent': 'MinhaAplicacaoPython/1.0',
    'X-Custom-Header': 'ValorCustomizado'
}
url_headers = 'https://httpbin.org/headers'
resposta_headers = requests.get(url_headers, headers=headers_personalizados)
print(resposta_headers.json())

Envio e Recebimento de JSON

A requests facilita o trabalho com JSON. Ao fornecer um dicionário para o argumento json em requisições POST, PUT, etc., a biblioteca automaticamente serializa o dicionário para JSON e define o cabeçalho Content-Type como application/json.

dados_json_envio = {
    'produto_id': 123,
    'nome_produto': 'Exemplo Item',
    'quantidade': 5
}
url_json = 'https://httpbin.org/post'
resposta_json_envio = requests.post(url_json, json=dados_json_envio)
print(f"JSON enviado e resposta: {resposta_json_envio.json()['json']}")

Para processar respostas que contêm JSON, use o método .json() do objeto de resposta, que analisa a string JSON e retorna um objeto Python (geralmente um dicionário ou lista).

url_api_dados = 'https://jsonplaceholder.typicode.com/todos/1'
resposta_api = requests.get(url_api_dados)
if resposta_api.status_code == 200:
    dados_recebidos = resposta_api.json()
    print(f"ID do To-Do: {dados_recebidos['id']}, Título: {dados_recebidos['title']}")

O conteúdo bruto da resposta pode ser acessado como texto Unicode via resposta.text ou como bytes via resposta.content.

Tratamento de Erros

É uma boa prática verificar o status da resposta. O método .raise_for_status() do objeto de resposta é útil para levantar uma exceção HTTPError para códigos de status 4xx (erros do cliente) ou 5xx (erros do servdior).

try:
    url_erro = 'https://httpbin.org/status/404' # URL que retorna erro 404
    resposta_erro = requests.get(url_erro)
    resposta_erro.raise_for_status() # Lança HTTPError para 4xx/5xx
    print("Requisição bem-sucedida!")
except requests.exceptions.HTTPError as e:
    print(f"Erro HTTP detectado: {e}")
except requests.exceptions.ConnectionError as e:
    print(f"Erro de conexão: {e}")
except requests.exceptions.Timeout as e:
    print(f"Timeout na requisição: {e}")
except requests.exceptions.RequestException as e:
    print(f"Um erro inesperado ocorreu: {e}")

Configurando Tempos Limite (Timeouts)

Para evitar que suas requisições fiquem penduradas indefinidamente, você pode definir um tempo limite em segundos para a conexão e para a leitura da resposta. O argumento timeout pode ser um único valor (para ambos) ou uma tupla (connect_timeout, read_timeout).

try:
    url_lenta = 'https://httpbin.org/delay/3' # Simula um atraso de 3 segundos
    # Timeout de 1 segundo para a conexão e 2 segundos para a leitura
    resposta_timeout = requests.get(url_lenta, timeout=(1, 2))
    print("Requisição concluída antes do timeout.")
except requests.exceptions.Timeout:
    print("A requisição excedeu o tempo limite especificado.")
except requests.exceptions.RequestException as e:
    print(f"Ocorreu um erro na requisição: {e}")

Utilizando Objetos de Sessão

Para interações mais complexas com um mesmo host, onde é necessário manter cookies, cabeçalhos ou outros parâmetros comuns entre várias requisições, os objetos de sessão (requests.Session) são ideais. Eles permitem a persistência de certas propriedades ao longo de múltiplas requisições, otimizando o desempenho e simplificando o código.

with requests.Session() as sessao_api:
    # Cabeçalhos padrão para todas as requisições desta sessão
    sessao_api.headers.update({'Autorizacao': 'Bearer token_secreto_aqui'})
    sessao_api.headers.update({'Accept': 'application/json'})

    # Primeira requisição com cabeçalhos da sessão
    resp_1 = sessao_api.get('https://httpbin.org/headers')
    print(f"Primeira resposta (headers): {resp_1.json()['headers']}")

    # Segunda requisição, também usará os cabeçalhos definidos na sessão
    resp_2 = sessao_api.post('https://httpbin.org/post', json={'item': 'teste'})
    print(f"Segunda resposta (headers): {resp_2.json()['headers']}")

    # Se um cookie fosse definido em uma resposta, ele seria enviado automaticamente na próxima requisição da sessão.
    # Exemplo: resp_login = sessao_api.post('https://api.example.com/login', data={'user':'a', 'pass':'b'})
    # resp_perfil = sessao_api.get('https://api.example.com/profile') # Enviaria o cookie de login

Autenticação

A biblioteca requests oferece suporte a vários métodos de autenticação. A autenticação HTTP Básica é implementada facilmente usando uma tupla (username, password) no argumento auth, ou utilizando a classe HTTPBasicAuth.

from requests.auth import HTTPBasicAuth

# Usando tupla para autenticação básica
url_auth = 'https://httpbin.org/basic-auth/user/pass'
resposta_auth_tupla = requests.get(url_auth, auth=('user', 'pass'))
print(f"Autenticação tupla: {resposta_auth_tupla.status_code}")

# Usando objeto HTTPBasicAuth para maior clareza ou complexidade
auth_obj = HTTPBasicAuth('admin', 'segredo')
resposta_auth_obj = requests.get('https://httpbin.org/basic-auth/admin/segredo', auth=auth_obj)
print(f"Autenticação objeto: {resposta_auth_obj.status_code}")

Verificação de Certificados SSL

Por padrão, a requests valida os certificados SSL para requisições HTTPS, o que é crucial para a segurança. Se a verificação falhar, uma exceção SSLError será lançada. Embora seja possível desativar essa verificação com verify=False, isso é fortemente desencorajado em ambientes de produção, pois expõe a aplicação a vulnerabilidades como ataques "man-in-the-middle".

try:
    # Requisição segura (padrão)
    resposta_segura = requests.get('https://www.google.com')
    print(f"Status requisição segura: {resposta_segura.status_code}")

    # Exemplo de desativação da verificação (NÃO RECOMENDADO)
    # resposta_insegura = requests.get('https://badssl.com/expired/', verify=False)
    # print(f"Status requisição insegura: {resposta_insegura.status_code}")

except requests.exceptions.SSLError as e:
    print(f"Erro de SSL: {e}. Certificado inválido ou não confiável.")
except requests.exceptions.RequestException as e:
    print(f"Ocorreu um erro geral: {e}")

Tags: Python RequestsLibrary HTTPRequests WebAPIs Networking

Publicado em 6-4 23:24 por Thomas