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}")