Generar códigos QR con Python es una forma sencilla de convertir enlaces, identificadores, textos o configuraciones en una imagen que puede leerse con un teléfono. La biblioteca qrcode abstrae la construcción de la matriz y utiliza Pillow para producir archivos PNG. Con unas pocas líneas puedes crear un código básico; con una estructura más cuidada puedes generar cientos de imágenes, validar entradas y organizar resultados automáticamente.
Este proyecto combina conceptos de archivos, imágenes y automatización. Si necesitas una base para trabajar con rutas, revisa pathlib en Python. Para construir una interfaz de terminal con opciones, resulta útil la guía de argparse.
Instalar la biblioteca qrcode
Crea un entorno virtual e instala la variante que incluye Pillow:
python -m venv .venv
# Windows PowerShell
.venv\Scripts\Activate.ps1
# macOS o Linux
source .venv/bin/activate
python -m pip install "qrcode[pil]"El entorno aislado evita conflictos con otros proyectos. Guarda la dependencia en tu archivo de proyecto o requirements para reproducir la instalación.
Crear el primer código QR
import qrcode
imagen = qrcode.make("https://academify.com.br/")
imagen.save("academify-qr.png")El método make() elige una configuración automática y devuelve una imagen. Este enfoque es suficiente para pruebas rápidas, pero una instancia QRCode ofrece mayor control.
Configurar tamaño y corrección de errores
import qrcode
from qrcode.constants import ERROR_CORRECT_M
qr = qrcode.QRCode(
version=None,
error_correction=ERROR_CORRECT_M,
box_size=10,
border=4,
)
qr.add_data("https://example.com/documentacion")
qr.make(fit=True)
imagen = qr.make_image(fill_color="black", back_color="white")
imagen.save("documentacion.png")box_size controla el tamaño de cada módulo cuadrado. border define la zona blanca exterior. El estándar recomienda una zona silenciosa suficiente para que los lectores separen el código del fondo.
La corrección de errores permite recuperar información cuando parte de la imagen está dañada u oculta. Los niveles más altos aumentan la redundancia y también el tamaño de la matriz.
Elegir el contenido adecuado
Un QR puede guardar texto, URLs, correos, datos Wi-Fi o información estructurada. No obstante, el espacio es limitado y una carga grande produce una matriz más densa y difícil de leer. Para contenido extenso, almacena una URL corta y estable en lugar de insertar todo el texto.
contenido = "https://example.com/guias/python?origen=qr"
if not contenido.startswith(("https://", "http://")):
raise ValueError("La URL debe utilizar HTTP o HTTPS")Valida datos externos antes de generar la imagen. Un código QR no vuelve seguro un enlace: solo lo oculta visualmente hasta que el lector lo interpreta.
Crear nombres de archivo seguros
from pathlib import Path
import re
def nombre_seguro(texto: str) -> str:
limpio = re.sub(r"[^a-zA-Z0-9_-]+", "-", texto.strip().lower())
return limpio.strip("-") or "codigo"
salida = Path("qr")
salida.mkdir(exist_ok=True)
ruta = salida / f"{nombre_seguro('Página principal')}.png"No utilices directamente entradas del usuario como rutas. Caracteres especiales, separadores y nombres reservados pueden provocar errores o escribir en ubicaciones inesperadas.
Generar varios códigos en lote
from pathlib import Path
import qrcode
registros = [
("inicio", "https://example.com/"),
("curso-python", "https://example.com/python"),
("contacto", "https://example.com/contacto"),
]
salida = Path("codigos_qr")
salida.mkdir(parents=True, exist_ok=True)
for nombre, contenido in registros:
imagen = qrcode.make(contenido)
imagen.save(salida / f"{nombre}.png")Este patrón puede ampliarse para leer datos de CSV. La guía de archivos CSV en Python explica cómo validar columnas, codificación y filas incompletas.
Leer datos desde un CSV
import csv
from pathlib import Path
import qrcode
salida = Path("resultado")
salida.mkdir(exist_ok=True)
with open("enlaces.csv", newline="", encoding="utf-8") as archivo:
lector = csv.DictReader(archivo)
for fila in lector:
nombre = fila["nombre"].strip()
url = fila["url"].strip()
if not nombre or not url:
continue
qrcode.make(url).save(salida / f"{nombre}.png")En producción, registra las filas omitidas, limpia el nombre y comprueba que no existan duplicados que sobrescriban imágenes anteriores.
Personalizar colores
qr = qrcode.QRCode(error_correction=qrcode.constants.ERROR_CORRECT_H)
qr.add_data("https://example.com")
qr.make(fit=True)
imagen = qr.make_image(
fill_color="#111827",
back_color="#ffffff",
)
imagen.save("qr-personalizado.png")Mantén contraste alto entre módulos y fondo. Combinaciones atractivas pero poco contrastadas pueden fallar con cámaras antiguas, iluminación deficiente o impresiones pequeñas. Prueba siempre con varios dispositivos.
Añadir un logotipo con cuidado
Pillow permite superponer una imagen central. Usa un nivel alto de corrección de errores y limita el tamaño del logotipo.
from PIL import Image
import qrcode
qr = qrcode.QRCode(error_correction=qrcode.constants.ERROR_CORRECT_H)
qr.add_data("https://example.com")
qr.make(fit=True)
imagen = qr.make_image(fill_color="black", back_color="white").convert("RGB")
logo = Image.open("logo.png").convert("RGBA")
logo.thumbnail((imagen.width // 5, imagen.height // 5))
posicion = (
(imagen.width - logo.width) // 2,
(imagen.height - logo.height) // 2,
)
imagen.paste(logo, posicion, logo)
imagen.save("qr-logo.png")La guía para redimensionar imágenes con Pillow ayuda a controlar formatos, proporciones y procesamiento por lotes.
Crear una función reutilizable
from pathlib import Path
import qrcode
def generar_qr(contenido: str, destino: Path) -> Path:
if not contenido.strip():
raise ValueError("El contenido no puede estar vacío")
destino.parent.mkdir(parents=True, exist_ok=True)
qr = qrcode.QRCode(
error_correction=qrcode.constants.ERROR_CORRECT_M,
box_size=10,
border=4,
)
qr.add_data(contenido)
qr.make(fit=True)
qr.make_image(fill_color="black", back_color="white").save(destino)
return destinoSeparar la lógica en una función facilita pruebas, automatización y reutilización dentro de una API o aplicación de escritorio.
Convertirlo en una herramienta de terminal
import argparse
from pathlib import Path
parser = argparse.ArgumentParser(description="Genera un código QR")
parser.add_argument("contenido")
parser.add_argument("--salida", default="codigo.png")
args = parser.parse_args()
generar_qr(args.contenido, Path(args.salida))Para un menú interactivo, también puedes aplicar el patrón presentado en menús de terminal con Python.
Seguridad y privacidad
No incluyas contraseñas, tokens permanentes o información personal sensible dentro del código. La imagen puede copiarse, fotografiarse y decodificarse sin autorización. Cuando el QR da acceso a una operación, usa URLs temporales, tokens de corta duración y controles del lado del servidor.
Si generas códigos para pagos o autenticación, valida el formato oficial correspondiente. No construyas cadenas financieras manualmente sin comprobar especificaciones y firmas.
Comprobar la calidad
Prueba la imagen en pantalla e impresa, a distintas distancias, con varios lectores y bajo iluminación real. Conserva el borde, evita deformar la proporción y no comprimas excesivamente el PNG. Un diseño visualmente correcto no garantiza una lectura confiable.
Errores frecuentes
Los problemas habituales son eliminar la zona blanca, usar poco contraste, crear imágenes demasiado pequeñas, guardar nombres inseguros, sobrescribir archivos y colocar un logotipo demasiado grande. Otro error es asumir que todo teléfono abrirá automáticamente cualquier esquema de URL.
Fuentes confiables
La página oficial del paquete qrcode en PyPI documenta instalación, opciones y ejemplos. La documentación oficial de Pillow explica el manejo de imágenes utilizado para personalización y logotipos.
Conclusión
Python permite generar códigos QR básicos o sistemas completos de producción por lotes. Utiliza qrcode para construir la matriz, Pillow para personalizar imágenes y pathlib para gestionar salidas. Prioriza contraste, validación, privacidad y pruebas reales: un código QR solo es útil cuando puede leerse de manera consistente y conduce a un destino seguro.






