Automatizar QGIS: una tarea, 4 métodos, cronometrados en 2 ciudades
Publicado el
Puedes automatizar un flujo de trabajo repetitivo en QGIS de cuatro formas: Batch Processing (procesamiento por lotes) para una herramienta sobre muchos archivos, el Graphical Modeler (modelador gráfico) para una cadena de herramientas que vas a repetir, un script PyQGIS para bucles y control exacto, o un agente IA dentro de QGIS cuando quieres el resultado con un solo mensaje en lenguaje natural.
Los tutoriales que leí enseñan uno de esos cuatro de forma aislada con un ejemplo de juguete, y ninguno prueba qué pasa cuando ejecutas el flujo por segunda vez en una ciudad nueva. El 7 de noviembre de 2026 tomé una tarea de varios pasos (superficie construida por distrito a partir de 180.602 edificios de OpenStreetMap en Bielefeld, Alemania), la ejecuté con los cuatro métodos en QGIS 3.44.15 y después repetí los cuatro en Münster (135.577 edificios, 6 distritos). Todos los métodos pasaron en ambas ciudades, aunque una ejecución del Graphical Modeler terminó primero con "OK" mientras escribía 1.058 polígonos en lugar de 10.
8.1s
Script PyQGIS en Bielefeld (7,4 s en Münster)
62.7s
Graphical Modeler en QGIS (44,5 s sin interfaz)
60s
AI Agent repite en Münster con 1 frase
1,058filas
Escritas en lugar de 10 por un fallo silencioso del modelo
¿Qué es la automatización en QGIS?
Automatizar QGIS significa ejecutar una herramienta de procesamiento o una cadena de herramientas sobre varias capas sin pasar a mano por cada diálogo. Debajo de todos los métodos está el framework Processing de QGIS, el mismo motor que mueve la caja de herramientas de Processing. Como las herramientas son idénticas tanto si las llamas desde una tabla por lotes, un diagrama del Graphical Modeler, un script de Python o la herramienta de línea de comandos qgis_process, elegir un método de automatización es en realidad elegir cómo quieres conectar esas herramientas y qué archivo quieres dejar en disco para el mes que viene.
La tarea y los datos de la prueba
Elegí un trabajo que aparece constantemente en urbanismo y consultoría: para cada distrito de la ciudad, recortar los edificios al límite del distrito, contar las huellas, sumar su superficie en metros cuadrados, aplicar un buffer de 25 m a los edificios recortados y disolverlos en un único polígono construido, y guardar un GeoPackage limpio con una fila por distrito.
Si un edificio cruza el límite entre distritos, se recorta y se cuenta una vez en cada distrito que toca. Ambas ciudades usan datos de OpenStreetMap de extractos PBF de BBBike (ODbL, colaboradores de OpenStreetMap), reproyectados a EPSG:25832 (ETRS89 / UTM zona 32N) para todas las mediciones.
- Ciudad 1, Bielefeld: 180.602 polígonos de edificios en 10 distritos (
admin_level=9), que dan 115.002 piezas de edificio recortadas. Dos edificios OSM originales tenían geometrías no válidas y se repararon una vez con Fix geometries (Corregir geometrías) para que los cuatro métodos partieran de los mismos archivos limpios. - Ciudad 2, Münster (la repetición): 135.577 polígonos de edificios en 6 distritos, que dan 116.382 piezas recortadas.
Antes de ejecutar cualquiera de los cuatro métodos, escribí una referencia independiente con llamadas de geometría de PyQGIS puro (QgsSpatialIndex, geometry.intersection(), unaryUnion() y buffer(25, 5), sin llamar a algoritmos de Processing) y guardé un script de comprobación. Un método pasaba solo si producía un GeoPackage con una capa de polígonos built_up en EPSG:25832, recuentos exactos de edificios por distrito, superficie de huellas a menos del 0,5 % de la referencia, hectáreas construidas a menos del 1 % y ninguna edición manual posterior.
Método 1: Batch Processing
Cada herramienta de la caja de herramientas de Processing tiene un botón Run as Batch Process (Ejecutar como proceso por lotes) en la esquina inferior izquierda de su diálogo. Convierte el diálogo en una hoja de cálculo donde cada fila es una ejecución de esa única herramienta.
En nuestra tarea, el procesamiento por lotes resuelve bien el Clip por distrito y el Buffer por distrito, porque esos dos pasos repiten exactamente el mismo algoritmo en los 10 distritos. Pero no puede hacer todo el flujo de una vez, porque Batch Processing solo ejecuta una herramienta cada vez y te deja 10 capas de salida separadas que todavía tienes que fusionar y volver a unir.
Reproyectar y dividir las entradas
Ejecuta Reproject layer (Vector general) sobre los edificios a EPSG:25832. Después ejecuta Split vector layer (Vector general) sobre la capa de distritos usando el campo name, que escribe un GeoPackage por distrito en una carpeta.
Ejecutar Clip por lotes en todos los distritos
Abre Clip (Vector overlay), haz clic en Run as Batch Process y añade una fila por cada archivo de distrito. Pon los edificios reproyectados como Input layer, usa Autofill para rellenar las capas de superposición de los distritos y los nombres de las tablas de salida (clip_<district>), y desmarca Load layers on completion. En Bielefeld, las 10 filas terminaron en 13,7 s (de 1,0 a 4,2 s por distrito).
Ejecutar Buffer por lotes con Dissolve activado
Abre Buffer (Vector geometry) en modo por lotes: una fila por capa recortada, Distance 25, Segments 5 y Dissolve result marcado. Los 10 buffers de Bielefeld se ejecutaron en 27,7 s.
Fusionar, agregar y volver a unir la tabla
Ejecuta Merge vector layers dos veces (una sobre las 10 capas de recorte y otra sobre las 10 capas de buffer). Ejecuta Aggregate (Vector geometry) sobre los recortes fusionados agrupando por el campo layer para obtener building_count (count($id)) y building_area_m2 (sum(area($geometry))). Ejecuta Refactor fields (Vector table) sobre los buffers fusionados para calcular built_up_ha con la expresión de la calculadora de campos $area / 10000, y después Join attributes by field value (Vector general) sobre district para producir la capa de salida única.

