BORME API

Notas de ingeniería · Datos abiertos

Cuarenta años de marcas españolas, seis ficheros rotos y un endpoint que se rindió

2026-08-24 · 7 min · nota de campo

El Registro Mercantil dice cómo se llama una empresa. No dice cómo se la conoce *en la factura*. Un grupo de restauración constituido como BARROCO MV SOCIEDAD LIMITADA opera como DON PABLO; la escritura y el rótulo no comparten nada. Para quien tiene que enlazar un cliente, un proveedor o un lead con una persona jurídica, ese hueco es el problema entero.

La OEPM publica el puente. Todas las marcas y nombres comerciales españoles desde 1987 están disponibles en masa, gratis, en XML según ST.66 de la OMPI, y el nombre comercial es justamente la arista que le falta al registro. Acabamos de cargarlo todo: 1.335.777 derechos, vinculados a 182.728 empresas.

Casi nada del trabajo fue analizar XML.

Los archivos no terminan

Cada año es un ZIP. Treinta y tres de los treinta y nueve llegaron íntegros. Seis no — y son los seis más pesados, de 2016 a 2021:

2016   756 MB   truncado
2017   771 MB   truncado
2018   441 MB   truncado
2019   278 MB   truncado
2020   347 MB   truncado
2021   468 MB   truncado

El tamaño no lo explica: 2022 pesa 850 MB y llega entero siempre. Nada da error. La descarga termina, el fichero *está ahí*, y unzip responde:

End-of-central-directory signature not found.

Un ZIP guarda su índice al final. Si se pierde la cola, se pierde el índice, y cualquier herramienta estándar rechaza el fichero completo — incluida la parte que llegó perfecta. zipfile de Python lanza BadZipFile y no devuelve nada.

Pero un ZIP también es un flujo. Cada miembro lleva su propia cabecera local, y un flujo deflate anuncia dónde acaba:

i = blob.find(b"PK\x03\x04", off)
n, m = struct.unpack("<HH", blob[i + 26:i + 30])
name  = blob[i + 30:i + 30 + n].decode("latin-1")
start = i + 30 + n + m
d = zlib.decompressobj(-15)
data = d.decompress(blob[start:])
off = len(blob) - len(d.unused_data)   # donde empieza la siguiente cabecera

Eso recuperó 282.464 registros de un fichero que las herramientas daban por basura.

Cada reintento corta en otro punto

Aquí está lo que convirtió un apaño en estrategia. Si vuelves a descargar un año truncado, vuelve a truncarse — pero no en el mismo sitio. 2019 llegó a 278 MB, luego a 436 MB, luego a 836 MB, y por fin entero a 857 MB. Cada intento trae un subconjunto distinto de días.

Lo que convierte la forma del cargador en la decisión importante: upsert, nunca insert. Cada pasada rellena los huecos de la anterior, y las pasadas convergen:

derechos de 2019 tras la pasada 1:  37.930
                 tras la pasada 2:  49.986   (+12.056)
                 tras la pasada 3:  62.226   (+12.240)
                 tras la pasada 4:  62.238   (+12)

La regla que sale de ahí: volver a descargar mientras el recuento siga creciendo. En la cuarta pasada 2019 sumó doce filas de sesenta y dos mil, y el año estaba completo. Si nos hubiéramos quedado en el primer resultado de aspecto correcto, ese año seguiría en la base de datos sin el cuarenta por ciento de sí mismo, y nada en el fichero lo habría indicado.

Los nombres dejan de venir el 1 de octubre de 2023

Hasta esa fecha, cada marca viaja con su APPLICANT-*.xml al lado: nombre, domicilio, localidad, provincia, todo dentro del archivo. Desde el 2 de octubre de 2023 los archivos llevan solo DATA-*.xml, y el titular vive detrás de una petición HTTP por solicitante.

Encontramos la frontera recorriendo un año día a día:

10/20231001.zip   APPLICANT presente
10/20231002.zip   solo DATA

Esa única fecha decide lo que cuesta un backfill completo. Todo lo anterior — unas nueve décimas partes del corpus — son descargas y CPU. Todo lo posterior es una petición por titular, y la clave está ligada al expediente (M4398660-001 es el primer solicitante *de esa solicitud*), así que una empresa con veinte marcas cuesta veinte peticiones. No hay nada que cachear.

Y entonces el endpoint dejó de responder

Resolvimos un año entero — 202.748 peticiones en unas dos horas y media — y fue bien. A la mañana siguiente, el mismo endpoint:

M4398617-001  HTTP 200  3,8s
N0503712-001  HTTP 503  7,2s
M4379229-001  HTTP 503  7,1s
M3625606-003  HTTP 200  7,0s
M2365972-001  HTTP 404  7,3s   ← esta clave devolvió datos el día anterior
M4398660-001  HTTP 200  6,1s

Un tercio rechazando, un 404 falso, todo seis segundos lento. Bajamos de diez hilos a tres; siete minutos de ejecución escribieron cero filas. Esa es la señal de que no es tu ritmo: aflojar debería reflejarse de inmediato en menos errores, y no lo hizo.

Lo hayamos provocado nosotros o simplemente llegado durante el episodio, la respuesta es la misma — parar y usar otra puerta. La oficina concede acceso a un servicio SOAP previa solicitud, y ese responde en dos segundos y devuelve *más*: la provincia, el porcentaje de titularidad, si el titular es empresa o persona. Devuelve menos de una sola cosa — los cosolicitantes — así que esas filas se quedan vacías en lugar de rellenarse a ojo.

Tres maneras en que los datos mienten en voz baja

Los registros anteriores a ~2016 no declaran modalidad. No hay elemento <IPRKind>. La modalidad está en el número de expediente: M es marca, N nombre comercial, R rótulo de establecimiento. Si no se lee ahí, todos los nombres comerciales de los años antiguos — justo la parte que interesa — se convierten en silencio en filas sin clasificar.

Ocho ficheros traen el año sin su siglo. 0022-02-15 para una marca solicitada en 2022, 0216-02-10 para otra de 2016. Adivinar el siglo no es seguro. Publicar la errata a quien está comprobando una empresa es peor. Ambos campos se dejan vacíos, con un suelo en 1826 — el año de la primera concesión española.

Un tercio de los nombres comerciales es el propio nombre de la empresa. TEAM DENTAL LAB en manos de TEAM DENTAL LAB SL. Guardar eso infla la capa con enlaces que no enseñan nada, porque la normalización de nombres ya los encuentra. Los descartamos — 59.051 — y conservamos los dos tercios reales:

EDICIONES PLAN B          → EDICIONES LITERARIAS INDEPENDIENTES SL
TODOPARATUINDUSTRIA.COM   → HIDROTECNIA DE COMPONENTES SL
FSA                       → FREIXENET SA
Cortijo Los Santeros      → PBS Y LEGADO SOCIEDAD LIMITADA

Cuánto vale

424.143 enlaces entre una marca y la empresa que la ostenta, sobre 182.728 empresas. El sesenta por ciento de esas empresas no tiene NIF en nuestros datos — son las inactivas, las pequeñas y las que nunca contrataron con la administración, la parte del registro más difícil de identificar por cualquier otra vía.

Y una cosa que la oficina no publica en ningún canal, ni masivo ni API: el NIF. Ni en los ficheros ST.66, ni tras el endpoint de solicitantes, ni en el boletín, ni en la especificación del servicio web. Cada enlace de aquí se hace sobre un nombre normalizado, y cada respuesta que servimos lo dice. Una marca es evidencia sobre una empresa. No es identidad, y esa diferencia es el producto.

build 2026.08.24·f5282ee-dirty