urllib.request no Python: HTTP nativo

Publicado em: 19/08/2026
Tempo de leitura: 5 minutos
Teclas formando HTTP representando requisições com urllib.request no Python

O módulo urllib.request permite abrir URLs e fazer requisições HTTP usando apenas a biblioteca padrão. Ele oferece urlopen(), objetos Request e uma arquitetura extensível de handlers para redirects, autenticação, cookies, proxies e HTTPS.

Embora bibliotecas como Requests ou HTTPX sejam mais convenientes em aplicações grandes, urllib.request é útil em scripts portáveis, instaladores, ferramentas administrativas e ambientes onde dependências externas não são desejadas. Este guia mostra GET, POST, JSON, downloads limitados, TLS, redirects, proxies, erros e proteção contra URLs não confiáveis.

Primeira requisição GET

from urllib.request import urlopen

with urlopen("https://www.python.org/", timeout=10) as response:
    print(response.status)
    print(response.headers.get_content_type())
    data = response.read(4096)

A resposta funciona como context manager e expõe status, headers e url. O corpo é retornado como bytes. Você precisa determinar o encoding antes de transformá-lo em texto.

charset = response.headers.get_content_charset() or "utf-8"
text = data.decode(charset, errors="replace")

O guia de codecs no Python explica por que bytes e texto devem ser tratados separadamente.

Use sempre timeout

Sem timeout, uma conexão pode bloquear o programa por muito tempo. O parâmetro cobre operações bloqueantes de conexão e leitura de protocolos suportados.

with urlopen(url, timeout=10) as response:
    body = response.read(1_000_000)

O timeout não substitui um limite de tamanho. Um servidor pode responder continuamente dentro do prazo. Leia em blocos e interrompa quando o total ultrapassar o máximo permitido.

Criando um objeto Request

Request permite definir método e headers.

from urllib.request import Request, urlopen

request = Request(
    "https://api.example.com/items",
    headers={
        "Accept": "application/json",
        "User-Agent": "MinhaFerramenta/1.0",
    },
    method="GET",
)

with urlopen(request, timeout=10) as response:
    body = response.read(500_000)

Identifique o cliente honestamente. Não copie um User-Agent de navegador para contornar regras de acesso. Respeite termos, limites e o arquivo robots quando aplicável.

Query strings corretas

Use urllib.parse.urlencode() em vez de concatenar parâmetros manualmente.

from urllib.parse import urlencode

params = urlencode({"q": "python seguro", "page": 2})
url = f"https://example.com/search?{params}"

O artigo sobre urllib.parse no Python cobre quoting, parsing e validação de URLs.

POST com formulário

from urllib.parse import urlencode
from urllib.request import Request, urlopen

form = urlencode({"name": "Ana", "active": "1"}).encode("ascii")
request = Request(
    "https://example.com/form",
    data=form,
    headers={"Content-Type": "application/x-www-form-urlencoded"},
    method="POST",
)

with urlopen(request, timeout=10) as response:
    result = response.read(100_000)

Quando data é fornecido sem método explícito, o padrão passa a ser POST. Declarar o método deixa a intenção clara.

Enviando e recebendo JSON

import json
from urllib.request import Request, urlopen

payload = json.dumps({"title": "Exemplo"}).encode("utf-8")
request = Request(
    "https://api.example.com/items",
    data=payload,
    headers={
        "Content-Type": "application/json",
        "Accept": "application/json",
    },
    method="POST",
)

with urlopen(request, timeout=10) as response:
    raw = response.read(500_000)
    result = json.loads(raw.decode("utf-8"))

Valide o Content-Type antes de assumir JSON e limite a resposta. O guia de APIs REST no Python apresenta validação de status, retries e autenticação.

Tratamento de HTTPError e URLError

from urllib.error import HTTPError, URLError

try:
    with urlopen(request, timeout=10) as response:
        body = response.read(100_000)
except HTTPError as error:
    error_body = error.read(20_000)
    print(error.code, error.reason)
except URLError as error:
    print(f"Falha de rede: {error.reason}")
except TimeoutError:
    print("Tempo esgotado")

HTTPError representa uma resposta HTTP com erro e também funciona como objeto de resposta, permitindo ler um corpo limitado. URLError cobre falhas de resolução, conexão, TLS e protocolos.

Downloads com limite

Evite response.read() sem limite para arquivos externos. Verifique o cabeçalho e conte os bytes realmente lidos.

from pathlib import Path

MAX_BYTES = 50 * 1024 * 1024

with urlopen(url, timeout=20) as response:
    declared = response.headers.get("Content-Length")
    if declared and int(declared) > MAX_BYTES:
        raise ValueError("Arquivo declarado é muito grande")

    total = 0
    with Path("download.tmp").open("wb") as output:
        while chunk := response.read(64 * 1024):
            total += len(chunk)
            if total > MAX_BYTES:
                raise ValueError("Download ultrapassou o limite")
            output.write(chunk)

Grave em arquivo temporário, valide hash ou formato e mova atomicamente para o destino. Veja o guia de hashlib no Python para verificar SHA-256.

Conteúdo comprimido

urllib.request não descomprime automaticamente toda resposta. Ao solicitar gzip, valide o header e limite também o tamanho descomprimido.

import gzip

encoding = response.headers.get("Content-Encoding", "").lower()
raw = response.read(2_000_000)

if encoding == "gzip":
    data = gzip.decompress(raw)
else:
    data = raw

Para dados não confiáveis e grandes, prefira descompressão incremental com limite. O artigo de gzip no Python detalha proteção contra expansão excessiva.

TLS e certificados

HTTPS usa validação segura por padrão. Para uma CA privada, forneça um SSLContext confiável.

