urllib.request en Python: HTTP nativo

Publicado el: 19/08/2026
Tempo de leitura: 4 minutos
Teclas formando HTTP que representan solicitudes con urllib.request en Python

El módulo urllib.request permite abrir URLs y realizar solicitudes HTTP utilizando únicamente la biblioteca estándar. Proporciona urlopen(), objetos Request configurables y una arquitectura de handlers para redirects, autenticación, cookies, proxies y HTTPS.

Clientes superiores como Requests o HTTPX son más cómodos en aplicaciones grandes, pero urllib.request es útil en scripts portables, instaladores, herramientas administrativas y entornos sin dependencias externas. Esta guía cubre GET, POST, JSON, descargas limitadas, TLS, redirects, proxies, errores, retries y protección frente a URLs no confiables.

Primera solicitud 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)

La respuesta funciona como context manager y expone status, headers y url. El cuerpo son bytes porque el cliente no puede determinar automáticamente el encoding correcto.

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

La guía de codecs en Python explica la frontera entre texto y bytes.

Usa siempre timeout

Sin timeout, DNS, conexión, TLS o lectura pueden bloquear el programa durante mucho tiempo.

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

El timeout no limita el tamaño. Un servidor puede continuar enviando datos mientras la conexión sigue activa. Cuenta los bytes y detén la lectura al superar el máximo configurado.

Objeto Request

from urllib.request import Request, urlopen

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

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

Identifica la automatización honestamente. No suplantes un navegador para evitar políticas. Respeta límites, términos y robots cuando corresponda.

Query strings correctas

from urllib.parse import urlencode

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

La guía de urllib.parse en Python cubre quoting, análisis y validación de URLs.

POST de formulario

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)

Si se proporciona data sin método, POST se convierte en el valor por defecto. Declararlo facilita la revisión.

Enviar JSON

import json
from urllib.request import Request, urlopen

payload = json.dumps({"title": "Ejemplo"}).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"))

Valida Content-Type, estado y tamaño antes de procesar. La guía para integrar APIs con Python complementa autenticación y errores.

HTTPError y 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"Fallo de red: {error.reason}")
except TimeoutError:
    print("Tiempo agotado")

HTTPError representa una respuesta de error y todavía permite leer un cuerpo limitado. URLError cubre DNS, conexión, TLS y protocolos.

Descargas con límite

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("El archivo declarado es demasiado 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("La descarga superó el límite")
            output.write(chunk)

Escribe en un temporal, valida formato o digest y mueve de forma atómica. La guía de hashlib en Python muestra verificación SHA-256.

Contenido comprimido

urllib.request no descomprime automáticamente todos los encodings. Si solicitas gzip, inspecciona la cabecera y limita entrada y salida.

import gzip

encoding = response.headers.get("Content-Encoding", "").lower()
raw = response.read(2_000_000)
data = gzip.decompress(raw) if encoding == "gzip" else raw

Para contenido grande o externo usa descompresión incremental con máximo. Consulta la guía de gzip en Python.

TLS y CA privada

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)

HTTPS valida certificado y hostname de forma segura. No desactives la comprobación. La guía de ssl en Python explica los contextos TLS.

Redirects

El opener por defecto sigue redirects. Revisa response.url para conocer el destino final. Los headers sensibles no deben enviarse a dominios inesperados. Usa add_unredirected_header() o un handler restrictivo.

Los códigos 301 y 302 pueden convertir POST en GET. Los códigos 307 y 308 conservan el método. Revisa esta política en operaciones que modifican estado.

Desactivar 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())

Si permites redirects, limita la cantidad y valida esquema, hostname, puerto e IP resuelta en cada salto.

Proxies del entorno

El opener puede leer http_proxy, https_proxy y configuración del sistema. Un servicio sensible no debería depender de un entorno no controlado.

from urllib.request import ProxyHandler, build_opener

opener = build_opener(ProxyHandler({}))

