HTTP com requests e httpx
1. Introdução às bibliotecas HTTP em Python
O protocolo HTTP é a espinha dorsal da comunicação na web moderna. Seja consumindo APIs REST, fazendo web scraping ou integrando serviços, dominar requisições HTTP é essencial para qualquer desenvolvedor Python. Duas bibliotecas se destacam nesse cenário: a clássica requests e a moderna httpx.
requests é a biblioteca mais popular para HTTP em Python, conhecida por sua API elegante e intuitiva. Já httpx surge como uma alternativa moderna, trazendo suporte nativo a async/await e mantendo compatibilidade com a interface do requests.
Instalação
# requests
pip install requests
# httpx
pip install httpx
Primeiros passos com ambas:
import requests
import httpx
# requests síncrono
response = requests.get('https://httpbin.org/get')
print(response.status_code)
# httpx síncrono
with httpx.Client() as client:
response = client.get('https://httpbin.org/get')
print(response.status_code)
2. Requisições básicas com requests
Métodos HTTP
import requests
# GET
response = requests.get('https://api.github.com/users/python')
print(response.json()['login'])
# POST
payload = {'title': 'Python', 'body': 'Linguagem poderosa'}
response = requests.post('https://jsonplaceholder.typicode.com/posts', json=payload)
print(response.status_code) # 201 Created
# PUT
response = requests.put('https://jsonplaceholder.typicode.com/posts/1', json=payload)
# DELETE
response = requests.delete('https://jsonplaceholder.typicode.com/posts/1')
Parâmetros e cabeçalhos
# Parâmetros de URL
params = {'q': 'python', 'sort': 'stars', 'order': 'desc'}
response = requests.get('https://api.github.com/search/repositories', params=params)
print(response.url) # URL com parâmetros
# Cabeçalhos personalizados
headers = {
'User-Agent': 'MeuApp/1.0',
'Accept': 'application/json',
'Authorization': 'Bearer meu-token-aqui'
}
response = requests.get('https://api.github.com/user', headers=headers)
Tratamento de respostas
response = requests.get('https://httpbin.org/encoding/utf8')
print(response.status_code) # 200
print(response.ok) # True
print(response.headers['Content-Type'])
print(response.encoding) # utf-8
print(response.text) # conteúdo como string
# Verificar encoding automaticamente
response.encoding = response.apparent_encoding
3. Requisições avançadas com requests
Sessões e cookies
# Sessão mantém cookies entre requisições
session = requests.Session()
# Login
login_data = {'username': 'admin', 'password': '1234'}
session.post('https://httpbin.org/post', data=login_data)
# Próximas requisições mantêm o cookie de sessão
response = session.get('https://httpbin.org/cookies')
print(response.json())
Upload e download de arquivos
# Download
response = requests.get('https://httpbin.org/image/png', stream=True)
with open('imagem.png', 'wb') as f:
for chunk in response.iter_content(chunk_size=8192):
f.write(chunk)
# Upload
files = {'file': ('relatorio.pdf', open('relatorio.pdf', 'rb'), 'application/pdf')}
response = requests.post('https://httpbin.org/post', files=files)
Timeouts e redirecionamentos
# Timeout (segundos)
try:
response = requests.get('https://httpbin.org/delay/5', timeout=3)
except requests.Timeout:
print("Requisição excedeu o tempo limite")
# Controle de redirecionamentos
response = requests.get('https://httpbin.org/redirect/3', allow_redirects=True)
print(response.history) # Lista de respostas intermediárias
# Desabilitar redirecionamentos
response = requests.get('https://httpbin.org/redirect/3', allow_redirects=False)
print(response.status_code) # 302
4. httpx: a alternativa moderna
Diferenças fundamentais
import httpx
# httpx usa Client por padrão (recomendado)
with httpx.Client() as client:
response = client.get('https://httpbin.org/get')
# Suporte nativo a HTTP/2
client = httpx.Client(http2=True)
response = client.get('https://http2.pro/api/v1')
print(response.http_version) # HTTP/2
Interface assíncrona
import asyncio
import httpx
async def fetch_data(url):
async with httpx.AsyncClient() as client:
response = await client.get(url)
return response.json()
async def main():
# Requisições concorrentes
urls = [
'https://jsonplaceholder.typicode.com/posts/1',
'https://jsonplaceholder.typicode.com/posts/2',
'https://jsonplaceholder.typicode.com/posts/3'
]
tasks = [fetch_data(url) for url in urls]
results = await asyncio.gather(*tasks)
for result in results:
print(result['title'])
# Executar
asyncio.run(main())
Interface síncrona e assíncrona no mesmo pacote
import httpx
# Síncrono
def sync_example():
with httpx.Client() as client:
response = client.get('https://httpbin.org/get')
return response.json()
# Assíncrono (mesmo pacote)
async def async_example():
async with httpx.AsyncClient() as client:
response = await client.get('https://httpbin.org/get')
return response.json()
5. Trabalhando com autenticação e segurança
Autenticação básica e Bearer token
import requests
from requests.auth import HTTPBasicAuth
# Autenticação básica
response = requests.get('https://httpbin.org/basic-auth/user/pass',
auth=HTTPBasicAuth('user', 'pass'))
# Bearer token
headers = {'Authorization': 'Bearer seu-token-aqui'}
response = requests.get('https://api.github.com/user', headers=headers)
# httpx também suporta ambas
import httpx
auth = httpx.BasicAuth('user', 'pass')
response = httpx.get('https://httpbin.org/basic-auth/user/pass', auth=auth)
SSL/TLS e proxies
# Verificação SSL personalizada
response = requests.get('https://exemplo.com', verify='/caminho/certificado.pem')
# Desabilitar verificação (não recomendado em produção)
response = requests.get('https://exemplo.com', verify=False)
# Proxies
proxies = {
'http': 'http://10.10.1.10:3128',
'https': 'http://10.10.1.10:1080'
}
response = requests.get('https://api.github.com', proxies=proxies)
# httpx com proxy
with httpx.Client(proxies='http://10.10.1.10:3128') as client:
response = client.get('https://api.github.com')
6. Tratamento de erros e exceções
Hierarquia de exceções
import requests
from requests.exceptions import RequestException, ConnectionError, Timeout, HTTPError
try:
response = requests.get('https://httpbin.org/status/500')
response.raise_for_status() # Levanta HTTPError para 4xx/5xx
except HTTPError as e:
print(f"Erro HTTP: {e.response.status_code}")
except ConnectionError:
print("Falha na conexão")
except Timeout:
print("Timeout excedido")
except RequestException as e:
print(f"Erro na requisição: {e}")
# httpx tem hierarquia similar
import httpx
try:
with httpx.Client() as client:
response = client.get('https://httpbin.org/status/500')
response.raise_for_status()
except httpx.HTTPStatusError as e:
print(f"Erro HTTP: {e.response.status_code}")
except httpx.ConnectError:
print("Falha na conexão")
Retry automático
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
session = requests.Session()
retry_strategy = Retry(
total=3,
backoff_factor=1,
status_forcelist=[500, 502, 503, 504],
)
adapter = HTTPAdapter(max_retries=retry_strategy)
session.mount('http://', adapter)
session.mount('https://', adapter)
response = session.get('https://httpbin.org/status/500')
Logging e debugging
import logging
import requests
# Habilitar logging detalhado
logging.basicConfig(level=logging.DEBUG)
requests_log = logging.getLogger("urllib3")
requests_log.setLevel(logging.DEBUG)
# httpx oferece eventos de debug
import httpx
def log_request(request):
print(f"Requisição: {request.method} {request.url}")
def log_response(response):
print(f"Resposta: {response.status_code}")
with httpx.Client(event_hooks={'request': [log_request], 'response': [log_response]}) as client:
response = client.get('https://httpbin.org/get')
7. Casos de uso práticos
Consumo de API REST (JSONPlaceholder)
import requests
import json
# Criar um post
novo_post = {
'title': 'Python HTTP',
'body': 'Trabalhando com requests e httpx',
'userId': 1
}
response = requests.post('https://jsonplaceholder.typicode.com/posts', json=novo_post)
post_criado = response.json()
print(f"Post criado: ID {post_criado['id']}")
# Listar todos os posts do usuário
response = requests.get('https://jsonplaceholder.typicode.com/posts', params={'userId': 1})
posts = response.json()
print(f"Total de posts: {len(posts)}")
Upload de múltiplos arquivos com progresso
import requests
from tqdm import tqdm
def upload_com_progresso(url, arquivos):
total_size = sum(len(open(f, 'rb').read()) for f in arquivos)
with tqdm(total=total_size, unit='B', unit_scale=True, desc="Upload") as pbar:
def callback(monitor):
pbar.update(monitor.bytes_sent - pbar.n)
files = [('files', open(f, 'rb')) for f in arquivos]
response = requests.post(url, files=files, hooks={'response': [callback]})
return response
# Uso
arquivos = ['foto1.jpg', 'foto2.jpg', 'foto3.jpg']
response = upload_com_progresso('https://httpbin.org/post', arquivos)
Comparação de desempenho: requests vs httpx
import time
import asyncio
import requests
import httpx
# Teste com requests síncrono
def test_requests_sync(urls):
start = time.time()
for url in urls:
response = requests.get(url)
return time.time() - start
# Teste com httpx síncrono
def test_httpx_sync(urls):
start = time.time()
with httpx.Client() as client:
for url in urls:
response = client.get(url)
return time.time() - start
# Teste com httpx assíncrono
async def test_httpx_async(urls):
start = time.time()
async with httpx.AsyncClient() as client:
tasks = [client.get(url) for url in urls]
await asyncio.gather(*tasks)
return time.time() - start
# Executar testes
urls = ['https://httpbin.org/get'] * 10
print(f"requests síncrono: {test_requests_sync(urls):.2f}s")
print(f"httpx síncrono: {test_httpx_sync(urls):.2f}s")
async def run_async():
result = await test_httpx_async(urls)
print(f"httpx assíncrono: {result:.2f}s")
asyncio.run(run_async())
8. Conclusão
Tanto requests quanto httpx são bibliotecas excelentes para trabalhar com HTTP em Python. O requests continua sendo a escolha ideal para projetos que priorizam simplicidade e maturidade, enquanto o httpx oferece vantagens significativas em cenários que exigem alto desempenho com I/O concorrente ou suporte a HTTP/2. A escolha entre elas depende do seu caso de uso específico: para scripts simples, requests é imbatível; para aplicações modernas que precisam de performance e assincronicidade, httpx é a melhor opção.
Referências
- Documentação oficial do requests — Guia completo da biblioteca requests com exemplos detalhados
- Documentação oficial do httpx — Referência completa para a biblioteca httpx, incluindo async/await
- HTTP Status Codes - MDN Web Docs — Guia de referência sobre códigos de status HTTP
- Real Python: Python's Requests Library Guide — Tutorial prático sobre requests com exemplos do mundo real
- TestDriven.io: Async Python with httpx — Artigo técnico sobre uso assíncrono do httpx em Python
- JSONPlaceholder API — API REST gratuita para testes e prototipação