A biblioteca requests é uma das ferramentas mais populares e poderosas para realizar requisições HTTP em Python. Ela abstrai a complexidade do protocolo HTTP, oferecendo uma API simples e intuitiva para enviar e receber dados de serviços web. Nesta aula, vamos explorar os principais conceitos e práticas para usar requests de forma eficiente, cobrindo desde operações básicas até o tratamento de erros.

Dominar o uso de requests é essencial para qualquer desenvolvedor que precise interagir com APIs, consumir serviços web ou automatizar tarefas que envolvam comunicação via HTTP. Ao final desta aula, você estará apto a fazer requisições GET e POST, configurar headers, manipular respostas JSON e lidar com erros de forma profissional.

GET e POST

Os métodos HTTP GET e POST são os mais comuns. O método GET é usado para recuperar dados de um servidor, enquanto o POST é usado para enviar dados para criar ou atualizar recursos. A biblioteca requests oferece funções simples para cada um: get() e post().

Para fazer uma requisição GET, basta chamar requests.get(url). A resposta é um objeto Response que contém o status code, o conteúdo e outras informações. Já para o POST, usamos requests.post(url, data={...}) ou json={...}, dependendo do tipo de dado que queremos enviar.

import requests

# GET
resposta = requests.get('https://api.github.com/users/octocat')
print(resposta.status_code)
print(resposta.json())

# POST
payload = {'nome': 'João', 'idade': 30}
resposta = requests.post('https://httpbin.org/post', data=payload)
print(resposta.status_code)
print(resposta.text)

No exemplo acima, usamos o endpoint público do GitHub para obter informações de um usuário e o serviço httpbin.org para testar o POST. Observe que o POST envia dados no corpo da requisição, que podem ser codificados como formulário (data) ou como JSON (json).

Headers

Cabeçalhos HTTP (headers) são metadados que acompanham a requisição ou resposta. Eles podem conter informações como tipo de conteúdo, autenticação, user-agent, entre outras. Em requests, podemos enviar headers personalizados usando o parâmetro headers.

Muitas APIs exigem que você envie um token de autenticação no header Authorization ou que especifique o tipo de conteúdo esperado. Além disso, é comum definir um User-Agent para identificar seu cliente.

import requests

headers = {
    'User-Agent': 'MeuApp/1.0',
    'Authorization': 'Bearer meu_token_aqui'
}

resposta = requests.get('https://api.github.com/user', headers=headers)
print(resposta.status_code)
print(resposta.json())

No exemplo, enviamos um header de autorização (Bearer token) e um User-Agent personalizado. A API do GitHub, por exemplo, retornará 401 se o token for inválido. Sempre consulte a documentação da API para saber quais headers são necessários.

JSON

JSON (JavaScript Object Notation) é o formato de troca de dados mais comum em APIs REST. A biblioteca requests facilita o trabalho com JSON: ao receber uma resposta, podemos chamar resposta.json() para converter o conteúdo em um dicionário Python. Para enviar dados JSON, usamos o parâmetro json no POST (ou em outros métodos).

É importante lembrar que a resposta deve ter o header Content-Type: application/json para que json() funcione. Caso contrário, pode ser necessário usar resposta.text e fazer o parse manualmente com json.loads().

import requests

# Enviando JSON
payload = {
    'titulo': 'Aprendendo Python',
    'autor': 'Maria',
    'ano': 2025
}
resposta = requests.post('https://httpbin.org/post', json=payload)
print(resposta.status_code)
print(resposta.json()['json'])  # o servidor ecoa o JSON enviado

# Recebendo JSON
resposta = requests.get('https://jsonplaceholder.typicode.com/posts/1')
post = resposta.json()
print(post['title'])

No exemplo, usamos o serviço httpbin para ecoar o JSON enviado e o JSONPlaceholder para obter um post. O método json() converte a resposta em um dicionário, permitindo acesso fácil aos campos.

Tratamento de erros

