Notas de ingeniería · Datos abiertos
Cuarenta años de marcas españolas, seis ficheros rotos y un endpoint que se rindió
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.