Un diccionario vacío desactiva proxies detectados. Configura proxies aprobados explícitamente y mantén credenciales fuera del código.

Autenticación Basic y Digest

HTTPBasicAuthHandler y HTTPDigestAuthHandler integran credenciales. Basic solo codifica usuario y contraseña y requiere HTTPS. Limita cada credencial al URI correcto. Python 3.14 añadió SHA-256 a Digest.

Protección contra SSRF

No pases una URL del usuario directamente a urlopen(). La biblioteca acepta esquemas como file:, data: y FTP, lo que puede leer archivos locales o acceder a servicios internos.

Permite solo HTTPS, normaliza hostname, resuelve DNS, bloquea direcciones privadas, loopback, link-local y metadata de nube, y repite la validación después de cada redirect. Considera DNS rebinding.

Retries seguros

El módulo no incluye una política completa. Repite solo errores transitorios y métodos idempotentes, con backoff y máximo. Un POST puede haberse procesado aunque la respuesta se perdiera. Usa idempotency key cuando exista.

Errores frecuentes

Los fallos comunes son omitir timeout, leer sin límite, asumir encoding, desactivar TLS, seguir redirects sin validar destino, filtrar Authorization, aceptar cualquier esquema, heredar proxies no confiables y repetir POST ciegamente.

Buenas prácticas

Crea Request explícito, define timeout, limita respuesta y descompresión, valida estado y tipo, usa HTTPS seguro, controla redirects y proxies y cierra con with. Para aplicaciones complejas, prefiere un cliente mantenido con pooling y políticas más completas.

Conclusión

urllib.request es un cliente HTTP funcional sin dependencias. Es adecuado para scripts controlados si timeouts, límites, TLS, redirects y URLs externas se gestionan explícitamente. Su arquitectura de handlers es potente, pero exige comprender cada etapa.

Consulta la documentación oficial de urllib.request y el RFC 9110 sobre semántica HTTP.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Contenido del artículo

    Artículos relacionados

    Código de error sobre datos binarios que representa fallos manejados con urllib.error en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    urllib.error en Python: maneja errores HTTP

    Aprende urllib.error en Python para manejar URLError, HTTPError, descargas incompletas, retries selectivos y diagnósticos de red claros.

    Ler mais

    Tempo de leitura: 5 minutos
    21/08/2026
    Teclas con la palabra HTML que representan entidades HTML en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    html.entities: convierte entidades HTML

    Aprende html.entities en Python para consultar entidades HTML, convertir nombres y code points y no confundir decodificación con sanitización.

    Ler mais

    Tempo de leitura: 7 minutos
    21/08/2026
    Carpeta con archivos que representa tipos MIME identificados con mimetypes en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    mimetypes: detecta tipos MIME de archivos

    Aprende mimetypes en Python para identificar tipos de archivo, validar cargas y definir Content-Type con más seguridad.

    Ler mais

    Tempo de leitura: 6 minutos
    20/08/2026
    Código HTML en una pantalla que representa análisis con html.parser en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    html.parser en Python: analiza HTML

    Aprende html.parser en Python para extraer texto, enlaces y metadatos, procesar HTML por bloques y no confundir parsing con sanitización.

    Ler mais

    Tempo de leitura: 4 minutos
    20/08/2026
    Persona usando un portátil en una sesión web que representa cookies con http.cookiejar en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    http.cookiejar en Python: gestiona cookies

    Aprende http.cookiejar en Python para mantener sesiones, aplicar políticas, persistir cookies de forma segura e integrar urllib.request.

    Ler mais

    Tempo de leitura: 5 minutos
    20/08/2026
    Rack de servidores que representa conexiones HTTP de bajo nivel con http.client en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    http.client en Python: HTTP de bajo nivel

    Aprende http.client en Python para controlar conexiones HTTP y HTTPS, streaming, headers, TLS, reutilización, límites y errores.

    Ler mais

    Tempo de leitura: 4 minutos
    20/08/2026