En las 9 ejecuciones (8 algoritmos distintos), el tiempo total de ejecución de las herramientas en Bielefeld fue de 62,0 segundos, y todos los recuentos por distrito coincidieron con la referencia. En Münster, el tiempo de las herramientas bajó a 39,8 segundos para 6 distritos, pero tuve que reconstruir las tablas por lotes de 6 filas y repetir a mano los 9 pasos. Cuando tu flujo es una cadena de herramientas distintas y no una sola herramienta repetida sobre 50 archivos, Batch Processing no encaja.
Método 2: El Graphical Modeler
El Graphical Modeler (Processing > Graphical Modeler) te permite conectar una cadena de herramientas de Processing en un solo diagrama y guardarlo como archivo .model3. Una vez creado, el modelo aparece en tu caja de herramientas de Processing como cualquier herramienta nativa.
Podrías pensar que necesitas un bucle sobre los distritos dentro del Modeler, pero no hace falta. Si ejecutas primero Intersection entre los edificios y los distritos, cada pieza de edificio hereda el atributo name de su distrito, así que Aggregate y Dissolve agrupados por name producen una fila por distrito en una sola pasada. (También podrías usar una unión espacial si no necesitaras dividir los edificios exactamente en el límite del distrito.)
Añadir las tres entradas del modelo
En un modelo nuevo, añade dos entradas Vector Layer (Polygons) llamadas Buildings y Districts, y una entrada Number llamada Buffer distance (m) con valor por defecto 25.
Reproyectar ambas entradas e intersecarlas
Añade dos nodos Reproject layer con destino EPSG:25832. Conecta ambos a un nodo Intersection (Buildings como Input, Districts como Overlay). En Input fields to keep de Intersection, limita los campos de los edificios a osm_id solamente, y en Overlay fields to keep, conserva name.
Ramificar en Aggregate para los recuentos y Dissolve + Buffer para la geometría
Desde Intersection, conecta una rama a Aggregate agrupado por name para calcular count($id) y sum(area($geometry)). Conecta una segunda rama desde Intersection a Dissolve (campo name) seguido de Buffer (vinculado a tu entrada Buffer distance (m), 5 segmentos).
Unir las ramas y dar formato a la tabla de salida
Añade Join attributes by field value para adjuntar la tabla de Aggregate a los polígonos con buffer sobre name, y después Refactor fields para renombrar name a district y calcular built_up_ha como $area / 10000. Marca la salida como built_up y guarda el modelo como built_up_by_district.model3.

