Skip to content

Biblioteca Python Requests: Guia Completo de Requisições HTTP em Python

Updated on

Fazer requisições HTTP em Python usando o módulo embutido urllib é notoriamente complexo e verboso. Você precisa codificar parâmetros manualmente, lidar com objetos de resposta com múltiplas chamadas de métodos e escrever dezenas de linhas de código boilerplate apenas para enviar uma requisição simples a uma API. Essa complexidade desacelera o desenvolvimento e torna seu código mais difícil de manter.

A biblioteca Python requests elimina essa frustração ao fornecer uma API elegante e amigável para comunicação HTTP. Seja consumindo APIs REST, fazendo web scraping, enviando arquivos ou construindo scripts de automação, a biblioteca requests torna as operações HTTP intuitivas e diretas com apenas algumas linhas de código.

Neste guia abrangente, você aprenderá desde requisições GET e POST básicas até recursos avançados como autenticação, sessões, tratamento de erros e padrões reais de integração com APIs.

📚

Instalando a Biblioteca Python Requests

A biblioteca requests não faz parte da biblioteca padrão do Python, então você precisa instalá-la separadamente usando pip:

pip install requests

Para usuários de conda:

conda install requests

Depois de instalada, você pode importá-la nos seus scripts Python:

import requests

Para verificar a instalação e checar a versão:

import requests
print(requests.__version__)

Fazendo Requisições GET com Python Requests

Requisições GET são o método HTTP mais comum, usado para recuperar dados de servidores. A biblioteca requests torna as requisições GET incrivelmente simples.

Requisição GET Básica

Veja como fazer uma requisição GET básica:

import requests
 
response = requests.get('https://api.github.com')
print(response.status_code)  # 200
print(response.text)  # Response body as string

Requisição GET com Parâmetros de Query

Em vez de construir URLs manualmente com query strings, use o parâmetro params:

import requests
 
# Method 1: Using params dictionary
params = {
    'q': 'python requests',
    'sort': 'stars',
    'order': 'desc'
}
response = requests.get('https://api.github.com/search/repositories', params=params)
 
# The URL is automatically constructed:
# https://api.github.com/search/repositories?q=python+requests&sort=stars&order=desc
 
print(response.url)  # View the constructed URL
data = response.json()  # Parse JSON response

Requisição GET com Headers Personalizados

Muitas APIs exigem headers personalizados para autenticação ou negociação de conteúdo:

import requests
 
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
    'Accept': 'application/json',
    'Accept-Language': 'en-US,en;q=0.9'
}
 
response = requests.get('https://api.example.com/data', headers=headers)
print(response.json())

Fazendo Requisições POST em Python

Requisições POST enviam dados para um servidor, comumente usadas para envios de formulários e operações de API.

Requisição POST com Dados de Formulário

Para enviar dados codificados como formulário (como envios de formulários HTML):

import requests
 
# Send form data
data = {
    'username': 'john_doe',
    'password': 'secret123',
    'remember_me': True
}
 
response = requests.post('https://example.com/login', data=data)
print(response.status_code)

Requisição POST com Payload JSON

APIs REST modernas geralmente esperam payloads JSON. A biblioteca requests lida com a serialização JSON automaticamente:

import requests
 
# Method 1: Using json parameter (recommended)
payload = {
    'name': 'New Project',
    'description': 'A test project',
    'tags': ['python', 'api']
}
 
response = requests.post('https://api.example.com/projects', json=payload)
 
# Method 2: Manual JSON encoding
import json
headers = {'Content-Type': 'application/json'}
response = requests.post(
    'https://api.example.com/projects',
    data=json.dumps(payload),
    headers=headers
)

Requisição POST com Arquivos

Faça upload de arquivos usando o parâmetro files:

import requests
 
# Upload a single file
files = {'file': open('report.pdf', 'rb')}
response = requests.post('https://example.com/upload', files=files)
 
# Upload multiple files
files = {
    'file1': open('document.pdf', 'rb'),
    'file2': open('image.jpg', 'rb')
}
response = requests.post('https://example.com/upload', files=files)
 
# Upload file with additional form data
files = {'file': open('data.csv', 'rb')}
data = {'description': 'Monthly report', 'category': 'finance'}
response = requests.post('https://example.com/upload', files=files, data=data)

