# PDF con formularios: rellenar campos con Python
Los PDF con formularios interactivos (AcroForm) son habituales en documentacion oficial, contratos y solicitudes. Python permite leer, rellenar y crear estos formularios automaticamente.
## Tipos de campos AcroForm
| Tipo | Descripcion |
|---|---|
| **TextField** | Texto libre |
| **CheckBox** | Casilla de verificacion |
| **RadioButton** | Boton de opcion |
| **ComboBox** | Lista desplegable |
| **ListBox** | Seleccion multiple |
| **Signature** | Firma digital |
## Leer campos con pypdf
```bash
pip install pypdf
```
```python
from pypdf import PdfReader
reader = PdfReader("formulario.pdf")
# Campos de texto
campos = reader.get_form_text_fields()
for nombre, valor in campos.items():
print(f" {nombre!r}: {valor!r}")
# Todos los tipos de campos
for nombre, campo in reader.get_fields().items():
tipo = campo.get('/FT', '?')
valor = campo.get('/V', '')
print(f" [{tipo}] {nombre}: {valor}")
```
## Rellenar formulario existente
```python
from pypdf import PdfReader, PdfWriter
reader = PdfReader("formulario_vacio.pdf")
writer = PdfWriter()
writer.append(reader)
datos = {
"nombre_completo": "Maria Garcia Lopez",
"dni": "12345678A",
"email": "maria@ejemplo.com",
"ciudad": "Madrid",
}
for pagina in writer.pages:
writer.update_page_form_field_values(pagina, datos)
with open("formulario_relleno.pdf", "wb") as f:
writer.write(f)
print("Guardado: formulario_relleno.pdf")
```
### Checkboxes y radio buttons
```python
datos = {
"nombre": "Juan Perez",
"aceptar_terminos": "Yes", # Checkbox: "Yes" = marcado
"sexo": "/Masculino", # RadioButton: valor del widget
"pais": "ES", # ComboBox: valor de opcion
}
for pagina in writer.pages:
writer.update_page_form_field_values(pagina, datos)
```
## Crear formulario PDF desde cero con reportlab
```bash
pip install reportlab
```
```python
from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import A4
def crear_formulario(ruta="formulario_nuevo.pdf"):
c = canvas.Canvas(ruta, pagesize=A4)
ancho, alto = A4
c.setFont("Helvetica-Bold", 18)
c.drawString(50, alto - 60, "Formulario de Registro")
c.setFont("Helvetica", 12)
c.drawString(50, alto - 110, "Nombre:")
c.acroForm.textfield(name="nombre", x=200, y=alto-120, width=300, height=20)
c.drawString(50, alto - 150, "Email:")
c.acroForm.textfield(name="email", x=200, y=alto-160, width=300, height=20)
c.drawString(50, alto - 200, "Acepto terminos:")
c.acroForm.checkbox(name="terminos", x=210, y=alto-210, buttonStyle="check")
c.drawString(50, alto - 250, "Pais:")
c.acroForm.choice(
name="pais",
options=[("ES","Espana"),("MX","Mexico"),("AR","Argentina"),("US","EEUU")],
x=200, y=alto-260, width=200, height=20, value="ES",
)
c.drawString(50, alto - 300, "Genero:")
c.acroForm.radio(name="genero", tooltip="Masculino", x=200, y=alto-310,
buttonStyle="circle", value="Masculino")
c.drawString(225, alto - 305, "Masculino")
c.acroForm.radio(name="genero", tooltip="Femenino", x=300, y=alto-310,
buttonStyle="circle", value="Femenino")
c.drawString(325, alto - 305, "Femenino")
c.save()
print(f"Formulario creado: {ruta}")
crear_formulario()
```
## Rellenar con pdfrw
```bash
pip install pdfrw
```
```python
import pdfrw
def rellenar_pdfrw(entrada, salida, datos):
plantilla = pdfrw.PdfReader(entrada)
for pagina in plantilla.pages:
anotaciones = pagina.get('/Annots') or []
for a in anotaciones:
if a.get('/Subtype') == '/Widget' and a.get('/T'):
nombre = a['/T'][1:-1]
if nombre in datos:
a.update(pdfrw.PdfDict(V=datos[nombre], AP=''))
plantilla.Root.AcroForm.update(pdfrw.PdfDict(NeedAppearances=pdfrw.PdfObject('true')))
pdfrw.PdfWriter().write(salida, plantilla)
print(f"Guardado: {salida}")
rellenar_pdfrw("plantilla.pdf", "relleno.pdf", {
"nombre": "Ana Torres",
"email": "ana@ejemplo.com",
})
```
## Aplanar el formulario (hacerlo estatico)
```python
# Metodo 1: pypdf
from pypdf import PdfReader, PdfWriter
reader = PdfReader("relleno.pdf")
writer = PdfWriter()
for pag in reader.pages:
writer.add_page(pag)
with open("aplanado.pdf", "wb") as f:
writer.write(f)
# Metodo 2: Ghostscript (mas fiel)
import subprocess
subprocess.run([
"gs", "-dNOPAUSE", "-dBATCH", "-sDEVICE=pdfwrite",
"-dFlattenForm", "-sOutputFile=aplanado_gs.pdf", "relleno.pdf"
], check=True)
```
## Extraer datos de un formulario relleno
```python
from pypdf import PdfReader
import json
reader = PdfReader("formulario_relleno.pdf")
extraidos = {}
for nombre, campo in reader.get_fields().items():
valor = campo.get('/V', '')
if hasattr(valor, 'get_object'):
valor = str(valor.get_object())
extraidos[nombre] = str(valor) if valor else ""
print(json.dumps(extraidos, ensure_ascii=False, indent=2))
```
## Herramientas para crear plantillas
| Herramienta | Tipo | AcroForm |
|---|---|---|
| Adobe Acrobat | Pago | Completo |
| LibreOffice Draw | Gratis | Basico |
| PDFescape | Online | Gratis basico |
| reportlab | Python | Programatico |
## Conversion online
Para rellenar o extraer datos de formularios PDF sin Python, KaijuConverter procesa PDFs directamente en el navegador.
Guía