Ejecutar el modelo desde su diálogo en Bielefeld tardó 62,7 segundos y pasó todas las comprobaciones. Mejor aún, el mismo archivo .model3 se ejecutó desde la terminal de macOS sin abrir una ventana de QGIS mediante qgis_process en 44,5 segundos.
La verdadera ventaja apareció en la repetición en Münster. Abrí el mismo diálogo del modelo, seleccioné muenster_buildings y muenster_districts en los dos desplegables e hice clic en Run. Terminó en 67,2 segundos sin ningún cambio en el modelo.

Método 3: Un script PyQGIS en la consola de Python
Si te manejas con Python, un script dentro de Plugins > Python Console > Show Editor te da un bucle for de verdad, las entradas como variables al principio del archivo y ningún paso de fusión.
Este es el script de 38 líneas (built_up_by_district.py) que ejecuté en QGIS 3.44.15, con las rutas de archivo acortadas:
# Built-up area by district. Run in the QGIS Python console (Plugins > Python Console > Show Editor > Run).
# Change the first five lines for a new city.
BUILDINGS = "data/bielefeld_buildings.gpkg"
DISTRICTS = "data/bielefeld_districts.gpkg"
NAME_FIELD = "name"
BUFFER_M = 25
OUT = "out/script/built_up_script.gpkg"
import processing
from qgis.core import (QgsVectorLayer, QgsCoordinateReferenceSystem, QgsFeature, QgsField, QgsFields, QgsGeometry)
from qgis.PyQt.QtCore import QVariant
crs = QgsCoordinateReferenceSystem("EPSG:25832") # metric, Germany
def run(alg, **p):
return processing.run(alg, p)["OUTPUT"]
buildings = run("native:reprojectlayer", INPUT=BUILDINGS, TARGET_CRS=crs, OUTPUT="memory:")
districts = run("native:reprojectlayer", INPUT=DISTRICTS, TARGET_CRS=crs, OUTPUT="memory:")
result = QgsVectorLayer("MultiPolygon?crs=EPSG:25832", "built_up", "memory")
result.dataProvider().addAttributes([QgsField("district", QVariant.String), QgsField("building_count", QVariant.Int),
QgsField("building_area_m2", QVariant.Double), QgsField("built_up_ha", QVariant.Double)])
result.updateFields()
for d in districts.getFeatures():
one = run("native:extractbyexpression", INPUT=districts, EXPRESSION=f"$id = {d.id()}", OUTPUT="memory:")
clipped = run("native:clip", INPUT=buildings, OVERLAY=one, OUTPUT="memory:")
area = sum(f.geometry().area() for f in clipped.getFeatures())
built_up = run("native:buffer", INPUT=clipped, DISTANCE=BUFFER_M, SEGMENTS=5, DISSOLVE=True, OUTPUT="memory:")
geom = next(built_up.getFeatures()).geometry()
f = QgsFeature(result.fields())
f.setGeometry(geom)
f.setAttributes([d[NAME_FIELD], clipped.featureCount(), area, geom.area() / 10000])
result.dataProvider().addFeature(f)
print(d[NAME_FIELD], clipped.featureCount(), round(area), round(geom.area() / 10000, 1))
processing.run("native:savefeatures", {"INPUT": result, "OUTPUT": OUT, "LAYER_NAME": "built_up"})
print("saved", OUT)
El script mantiene todas las capas intermedias en memoria y recorre los distritos en un bucle, y fue con diferencia el método más rápido (no perfilamos por qué). Terminó Bielefeld en 8,1 segundos y coincidió con la referencia independiente al 0.00% en todos los distritos.