Outros Métodos HTTP: PUT, PATCH, DELETE

A biblioteca requests suporta todos os métodos HTTP padrão:

import requests
 
# PUT - Replace entire resource
data = {'name': 'Updated Name', 'status': 'active'}
response = requests.put('https://api.example.com/users/123', json=data)
 
# PATCH - Partially update resource
data = {'status': 'inactive'}
response = requests.patch('https://api.example.com/users/123', json=data)
 
# DELETE - Remove resource
response = requests.delete('https://api.example.com/users/123')
print(response.status_code)  # 204 No Content
 
# HEAD - Get headers only (no response body)
response = requests.head('https://example.com')
print(response.headers)
 
# OPTIONS - Get supported methods
response = requests.options('https://api.example.com/users')
print(response.headers.get('Allow'))

Entendendo o Objeto Response

O objeto Response contém todas as informações sobre a resposta do servidor:

import requests
 
response = requests.get('https://api.github.com/users/github')
 
# Status code
print(response.status_code)  # 200, 404, 500, etc.
 
# Response body as string
print(response.text)
 
# Response body as JSON (for JSON APIs)
data = response.json()
print(data['login'])
 
# Raw binary content (for images, files)
image_data = response.content
with open('profile.jpg', 'wb') as f:
    f.write(image_data)
 
# Response headers
print(response.headers)
print(response.headers['Content-Type'])
 
# Encoding
print(response.encoding)  # 'utf-8'
 
# Request information
print(response.request.headers)
print(response.request.url)
 
# Check if request was successful
if response.ok:  # True if status_code < 400
    print("Success!")

Trabalhando com Headers de Requisição

Headers carregam metadados importantes sobre a requisição:

Definindo Headers Personalizados

import requests
 
headers = {
    'User-Agent': 'MyApp/1.0',
    'Accept': 'application/json',
    'Accept-Encoding': 'gzip, deflate',
    'Connection': 'keep-alive',
    'Custom-Header': 'custom-value'
}
 
response = requests.get('https://api.example.com', headers=headers)

Acessando Headers de Resposta

import requests
 
response = requests.get('https://api.github.com')
 
# Dictionary-like access
print(response.headers['Content-Type'])
print(response.headers.get('X-RateLimit-Remaining'))
 
# Case-insensitive access
print(response.headers['content-type'])  # Works!
 
# Iterate all headers
for key, value in response.headers.items():
    print(f"{key}: {value}")

Autenticação com Python Requests

A biblioteca requests suporta múltiplos mecanismos de autenticação:

Autenticação Básica

import requests
from requests.auth import HTTPBasicAuth
 
# Method 1: Using auth parameter (recommended)
response = requests.get(
    'https://api.example.com/protected',
    auth=('username', 'password')
)
 
# Method 2: Explicit HTTPBasicAuth
response = requests.get(
    'https://api.example.com/protected',
    auth=HTTPBasicAuth('username', 'password')
)
 
# Method 3: Manual header (not recommended)
import base64
credentials = base64.b64encode(b'username:password').decode('utf-8')
headers = {'Authorization': f'Basic {credentials}'}
response = requests.get('https://api.example.com/protected', headers=headers)

Autenticação com Bearer Token

Comum para tokens JWT e OAuth 2.0:

import requests
 
token = 'your_access_token_here'
headers = {'Authorization': f'Bearer {token}'}
 
response = requests.get('https://api.example.com/user', headers=headers)

Autenticação com Chave de API (API Key)

import requests
 
# Method 1: Query parameter
params = {'api_key': 'your_api_key_here'}
response = requests.get('https://api.example.com/data', params=params)
 
# Method 2: Custom header
headers = {'X-API-Key': 'your_api_key_here'}
response = requests.get('https://api.example.com/data', headers=headers)

Autenticação OAuth 2.0

Para OAuth 2.0, use a biblioteca requests-oauthlib:

from requests_oauthlib import OAuth2Session
 
client_id = 'your_client_id'
client_secret = 'your_client_secret'
token_url = 'https://oauth.example.com/token'
 
oauth = OAuth2Session(client_id)
token = oauth.fetch_token(token_url, client_secret=client_secret)
 
# Make authenticated requests
response = oauth.get('https://api.example.com/protected')

Sessões para Conexões Persistentes

Sessões mantêm cookies, connection pooling e configurações entre múltiplas requisições:

import requests
 
# Create a session
session = requests.Session()
 
# Set headers for all requests in this session
session.headers.update({
    'User-Agent': 'MyApp/1.0',
    'Accept': 'application/json'
})
 
# Login and session maintains cookies
login_data = {'username': 'john', 'password': 'secret'}
session.post('https://example.com/login', data=login_data)
 
# Subsequent requests use the session cookies
response1 = session.get('https://example.com/dashboard')
response2 = session.get('https://example.com/profile')
 
# Close the session
session.close()

Sessão com Autenticação

import requests
 
session = requests.Session()
session.auth = ('username', 'password')
 
# All requests in this session use the authentication
response1 = session.get('https://api.example.com/users')
response2 = session.get('https://api.example.com/posts')

Session Context Manager

import requests
 
with requests.Session() as session:
    session.headers.update({'Authorization': 'Bearer token123'})
 
    response1 = session.get('https://api.example.com/data')
    response2 = session.post('https://api.example.com/data', json={'key': 'value'})
 
# Session automatically closed after with block

Estratégias de Timeout e Retry

Sempre defina timeouts para evitar que requisições fiquem travadas indefinidamente:

Definindo Timeouts

import requests
 
# Single timeout value (applies to both connect and read)
response = requests.get('https://api.example.com', timeout=5)
 
# Separate connect and read timeouts
response = requests.get('https://api.example.com', timeout=(3, 10))
# 3 seconds to establish connection, 10 seconds to read response
 
# No timeout (dangerous - may hang forever)
response = requests.get('https://api.example.com', timeout=None)

Implementando Lógica de Retry

import requests
from requests.adapters import HTTPAdapter
from requests.packages.urllib3.util.retry import Retry
 
# Configure retry strategy
retry_strategy = Retry(
    total=3,  # Total number of retries
    backoff_factor=1,  # Wait 1, 2, 4 seconds between retries
    status_forcelist=[429, 500, 502, 503, 504],  # Retry on these status codes
    allowed_methods=["HEAD", "GET", "OPTIONS", "POST"]
)
 
adapter = HTTPAdapter(max_retries=retry_strategy)
session = requests.Session()
session.mount("http://", adapter)
session.mount("https://", adapter)
 
# Requests will automatically retry on failure
response = session.get('https://api.example.com/data')

Tratamento de Erros em Python Requests

Um tratamento de erros robusto é crucial para aplicações em produção:

Tratando Exceções Comuns

import requests
from requests.exceptions import (
    ConnectionError,
    Timeout,
    HTTPError,
    RequestException
)
 
try:
    response = requests.get('https://api.example.com/data', timeout=5)
    response.raise_for_status()  # Raises HTTPError for 4xx/5xx status codes
    data = response.json()
 
except ConnectionError:
    print("Failed to connect to the server")
 
except Timeout:
    print("Request timed out")
 
except HTTPError as e:
    print(f"HTTP error occurred: {e}")
    print(f"Status code: {e.response.status_code}")
 
except RequestException as e:
    # Catches all requests exceptions
    print(f"An error occurred: {e}")
 
except ValueError:
    # JSON decoding error
    print("Invalid JSON response")

Verificando Status Codes

import requests
 
response = requests.get('https://api.example.com/data')
 
# Method 1: Manual check
if response.status_code == 200:
    data = response.json()
elif response.status_code == 404:
    print("Resource not found")
elif response.status_code >= 500:
    print("Server error")
 
# Method 2: Using raise_for_status()
try:
    response.raise_for_status()
    data = response.json()
except requests.exceptions.HTTPError as e:
    if response.status_code == 404:
        print("Resource not found")
    elif response.status_code == 401:
        print("Authentication required")
    else:
        print(f"HTTP error: {e}")
 
# Method 3: Using response.ok
if response.ok:  # True if status_code < 400
    data = response.json()
else:
    print(f"Request failed with status {response.status_code}")

Verificação SSL e Certificados

Por padrão, requests verifica certificados SSL:

import requests
 
# Default behavior - verify SSL certificate
response = requests.get('https://api.example.com')
 
# Disable SSL verification (not recommended for production)
response = requests.get('https://example.com', verify=False)
 
# Suppress the InsecureRequestWarning
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
response = requests.get('https://example.com', verify=False)
 