Ao trabalhar com requisições HTTP, erros podem ocorrer por diversos motivos: rede indisponível, servidor fora do ar, URL inválida, status code de erro (4xx ou 5xx), entre outros. A biblioteca requests fornece várias ferramentas para tratar esses erros de forma elegante.

Podemos verificar o status code da resposta e usar o método raise_for_status(), que lança uma exceção se o status indicar erro. Além disso, podemos capturar exceções específicas como requests.exceptions.ConnectionError e requests.exceptions.Timeout.

import requests

try:
    resposta = requests.get('https://api.github.com/invalid-endpoint', timeout=5)
    resposta.raise_for_status()  # lança exceção para status >= 400
    print(resposta.json())
except requests.exceptions.Timeout:
    print('A requisição excedeu o tempo limite.')
except requests.exceptions.ConnectionError:
    print('Falha de conexão.')
except requests.exceptions.HTTPError as err:
    print(f'Erro HTTP: {err}')
except requests.exceptions.RequestException as e:
    print(f'Erro inesperado: {e}')

No exemplo, usamos um endpoint inválido para forçar um erro 404. O raise_for_status() lança uma exceção que é capturada. Também definimos um timeout de 5 segundos para evitar que a requisição fique pendente indefinidamente.

Boas práticas

Ao usar requests, é recomendável criar uma sessão (requests.Session()) para reutilizar a conexão e manter cookies entre requisições. Além disso, sempre defina um timeout para evitar travamentos. Use with para garantir o fechamento da resposta quando possível.

import requests

with requests.Session() as sessao:
    sessao.headers.update({'User-Agent': 'MeuApp/1.0'})
    resposta = sessao.get('https://httpbin.org/headers', timeout=5)
    print(resposta.json())

Essas práticas tornam seu código mais robusto e eficiente.

Exercícios

  1. Faça uma requisição GET para https://jsonplaceholder.typicode.com/users e exiba o nome de cada usuário.
  2. ✓ Resposta:
    import requests
    
    resposta = requests.get('https://jsonplaceholder.typicode.com/users')
    if resposta.status_code == 200:
        usuarios = resposta.json()
        for usuario in usuarios:
            print(usuario['name'])
    else:
        print('Erro na requisição')
    
  3. Envie um POST para https://httpbin.org/post com os dados {'curso': 'Python', 'aula': 84} usando JSON e imprima o JSON de resposta.
  4. ✓ Resposta:
    import requests
    
    payload = {'curso': 'Python', 'aula': 84}
    resposta = requests.post('https://httpbin.org/post', json=payload)
    print(resposta.json())
    
  5. Faça uma requisição GET para https://api.github.com/repos/octocat/Hello-World com um header Accept: application/vnd.github.v3+json e imprima o nome do repositório e a descrição.
  6. ✓ Resposta:
    import requests
    
    headers = {'Accept': 'application/vnd.github.v3+json'}
    resposta = requests.get('https://api.github.com/repos/octocat/Hello-World', headers=headers)
    if resposta.status_code == 200:
        repo = resposta.json()
        print('Nome:', repo['name'])
        print('Descrição:', repo['description'])
    else:
        print('Erro:', resposta.status_code)
    
  7. Escreva um script que tente acessar https://httpbin.org/status/404 e trate o erro usando raise_for_status(), capturando a exceção HTTPError.
  8. ✓ Resposta:
    import requests
    
    try:
        resposta = requests.get('https://httpbin.org/status/404')
        resposta.raise_for_status()
        print('Sucesso')
    except requests.exceptions.HTTPError as err:
        print(f'Erro HTTP: {err}')
    
  9. Use uma sessão para fazer duas requisições: primeiro um GET em https://httpbin.org/cookies/set?nome=Joao e depois um GET em https://httpbin.org/cookies para verificar se o cookie foi mantido.
  10. ✓ Resposta:
    import requests
    
    with requests.Session() as sessao:
        # Define o cookie
        resposta = sessao.get('https://httpbin.org/cookies/set?nome=Joao')
        print(resposta.status_code)
        # Verifica o cookie
        resposta = sessao.get('https://httpbin.org/cookies')
        print(resposta.json())
    

Referências