Para repetirlo en Münster, cambié tres líneas al principio (BUILDINGS, DISTRICTS y OUT) e hice clic en el botón verde Run Script. Terminó en 7,4 segundos. Si quieres saber en detalle cómo funciona processing.run, consulta nuestra guía de PyQGIS.
Cómo se compararon los cuatro métodos en ambas ciudades
Esto es lo que medimos con los cuatro métodos el 7 de noviembre de 2026:
| Batch Processing | Graphical Modeler | Script PyQGIS | AI Agent (Medium, Balanced) | |
|---|---|---|---|---|
| Preparación / estructura | 9 ejecuciones con 8 algoritmos (2 tablas por lotes de 10 filas) | 3 entradas + 8 nodos de algoritmo + 1 salida | 38 líneas de Python, 5 algoritmos | 1 mensaje en lenguaje natural (27 llamadas a herramientas del agente) |
| Tiempo en Bielefeld (10 distritos) | 62,0 s de tiempo de herramientas (lanzadas una a una) | 62,7 s en el diálogo (44,5 s con qgis_process) | 8,1 s (tras corregir 1 llamada de guardado fallida) | 110 s desde Send hasta la tabla de respuesta |
| Repetición en Münster (6 distritos) | 39,8 s de tiempo de herramientas (reconstruir filas y las 9 ejecuciones) | 67,2 s (elegir 2 capas nuevas, clic en Run) | 7,4 s (cambiar 3 líneas de rutas, clic en Run) | 60 s (1 mensaje de seguimiento de 46 palabras, 15 llamadas a herramientas) |
Mayor diferencia con la referencia (built_up_ha) | +0,08 % | +0,08 % | 0,00 % | +0,21 % |
| Qué te queda después | ~20 capas intermedias | Un archivo .model3 (se ejecuta en la interfaz o sin ella) | Un archivo de script .py | El historial del chat y el texto de tu prompt |
Todos los métodos coincidieron con los recuentos de edificios y las superficies de huellas de la referencia (building_area_m2) al 0.00%. La diferencia de +0.08% en built_up_ha de Batch Processing y el Graphical Modeler viene de que $area en Refactor fields mide sobre el elipsoide del proyecto, mientras que el script y la referencia usaron geometry().area() plana en EPSG:25832.
Qué falló por el camino (incluida una respuesta errónea silenciosa)
Los tutoriales casi nunca muestran las ejecuciones que fallan, así que anoté cada error durante el día. El fallo más inquietante no fue un cierre ni un aviso de error en rojo: fue una ejecución del Graphical Modeler que informó de éxito y dio una salida errónea.
Cuando ejecuté el modelo por primera vez sin interfaz, antes de limitar los campos en el nodo Intersection, el registro mostró:
Model processed OK. Executed 8 algorithm(s) total in 84.548 s.
Ni un error, ni un aviso. Cuando revisé el GeoPackage de salida, built_up tenía 1.058 polígonos en lugar de 10.
La razón: los edificios de OpenStreetMap tienen su propia columna name (el nombre de una tienda, una escuela o una iglesia), y la capa de distritos también tiene una columna name. Cuando Intersection combinó todos los campos de ambas capas, el name de los edificios siguió siendo name y el name del distrito se renombró en silencio a name_2. Más abajo, Aggregate y Dissolve agruparon por name, ¡así que agruparon por nombres de edificios en lugar de distritos! Limitar Input fields to keep de Intersection a osm_id evitó la colisión y devolvió la salida a los 10 distritos.
Otras tres cosas fallaron y conviene conocerlas antes de automatizar tus propios datos:
- Las geometrías OSM no válidas detienen Processing por defecto. Dos de los 180.602 edificios de Bielefeld tenían anillos que se autointersecaban. Con la configuración por defecto de QGIS, Clip se detiene de inmediato con
Feature (18818404) from 'b' has invalid geometry. Ejecuta Fix geometries como primer paso siempre que tu entrada venga de OpenStreetMap en bruto. savefeaturesen PyQGIS no se lleva bien con las cadenas de conexión de GDAL. En mi primera ejecución del script (10,0 s), pasarogr:dbname='...' table="built_up"anative:savefeatureslanzóOGR driver for '' not found. Pasa la ruta.gpkgsimple enOUTPUTy ponLAYER_NAME: "built_up"como parámetro aparte.- Cargar muchas capas intermedias hizo caer nuestra sesión. QGIS se cerró (
SIGSEGV) tres veces mientras las salidas de Processing se cargaban en el árbol de capas con Load layers on completion marcado. Desmarcarlo en las filas intermedias por lotes acabó con los cierres.
Método 4: Pedírselo a un agente IA dentro de QGIS
Nosotros desarrollamos AI Agent, así que esta sección trata de nuestro propio plugin. Acopla un panel de chat dentro de QGIS, inspecciona las capas y campos que ya tiene tu proyecto, llama él mismo a las herramientas de Processing de QGIS y a PyQGIS, y comprueba la salida antes de responder.
Para un trabajo puntual o un proyecto de dos ciudades, crear un modelo gráfico de 8 nodos o depurar un script de 38 líneas suele ser más preparación de la que merece la tarea. Abrí un proyecto con las capas buildings y districts de Bielefeld, puse el panel en esfuerzo Medium y permisos Balanced, y envié un mensaje:
The project has two layers: "buildings" (OSM buildings of Bielefeld, Germany) and "districts" (its 10 city districts, the district name is in the field "name"). For each district: clip the buildings to the district, count the buildings, sum their footprint area in square meters, and build a 25 m buffer around the clipped buildings, dissolved into one built-up polygon, with its area in hectares. Measure in a metric CRS (EPSG:25832). Write one GeoPackage at [output folder]/built_up_agent.gpkg with a single polygon layer named built_up, one feature per district, fields district, building_count, building_area_m2, built_up_ha, in EPSG:25832. Then show me the result table.
(Rutas de salida acortadas en ambos prompts. Nota de transparencia: en el primer intento, QGIS se cerró 9 segundos después de hacer clic en Send por un segfault en un slot de Qt antes de que llegara ninguna respuesta. Volví a abrir el proyecto, envié exactamente el mismo prompt una vez y no lo reenvié después.)
En 110 segundos, el agente hizo 27 llamadas a herramientas (12 run_processing, 7 get_algorithm_help, 4 execute_code, 2 get_layer_info, 1 export_layer, 1 get_features), se recuperó solo de un error interno de Processing sin mostrar una tarjeta de permiso, escribió el GeoPackage e imprimió la tabla de los 10 distritos en el chat. Sin que se lo pidiera, también señaló en su respuesta: "Los buffers de 25 m pueden extenderse más allá de los límites de los distritos y solaparse."