# Use custom CA bundle
response = requests.get('https://example.com', verify='/path/to/ca_bundle.crt')
 
# Client-side certificates
response = requests.get(
    'https://example.com',
    cert=('/path/to/client.crt', '/path/to/client.key')
)

Usando Proxies com Python Requests

Configure servidores proxy para requisições:

import requests
 
# HTTP and HTTPS proxies
proxies = {
    'http': 'http://10.10.1.10:3128',
    'https': 'http://10.10.1.10:1080',
}
 
response = requests.get('https://api.example.com', proxies=proxies)
 
# SOCKS proxy (requires requests[socks])
proxies = {
    'http': 'socks5://user:pass@host:port',
    'https': 'socks5://user:pass@host:port'
}
 
# Use environment variables
# Set HTTP_PROXY and HTTPS_PROXY environment variables
response = requests.get('https://api.example.com')  # Automatically uses env proxies
 
# Disable proxies
response = requests.get('https://api.example.com', proxies={'http': None, 'https': None})

Comparação de Bibliotecas HTTP em Python

Veja como a biblioteca requests se compara com alternativas:

Featurerequestsurllibhttpxaiohttp
Ease of UseExcellent (Pythonic API)Poor (verbose)ExcellentGood
Async SupportNoNoYesYes
HTTP/2 SupportNoNoYesNo
Session ManagementBuilt-inManualBuilt-inBuilt-in
JSON HandlingAutomaticManualAutomaticAutomatic
Connection PoolingYesNoYesYes
Standard LibraryNo (pip install)YesNo (pip install)No (pip install)
DocumentationExcellentGoodExcellentGood
PerformanceGoodFairExcellentExcellent (async)
SSL/TLSFull supportFull supportFull supportFull support
Best ForSynchronous HTTP, general useSimple scripts, no dependenciesModern sync/async HTTPHigh-performance async

Quando usar cada uma:

  • requests: Escolha padrão para a maioria das operações HTTP síncronas. Melhor para web scraping, consumo de APIs e tarefas HTTP gerais.
  • urllib: Apenas quando você não pode instalar pacotes externos (exigência de biblioteca padrão).
  • httpx: Quando você precisa de suporte a HTTP/2 ou quer uma API moderna compatível com requests com capacidades async.
  • aiohttp: Para aplicações assíncronas de alto desempenho lidando com muitas requisições concorrentes.

Rate Limiting e Scraping Responsável

Ao fazer scraping de sites ou chamar APIs, implemente rate limiting:

import requests
import time
from datetime import datetime
 
class RateLimitedSession:
    def __init__(self, requests_per_second=1):
        self.session = requests.Session()
        self.min_interval = 1.0 / requests_per_second
        self.last_request_time = 0
 
    def get(self, url, **kwargs):
        # Wait if necessary
        elapsed = time.time() - self.last_request_time
        if elapsed < self.min_interval:
            time.sleep(self.min_interval - elapsed)
 
        # Make request
        response = self.session.get(url, **kwargs)
        self.last_request_time = time.time()
        return response
 
# Use rate-limited session
session = RateLimitedSession(requests_per_second=2)  # 2 requests per second
 
urls = ['https://api.example.com/item/1', 'https://api.example.com/item/2']
for url in urls:
    response = session.get(url)
    print(f"{datetime.now()}: {response.status_code}")

Respeitando o robots.txt

import requests
from urllib.robotparser import RobotFileParser
 
def can_fetch(url, user_agent='MyBot'):
    """Check if URL can be scraped according to robots.txt"""
    rp = RobotFileParser()
    robots_url = f"{url.split('/')[0]}//{url.split('/')[2]}/robots.txt"
    rp.set_url(robots_url)
    rp.read()
    return rp.can_fetch(user_agent, url)
 
url = 'https://example.com/page'
if can_fetch(url):
    response = requests.get(url)
else:
    print("Scraping not allowed by robots.txt")

Exemplos Reais e Casos de Uso

Exemplo 1: Consumindo uma API REST

import requests
 