import ssl

context = ssl.create_default_context(cafile="empresa-ca.pem")
with urlopen(request, timeout=10, context=context) as response:
    body = response.read(100_000)

Não desative hostname nem validação de certificado. Corrija a cadeia de confiança. O guia de ssl no Python explica os riscos de CERT_NONE.

Redirects e headers sensíveis

O handler padrão segue redirects HTTP. Analise o URL final em response.url. Credenciais e headers sensíveis não devem ser encaminhados para domínios inesperados. Use add_unredirected_header() para um header que não pode acompanhar redirects ou implemente um HTTPRedirectHandler restritivo.

Redirects 301 e 302 podem transformar POST em GET, imitando navegadores. Os códigos 307 e 308 preservam o método. Quando a operação tem efeito, revise explicitamente essa política.

Desabilitando redirects automáticos

from urllib.request import build_opener, HTTPRedirectHandler

class NoRedirect(HTTPRedirectHandler):
    def redirect_request(self, req, fp, code, msg, headers, newurl):
        return None

opener = build_opener(NoRedirect())

Ao permitir redirects, imponha quantidade máxima e valide esquema, hostname e porta de cada destino. Isso é essencial quando parte do URL vem do usuário.

Proxies do ambiente

O opener padrão pode ler http_proxy, https_proxy e configurações do sistema. Em servidores e tarefas sensíveis, não deixe essa dependência implícita.

from urllib.request import ProxyHandler, build_opener

opener = build_opener(ProxyHandler({}))  # sem proxy autodetectado

Para proxy explícito, forneça um dicionário e mantenha credenciais fora do código. Variáveis de ambiente não confiáveis podem desviar tráfego.

Autenticação Basic e Digest

HTTPBasicAuthHandler e HTTPDigestAuthHandler integram autenticação ao opener. Basic apenas codifica usuário e senha; ele exige HTTPS. Restrinja credenciais ao URI correto para evitar envio a outros hosts. Python 3.14 adicionou suporte a SHA-256 no handler Digest.

Proteção contra SSRF

Não passe diretamente uma URL fornecida pelo usuário para urlopen(). O módulo também abre esquemas como file:, data: e FTP. Uma aplicação pode acabar lendo arquivos locais ou acessando serviços internos.

Faça parsing, permita apenas https, normalize hostname, resolva DNS, bloqueie IPs privados, loopback, link-local e metadata de nuvem, e valide novamente após cada redirect. Considere DNS rebinding e diferenças entre o hostname validado e o endereço usado na conexão.

Retries seguros

urllib.request não implementa uma política completa de retry. Repita somente erros transitórios e métodos idempotentes, com backoff e limite. Um POST pode ter sido processado mesmo se a resposta não chegou. Use idempotency key quando a API oferecer suporte.

Erros comuns

Os principais problemas são omitir timeout, ler resposta sem limite, confiar no encoding, desativar TLS, seguir redirects sem validar destino, vazar Authorization, aceitar qualquer esquema, depender de proxy do ambiente e repetir POST cegamente.

Boas práticas

Crie Request explícito, configure timeout, limite corpo e descompressão, valide status e tipo, use HTTPS com contexto seguro, trate redirects, controle proxies e feche respostas com with. Para aplicações complexas, prefira um cliente HTTP mantido com pooling, retries e limites mais completos.

Conclusão

urllib.request oferece um cliente HTTP funcional sem dependências externas. Ele é adequado para scripts e integrações controladas, desde que timeouts, limites, TLS, redirects e URLs externas sejam tratados explicitamente. A arquitetura de handlers permite personalização, mas também exige compreender o comportamento de cada etapa.

Consulte a documentação oficial de urllib.request e o RFC 9110 sobre semântica HTTP.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Conteúdo do artigo

    Artigos relacionados

    Cabos Ethernet conectados representando servidores de rede com socketserver no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    socketserver no Python: crie servidores

    Aprenda socketserver no Python para criar servidores TCP e UDP, aplicar concorrência, limites, timeouts e encerramento seguro.

    Ler mais

    Tempo de leitura: 6 minutos
    19/08/2026
    Sala de servidores iluminada representando conexões TLS seguras com ssl no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    ssl no Python: conexões TLS seguras

    Aprenda ssl no Python para criar clientes e servidores TLS, validar certificados, configurar versões mínimas, CA e autenticação mútua.

    Ler mais

    Tempo de leitura: 6 minutos
    19/08/2026
    Tela de verificação de conta representando autenticação de mensagens com HMAC no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    hmac no Python: autentique mensagens

    Aprenda HMAC no Python para assinar e validar webhooks, arquivos e mensagens com SHA-256, chaves seguras e comparação resistente a

    Ler mais

    Tempo de leitura: 6 minutos
    19/08/2026
    Leitor de impressão digital representando verificação de hashes com hashlib no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    hashlib no Python: hashes seguros

    Aprenda hashlib no Python para calcular SHA-256, verificar arquivos, usar BLAKE2, derivar chaves e evitar erros comuns de segurança.

    Ler mais

    Tempo de leitura: 6 minutos
    19/08/2026
    Código binário projetado representando conversões com binascii no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    binascii no Python: binário e ASCII

    Aprenda binascii no Python para converter hexadecimal, Base64 e quoted-printable, calcular CRC e validar dados binários com segurança.

    Ler mais

    Tempo de leitura: 6 minutos
    18/08/2026
    A person reads 'Python for Unix and Linux System Administration' indoors.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    codecs no Python: domine encodings

    Aprenda codecs no Python para trabalhar com encodings, handlers de erro, BOM, streams incrementais e migrar codecs.open para open.

    Ler mais

    Tempo de leitura: 7 minutos
    18/08/2026