Después arrastré muenster_buildings y muenster_districts al proyecto y escribí un mensaje de seguimiento de 46 palabras en el mismo chat:
Now do the same for Münster. I added two layers: "muenster_buildings" and "muenster_districts" (6 districts, the name is in the field "name"). Same fields and same 25 m buffer, in a new GeoPackage at [output folder]/built_up_agent_muenster.gpkg with the layer named built_up. Then show me the result table.
Con la primera prueba en el mismo chat, el agente terminó Münster en 60 segundos con 15 llamadas a herramientas (11 run_processing, 1 export_layer, 1 get_features, 1 zoom_to_layer, 1 execute_code) y ningún error.

Todos los recuentos de edificios y superficies de huellas coincidieron con la referencia al 0.00% en ambas ciudades.
¿Dónde están los límites? Primero, los valores de built_up_ha del agente quedaron entre un 0.07% y un 0.21% por encima de la referencia plana (por ejemplo, Brackwede salió con 1,390.51 ha frente a 1,388.31 ha en la referencia; no medimos qué paso interno causó esa pequeña diferencia). Segundo, el GeoPackage exportado conservó una columna _export_fid de más. Tercero, y lo más importante para automatizar: el agente planifica sus pasos de nuevo en cada mensaje (27 llamadas a herramientas en Bielefeld, 15 en Münster) y funciona dentro de una sesión de QGIS abierta, así que no te deja un archivo .model3 o .py que puedas programar sin supervisión con cron.