class GitHubAPI:
    def __init__(self, token=None):
        self.base_url = 'https://api.github.com'
        self.session = requests.Session()
        if token:
            self.session.headers.update({'Authorization': f'token {token}'})
 
    def get_user(self, username):
        """Get user information"""
        response = self.session.get(f'{self.base_url}/users/{username}')
        response.raise_for_status()
        return response.json()
 
    def search_repositories(self, query, sort='stars', limit=10):
        """Search repositories"""
        params = {'q': query, 'sort': sort, 'per_page': limit}
        response = self.session.get(f'{self.base_url}/search/repositories', params=params)
        response.raise_for_status()
        return response.json()['items']
 
    def create_issue(self, owner, repo, title, body):
        """Create an issue in a repository"""
        url = f'{self.base_url}/repos/{owner}/{repo}/issues'
        data = {'title': title, 'body': body}
        response = self.session.post(url, json=data)
        response.raise_for_status()
        return response.json()
 
# Usage
api = GitHubAPI(token='your_github_token')
user = api.get_user('torvalds')
print(f"Name: {user['name']}, Followers: {user['followers']}")
 
repos = api.search_repositories('python requests', limit=5)
for repo in repos:
    print(f"{repo['full_name']}: {repo['stargazers_count']} stars")

Exemplo 2: Baixando Arquivos com Progresso

import requests
from tqdm import tqdm
 
def download_file(url, filename):
    """Download file with progress bar"""
    response = requests.get(url, stream=True)
    response.raise_for_status()
 
    total_size = int(response.headers.get('content-length', 0))
 
    with open(filename, 'wb') as f, tqdm(
        desc=filename,
        total=total_size,
        unit='B',
        unit_scale=True,
        unit_divisor=1024,
    ) as progress_bar:
        for chunk in response.iter_content(chunk_size=8192):
            f.write(chunk)
            progress_bar.update(len(chunk))
 
# Download a file
download_file('https://example.com/large-file.zip', 'downloaded.zip')

Exemplo 3: Web Scraping com Tratamento de Erros

import requests
from bs4 import BeautifulSoup
import time
 
def scrape_articles(base_url, max_pages=5):
    """Scrape article titles from a news website"""
    session = requests.Session()
    session.headers.update({
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
    })
 
    articles = []
 
    for page in range(1, max_pages + 1):
        try:
            url = f"{base_url}?page={page}"
            response = session.get(url, timeout=10)
            response.raise_for_status()
 
            soup = BeautifulSoup(response.content, 'html.parser')
            titles = soup.find_all('h2', class_='article-title')
 
            for title in titles:
                articles.append({
                    'title': title.text.strip(),
                    'url': title.find('a')['href'] if title.find('a') else None
                })
 
            print(f"Scraped page {page}: {len(titles)} articles")
            time.sleep(1)  # Rate limiting
 
        except requests.exceptions.RequestException as e:
            print(f"Error scraping page {page}: {e}")
            continue
 
    return articles
 
# Usage
articles = scrape_articles('https://news.example.com/articles', max_pages=3)
print(f"Total articles collected: {len(articles)}")

Exemplo 4: Integração de API com Paginação

import requests
 
def fetch_all_items(api_url, headers=None):
    """Fetch all items from a paginated API"""
    items = []
    page = 1
 
    while True:
        try:
            params = {'page': page, 'per_page': 100}
            response = requests.get(api_url, params=params, headers=headers, timeout=10)
            response.raise_for_status()
 
            data = response.json()
 
            if not data:  # No more items
                break
 
            items.extend(data)
            print(f"Fetched page {page}: {len(data)} items")
 
            page += 1
 
            # Check for pagination in headers
            if 'Link' in response.headers:
                links = response.headers['Link']
                if 'rel="next"' not in links:
                    break
 
        except requests.exceptions.RequestException as e:
            print(f"Error fetching page {page}: {e}")
            break
 
    return items
 
# Usage
all_items = fetch_all_items('https://api.example.com/items')
print(f"Total items: {len(all_items)}")

Testando APIs no Jupyter com RunCell

Ao desenvolver e testar integrações com APIs, o RunCell (opens in a new tab) fornece um ambiente de agente com IA diretamente em notebooks Jupyter. Em vez de depurar manualmente requisições e respostas HTTP, o agente inteligente do RunCell pode ajudar você a:

  • Construir e testar automaticamente requisições de API com a autenticação correta
  • Depurar parsing de resposta e tratamento de erros em tempo real
  • Gerar trechos de código para padrões HTTP comuns
  • Validar respostas de API contra schemas esperados
  • Iterar rapidamente em transformações de dados a partir de respostas de API