¿Qué método de automatización de QGIS elegir?
En lugar de tratar una herramienta como la ganadora, elige el método según la frecuencia con la que vas a repetir el trabajo:
- Ejecutas exactamente la misma herramienta sobre 10 a 100 archivos: usa Batch Processing. Viene integrado en cada diálogo de Processing, no cuesta nada y no requiere código. Deja de usarlo en cuanto tu flujo encadene tres o cuatro herramientas distintas.
- Tú o tu equipo vais a ejecutar una cadena de varios pasos cada mes, o de forma programada en un servidor: créala en el Graphical Modeler. Obtienes un único archivo
.model3que puedes compartir con colegas que no escriben Python, y puedes ejecutarlo sin interfaz desde un script de shell o una tarea programada medianteqgis_process. - Necesitas bucles a medida, control plano exacto o la máxima velocidad de ejecución: escribe un script PyQGIS. Nuestro script de 38 líneas fue de 8 a 9 veces más rápido que el Modeler en ambas ciudades.
- Tienes una tarea compleja que ejecutar una vez, dos, o en unas pocas variantes de proyecto hoy: usa un agente IA dentro de QGIS como AI Agent (o consulta nuestra visión general en el hub de IA para QGIS). Te ahorras buscar los nombres exactos de las herramientas y repites en una segunda ciudad con una frase. El plan Free da 5 tareas al mes con esfuerzo Low; estas pruebas se hicieron con Medium, que viene con Pro (49 EUR / mes sin IVA, 300 tareas).
Cómo lo medimos. Todas las pruebas se hicieron el 7 de noviembre de 2026 en un Mac con Apple Silicon (macOS 27.0.1, arm64) en una sesión aislada de QGIS 3.44.15-Solothurn (Python 3.12.11) con AI Agent 1.9.4 (esfuerzo Medium, modo Balanced). La carga de la máquina varió durante el día, así que compara los tiempos como órdenes de magnitud, no como benchmarks de CPU. Medimos el tiempo real de ejecución de la máquina y el número de pasos, no los minutos que tarda una persona analista SIG en montar un modelo o escribir un script desde cero. Todas las entradas, el archivo .model3, los scripts .py, el comprobador de referencia y los registros JSON en bruto están guardados en nuestro archivo del experimento.
Preguntas frecuentes
¿Cómo automatizo un flujo de trabajo repetitivo en QGIS?
Tienes cuatro opciones principales según la frecuencia con la que se repite el trabajo. Para una sola herramienta sobre muchos archivos, haz clic en Run as Batch Process dentro del diálogo de la herramienta. Para una cadena de varios pasos que vas a repetir con regularidad, conecta las herramientas en Processing > Graphical Modeler y guarda un archivo .model3. Para bucles y el mejor rendimiento, escribe un script de Python con processing.run() en la consola de Python de QGIS. Para análisis puntuales o de pocas veces en los que no quieres conectar nodos ni escribir código, describe el flujo con palabras sencillas en un plugin de agente como AI Agent.
¿Uso el Graphical Modeler de QGIS o Python (PyQGIS)?
Usa el Graphical Modeler cuando tu flujo es una cadena directa de algoritmos de Processing y quieres un archivo .model3 visual que puedan abrir en tu equipo personas que no programan, o que puedas ejecutar desde la línea de comandos con qgis_process. Usa PyQGIS cuando necesites recorrer entidades en un bucle, mantener capas intermedias en memoria (el script tardó 8,1 s frente a 62,7 s del modelo en nuestra prueba de Bielefeld), gestionar errores en código o controlar de forma explícita los esquemas de salida.
¿Puedo exportar un modelo gráfico de QGIS a un script de Python?
Sí. El Graphical Modeler puede exportar un modelo como script de Processing en Python (Export as Script Algorithm), que luego puedes editar para añadir bucles, variables o lógica propia. No probamos la exportación en esta comparación.
¿Puede QGIS ejecutar flujos automatizados de forma programada sin abrir la aplicación?
Sí. QGIS incluye una utilidad de línea de comandos llamada qgis_process. Puedes pasarle cualquier algoritmo nativo o cualquier archivo .model3 guardado (por ejemplo, qgis_process run model3 --BUILDINGS=... --DISTRICTS=... --built_up=...) desde un script de bash, el Programador de tareas de Windows o una tarea de cron sin abrir la interfaz gráfica de QGIS. En nuestra prueba de Bielefeld, el modelo se ejecutó sin interfaz con qgis_process en 44,5 segundos.
Sigue leyendoQué es PyQGIS: automatiza QGIS con o sin código
Hazlo en QGIS pidiéndoselo
AI Agent realiza la tarea que describes, en tu propio proyecto de QGIS. Gratis, sin tarjeta.
de cuatro formas: Batch Processing (procesamiento por lotes) para una herramienta sobre muchos archivos, el Graphical Modeler (modelador gráfico) para una cadena de herramientas que vas a repetir, un script 