Isso é particularmente valioso ao trabalhar com APIs complexas que exigem múltiplas etapas de autenticação, tratamento de paginação ou lógica de parsing de dados mais intrincada. O RunCell acelera o fluxo de desenvolvimento ao reduzir o vai-e-volta de testar requisições HTTP manualmente.

FAQ

Para que serve a biblioteca requests do Python?

A biblioteca requests do Python é usada para fazer requisições HTTP para servidores web e APIs. Ela simplifica tarefas como buscar páginas web, consumir APIs REST, enviar dados de formulário, fazer upload de arquivos e lidar com autenticação. É a biblioteca HTTP mais popular em Python devido à sua API intuitiva e ao conjunto abrangente de recursos.

Como instalo a biblioteca requests do Python?

Instale a biblioteca requests usando pip: pip install requests. Para ambientes conda, use conda install requests. Depois de instalada, importe-a com import requests no seu código Python. A biblioteca não faz parte da biblioteca padrão do Python, então a instalação é necessária.

Qual é a diferença entre requests.get() e requests.post()?

requests.get() recupera dados de um servidor sem modificar nada, normalmente usada para buscar páginas web ou dados de APIs. requests.post() envia dados ao servidor para criar ou atualizar recursos, comumente usada para envios de formulários, upload de arquivos ou operações de API que modificam o estado do servidor. Requisições GET passam parâmetros na URL, enquanto requisições POST enviam dados no corpo da requisição.

Como faço o tratamento de erros com a biblioteca requests do Python?

Use blocos try-except para capturar exceções de requisição: ConnectionError para problemas de rede, Timeout para respostas lentas, HTTPError para status codes 4xx/5xx e RequestException como captura geral. Chame response.raise_for_status() após cada requisição para levantar automaticamente HTTPError quando a requisição falhar. Sempre defina timeouts para evitar que requisições fiquem travadas indefinidamente.

Como envio dados JSON com Python requests?

Use o parâmetro json em requests: requests.post(url, json=data). A biblioteca serializa automaticamente dicionários Python para JSON e define o header Content-Type: application/json. Para fazer o parsing de respostas JSON, use response.json(), que desserializa o corpo da resposta JSON em um dicionário Python.

Devo usar requests ou urllib em Python?

Use a biblioteca requests para a maioria das operações HTTP. Ela oferece uma API mais limpa, tratamento automático de JSON, gerenciamento de sessão embutido e melhor tratamento de erros em comparação ao urllib. Só use urllib quando você não puder instalar pacotes externos e precisar depender apenas da biblioteca padrão do Python. Para aplicações modernas que exigem HTTP/2 ou suporte async, considere httpx como alternativa.

Como adiciono autenticação no Python requests?

Para autenticação Basic, use requests.get(url, auth=('username', 'password')). Para tokens Bearer (JWT, OAuth), adicione um header Authorization: headers = {'Authorization': f'Bearer {token}'}. Para API keys, adicione-as como parâmetros de query usando o dicionário params ou como headers personalizados como 'X-API-Key'. Sessões podem persistir a autenticação entre múltiplas requisições.

O que são sessões (sessions) em Python requests e quando devo usá-las?

Sessions mantêm configurações (headers, cookies, autenticação) entre múltiplas requisições para o mesmo servidor. Use sessions quando fizer múltiplas requisições a uma API, quando precisar manter estado de login com cookies, ou quando quiser reutilizar conexões TCP para melhor desempenho. Crie uma sessão com session = requests.Session() e use session.get() em vez de requests.get().

Conclusão

A biblioteca Python requests é uma ferramenta indispensável para comunicação HTTP em Python. Sua API elegante transforma operações HTTP complexas em código simples e legível. De requisições GET básicas a recursos avançados como autenticação, sessões, upload de arquivos e tratamento de erros, requests fornece tudo o que você precisa para interações HTTP robustas.

Ao dominar os padrões e as boas práticas deste guia — definir timeouts, implementar lógica de retry, tratar erros com elegância e respeitar rate limits — você construirá aplicações confiáveis que se comunicam de forma eficaz com serviços web e APIs. Seja consumindo APIs REST, fazendo web scraping ou criando ferramentas de automação, a biblioteca requests torna as operações HTTP diretas e fáceis de manter.

📚