AIREITER

Imagen IA

FLUX.2 ProGPT-Image 2Wan 2.7 Image ProGPT 4o ImageSeedream 5.0 ProSeedream V5 liteSeedream V4.5Más

Video IA

Kling 3.0 Motion ControlSora 2 ProKling 3.0 TurboSora 2Kling 3.0Grok Imagine 1.5Veo 3.1Más

LLM

Gemini 3.6 FlashGemini 3.1 ProKimi K3Gemini 3 ProGemini 2.5 ProClaude Opus 5Claude Fable 5Más
PróximamenteSeedance 2.5
Super ResolutionLyric Video GeneratorGPT Image 2 1K GeneratorGPT Image 2 Product Mockup GeneratorUse GPT-5.6 Online
DOCS APIPRECIOS
BlogActualizacionesLLM API GuideClaude API GuideKimi K3 API Guide
PLANTILLAS
  • AIReiter
  • Blog
  • La inteligencia publicitaria B2B solo sale del HTML: cómo crear un parser que resista rediseños

La inteligencia publicitaria B2B solo sale del HTML: cómo crear un parser que resista rediseños

Última actualización: 2026-07-31 07:00:57

Quieres saber en qué países se está anunciando un competidor B2B este trimestre, cuánto tiempo lleva activo, qué volumen aproximado de impresiones está generando y qué segmentos de audiencia está atacando. Toda esa información está en su biblioteca pública de anuncios, que muchas plataformas deben publicar para cumplir con las normas de transparencia publicitaria. Pero abres DevTools, investigas un rato y no aparece ningún endpoint JSON limpio: solo una página completa de HTML renderizado en servidor. Escribes un parser, funciona y obtienes los datos. Tres semanas después, la plataforma rediseña la interfaz y el parser deja de extraer todos los campos sin lanzar ni un error. Devuelve silenciosamente un montón de valores vacíos, y casi tomas una decisión basándote en datos inexistentes.

Este artículo trata de cómo mantener vivo un parser de este tipo después de un rediseño y de dónde encaja realmente un modelo en su mantenimiento. Antes, el límite de los datos: todo lo que se menciona aquí procede de la biblioteca pública de anuncios y del creative center de cada plataforma, accedidos tras iniciar sesión de forma normal con tu propia cuenta. No se usan firmas, no se elude nada y no se accede a endpoints no públicos. Como veremos, esa frontera forma parte explícita del diseño del parser.

Por qué la inteligencia publicitaria B2B acaba dependiendo del HTML

Incluso entre las bibliotecas de anuncios hay tres formas de exponer los datos: algunas orientadas a consumo, como la biblioteca de anuncios de Meta, ofrecen búsquedas estructuradas y JSON; otras exigen una sesión incluso para buscar; y la mayoría de las plataformas B2B solo sirven HTML renderizado en servidor, sin ningún endpoint JSON. La diferencia de fondo es sencilla: estas bibliotecas existen por cumplimiento normativo, no como una API de producto.

Su objetivo es cumplir con la regulación de transparencia publicitaria, no atender llamadas de desarrolladores. No tienen número de versión, changelog ni promesa de compatibilidad hacia atrás. La página está pensada para personas; el servidor la renderiza y entrega HTML, y la única «API» disponible es la propia web.

Eso las vuelve frágiles por definición: dependes de detalles de implementación de una interfaz ajena, pueden cambiarlos cuando quieran y no tienen obligación de avisarte. En una API JSON, cambiar un campo al menos cuenta como un cambio; para quien mantiene una interfaz HTML, un rediseño no es más que una iteración rutinaria de frontend. No puedes evitarlo. Lo único que puedes hacer es diseñar el parser para que falle de forma controlada y se pueda reparar rápido tras un rediseño, en lugar de devolver valores vacíos en silencio.

Un parser en streaming reduce más carga mental que código

El primer impulso suele ser tirar de lxml o BeautifulSoup, construir el árbol DOM completo de la página y encadenar .find() hasta llegar a cada dato. Puede funcionar, pero para este objetivo no es la mejor elección. El árbol DOM es un producto intermedio del navegador al renderizar la página —MDN define el DOM como el análisis de un documento en un árbol de nodos al que los scripts acceden por su estructura—, mientras que aquí solo necesitas extraer unos pocos campos. No necesitas ese árbol y tampoco conviene atarte a su estructura.

La solución a la que llegué fue una subclase de HTMLParser de la biblioteca estándar de Python: algo más de ochocientas líneas, 881 para ser exactos, y completamente en streaming. Unas pocas callbacks de starttag / data / endtag alimentan una máquina de estados que acumula información mientras recorre el HTML. Al llegar al límite de una tarjeta, emite un registro, limpia el estado y sigue adelante, sin construir nunca un árbol DOM completo.

El ahorro del streaming es tangible. Primero, memoria: el HTML de una página de detalle puede ocupar fácilmente de decenas a cientos de KB; un árbol DOM mantiene en memoria toda la estructura, mientras que el streaming solo conserva el estado de «dónde estoy escaneando y cuánto llevo de esta tarjeta». Pero el ahorro más importante es la carga mental. En cuanto escribes .find('div').find('div')[2], has vinculado el parser a una posición jerárquica del DOM. Y la jerarquía es justo lo que un rediseño suele alterar: basta con añadir un contenedor o separar un wrapper para que se desplacen todas las posiciones. Una máquina de estados te obliga a plantear otra pregunta: «¿esto que estoy leyendo es, semánticamente, el inicio de una tarjeta, una cifra de impresiones o una etiqueta de segmentación?». La posición cambia; la semántica, mucho menos.

Tres decisiones para sobrevivir a un rediseño

Todo se resume en tres principios, aprendidos a base de rediseños.

El primero: ancla el parser a la semántica, no a la posición. La máquina de estados debe avanzar mediante señales semánticas: el texto de una etiqueta de campo, palabras legibles como «impresiones totales» o «fechas de publicación», marcadores con roles relevantes o el límite semántico de un bloque. Nunca por algo como «el tercer nodo desde arriba». La prueba cabe en una pregunta: si mueven este elemento o le añaden otra capa contenedora, ¿el parseo sigue funcionando? Si la respuesta es sí, el ancla es válida. Las anclas posicionales se rompen con el primer rediseño; las semánticas sobreviven a la mayoría de cambios puramente visuales.

El segundo: si falta un campo, degrada; no lances una excepción. Antes de acumular los datos de cada tarjeta, inicializa una plantilla con valores vacíos para todos los campos: cadena vacía para texto, None para números y arrays vacíos para listas. Rellena lo que puedas y deja vacío lo que no. Que falle la extracción de un único campo no debe invalidar toda la tarjeta, y mucho menos toda la página. Si a un anuncio le falta el copy de CTA, aún quieres conocer sus impresiones y los países a los que se dirige. Permitir que un dato secundario ausente destruya la inteligencia que sí podía extraerse de la página es el peor diseño posible.

El tercero: marca la completitud de los resultados para que «vacío» y «roto» no parezcan lo mismo. Es el más fácil de pasar por alto y el más caro. «Se han parseado 0 anuncios» puede significar dos cosas totalmente distintas: que realmente no había anuncios, porque ese anunciante no publicó ninguno este trimestre, o que la estructura de la página cambió y el parser ya no encuentra ningún ancla. Ambos casos deben distinguirse en el valor de retorno. La forma de hacerlo es adjuntar evidencias de contraste: el número de tarjetas capturadas, el total declarado por la propia página y el estado de la paginación. Así, una combinación como «0 tarjetas, pero los metadatos de la página indican que debería haber un lote y no aparece marcador de página siguiente» puede identificarse como un cambio de estructura, en lugar de como una ausencia real, y lanzar un error claro en vez de devolver una lista vacía sin más.

El límite de datos mencionado antes también se aplica en esta capa: el parser comprueba si ha sido redirigido a una página de inicio de sesión y, en cuanto detecta que el título corresponde a una página de login o registro, falla explícitamente en lugar de seguir parseando. Solo trata páginas públicas que puedes ver normalmente con tu propia cuenta; se detiene ante un muro de inicio de sesión y nunca intenta atravesarlo.

El valor está en las dimensiones de filtrado

A estas alturas podrías pensar que el objetivo es extraer perfectamente todos los campos de cada anuncio. No lo es. Los campos de un anuncio aislado tienen poco valor por sí mismos; lo que de verdad importa son las dimensiones con las que puedes segmentar ese conjunto de anuncios. Los filtros de búsqueda de la biblioteca publicitaria ya son, en la práctica, una lista de dimensiones de inteligencia. Si los conviertes en parámetros de consulta programables, no obtienes «un anuncio», sino «la porción de lanzamiento de un competidor»:

  • País: en qué mercados se anuncia y en cuáles no. Que una empresa B2B empiece de repente a anunciarse en un país puede revelar una expansión antes de que su propia web lo refleje.

  • Ventana de publicación, con fecha de inicio y fin: cuánto tiempo estuvo activa una creatividad. Un anuncio que se mantiene mucho tiempo es una señal especialmente fuerte, porque nadie sigue pagando por una creatividad que no convierte. Su duración es, por sí misma, el resultado de una prueba A/B validada con dinero real y ejecutada por la otra parte.

  • Rango de impresiones, mínimo y máximo: una aproximación al gasto. El valor absoluto no es preciso, pero basta para ordenar cuáles son las compras publicitarias prioritarias.

  • Facetas de segmentación: qué criterios de targeting se incluyen o excluyen. Es la inteligencia de audiencia más directa: a quién cree el competidor que puede venderle su producto.

Extraer campos es el medio; estas dimensiones son el fin. Al escribir el parser, piensa al revés: para consultar y ordenar por estas dimensiones, ¿cuál es el conjunto mínimo de campos que necesito extraer de forma fiable? Los demás campos vistosos pueden quedarse fuera sin perjudicar la inteligencia obtenida.

Tras un rediseño, usa el modelo para comparar el HTML antiguo y el nuevo

Un parser así acabará rompiéndose con algún rediseño. Ahí es donde realmente encaja un modelo, y no dentro del propio parseo. Parsear es trabajo determinista: una máquina de estados codificada de forma explícita. No conviene meter llamadas a un modelo en ese flujo (no delegues trabajo determinista a un modelo; es el mismo principio que en la línea de ingeniería inversa). El trabajo del modelo es el mantenimiento.

El flujo es este: abre la biblioteca de anuncios con tu propia cuenta, conserva una copia del HTML guardado antes del rediseño y otra del HTML nuevo, entrégaselos al modelo junto con la lista de campos que extrae el parser actual y pídele que identifique, comparando ambas versiones, qué anclas semánticas cambiaron, cuál debería ser la nueva ancla y qué pocas líneas habría que modificar. Es un caso de manual para una capa de razonamiento: debe localizar si la semántica equivalente sigue existiendo en la nueva estructura y proponer un plan aplicable, no limitarse a decir que «la estructura se ha ajustado». Cada etapa exige capacidades distintas; usar una única capa para todo implica pagar de más o perder precisión:

Etapa

Capacidad necesaria

Elección

model id

Leer una página completa de HTML SSR y alinear la estructura antigua con la nueva

Contexto largo, capaz de absorber de una vez una página de detalle de decenas a cientos de KB

Kimi K3

kimi-k3

Tras un rediseño, leer el diff entre ambas versiones, determinar dónde se desplazó el ancla y proponer el cambio mínimo

Razonamiento sólido, que explique a partir de la estructura en vez de repetir el fenómeno

Claude Opus 5

claude-opus-5

Normalizar y etiquetar en bloque las tarjetas de cientos de anunciantes para convertirlas en inteligencia

Bajo coste, cientos o miles de llamadas con alta concurrencia

Claude Sonnet 5

claude-sonnet-5

Atribuir diferencias cuando falla la comparación de fixtures

Razonamiento intermedio, que explique «campo esperado frente a extracción real»

GPT-5.6 Sol

gpt-5.6-sol

La segunda capa es el núcleo y la única etapa en la que cambiar de modelo modifica el resultado de forma visible. No tienes por qué creerme sobre si merece la pena pagar por una capa de razonamiento: pruébalo. El protocolo es corto:

  1. Guarda el HTML de una página antes de un rediseño y otro después de él; abre la biblioteca de anuncios con tu propia cuenta y guarda la página.

  2. Entrega ambos HTML y la lista de campos del parser actual a claude-opus-5 y gpt-5.6-sol.

  3. Fíjate en una sola cosa: ¿la corrección señala un cambio concreto en un ancla semántica —«antes se anclaba a la etiqueta “impresiones totales”, el rol del contenedor de esa etiqueta cambió en la nueva versión, cámbialo para anclarte a X»— o se queda en un vago «la estructura se ha ajustado, recomendamos readaptar»?

  4. La primera respuesta se puede aplicar directamente; la segunda no dice nada útil. Esa diferencia es tu criterio de selección y determina cuántas rondas de prueba a ciegas tendrás que hacer el día del rediseño.

Una sola ronda basta para ver la diferencia, con más claridad que cualquier benchmark.

El verdadero freno es el coste de cambiar de proveedor

Las cuatro capas proceden de tres proveedores, tres SDK y tres esquemas de autenticación, además de tres formatos de error. Configurar tres clientes para distintas etapas hace que la mayoría calcule el esfuerzo, decida que no compensa para «alguna reparación ocasional del parser y limpieza masiva de datos» y termine usando un único modelo para todo. Así, para arreglar un rediseño acaban con una capa que solo responde «recomendamos readaptar», perdiendo tiempo sin saber por qué.

AIReiter aplana esa capa: una clave, una interfaz compatible con OpenAI y las cuatro capas detrás. Para cambiar entre ellas, basta modificar el campo model del cuerpo de la solicitud.

# Reparación tras un rediseño: la capa de razonamiento
curl https://aireiter.com/api/v1/chat/completions \
  -H "Authorization: Bearer $AIREITER_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "claude-opus-5",
    "messages": [{"role": "user", "content": "<diff del HTML antiguo y nuevo + lista de campos actual; pide localizar el desplazamiento del ancla>"}]
  }'

# Normalización masiva de inteligencia: cambia el campo model y deja lo demás igual
#   "model": "claude-sonnet-5"
# Contexto largo para leer la página completa: "model": "kimi-k3"
# Atribución de diferencias:                    "model": "gpt-5.6-sol"

Si ya utilizas el SDK de OpenAI, apunta base_url a https://aireiter.com/api/v1 y no cambies nada más. Con el SDK de Anthropic, usa POST /api/v1/messages con la misma clave.

En precio, los modelos Claude tienen un 30% de descuento sobre tarifa, los modelos GPT cuestan la mitad y Kimi K3 se puede invocar con la misma clave. En este flujo, el descuento se aplica justo donde está el coste principal. No es la reparación tras un rediseño, que es una llamada ocasional, poco frecuente y de alto valor; es la normalización masiva de inteligencia. Supervisas veinte anunciantes competidores, con decenas o cientos de tarjetas cada uno, y se las pasas todas al modelo para extraer propuesta, audiencia y ventana de publicación. Esa es la parte con mayor densidad de llamadas y se ejecuta con Claude Sonnet al 30% de descuento. La entrada de contexto largo para leer una página completa y alinear estructuras es la siguiente más intensa. Las dos partes más caras coinciden directamente con el descuento.

  • Obtén una API key

  • Pruébalo sin registrarte: entrega manualmente una pareja de HTML antes y después a ambos modelos y compara cuál identifica de verdad dónde se desplazó el ancla; después decide si te interesa integrarlo.

Una vez reparado el parser y normalizadas las tarjetas en bloque, el siguiente paso es alimentar el pipeline creativo para tomar decisiones y generar activos. Ese es el trabajo de el ciclo completo desde la keyword hasta el anuncio terminado; este artículo cubre su tramo inicial: extraer de forma fiable datos públicos.

La última palabra sobre los campos correctos la tiene el fixture

La corrección que propone el modelo no deja de ser una sugerencia hasta que la validas. Puede decir que «el ancla debería cambiar a X» y sonar razonable, pero nada garantiza que X funcione en todas las tarjetas. Los anuncios B2B pueden ser de imagen y texto, solo texto, carrusel, con landing page o sin ella; las dos muestras que revisó el modelo quizá no cubran todas esas variantes.

Lo que evita este problema es lo mismo que frena las alucinaciones de un modelo en ingeniería inversa: una comparación de vectores fijos. Guarda como fixture, versionado en el repositorio, un lote de entradas conocidas —unas cuantas páginas HTML reales guardadas— junto con sus salidas correctas conocidas —los resultados de campos que verificaste manualmente una vez—. Cada vez que cambies el parser, tanto si lo haces por tu cuenta como siguiendo la propuesta del modelo, vuelve a ejecutar ese lote de fixtures y compara campo a campo. Es lo único que permite distinguir rápidamente, tras un rediseño upstream, entre «apliqué mal la sugerencia» y «la página volvió a cambiar»: si todo pasa, el cambio es correcto; si fallan unos pocos casos, los campos de esos casos indican directamente en qué capa está el problema. El modelo genera sugerencias de reparación; el fixture decide si son correctas. No deben mezclarse ambos papeles. El método completo de esta comparación diferencial se explica en el artículo sobre pruebas diferenciales, y el parser de bibliotecas publicitarias aplica la misma barrera. Sin esta capa, estarías tomando la confianza del modelo como corrección. Es muy fácil «aplicar la sugerencia, no ver errores, desplegar y descubrir tres días después que los datos de un país llevaban todo el tiempo vacíos».

En resumen

La inteligencia publicitaria B2B solo puede extraerse del HTML porque la biblioteca de anuncios es un artefacto de cumplimiento, no una API de producto: no hay contrato de API y los rediseños pueden llegar en cualquier momento. La resistencia al desgaste depende de tres decisiones: anclarse a la semántica y no a la posición, degradar ante campos ausentes en vez de lanzar errores, y etiquetar la completitud para que «vacío» y «roto» no parezcan iguales. Lo que aporta valor no son los campos de un anuncio aislado, sino las dimensiones de país, ventana de publicación, rango de impresiones y facetas de segmentación que permiten recortar el lanzamiento de un competidor. El lugar del modelo es concreto: no en el parseo, que debe ser una máquina de estados determinista, sino en el mantenimiento. Comparar el HTML antiguo y el nuevo tras un rediseño para proponer reparaciones es donde ayuda una capa de razonamiento; convertir tarjetas en inteligencia en bloque es tarea de una capa económica y de alta concurrencia. Pero la decisión final sobre si los campos son correctos siempre corresponde al fixture. Conecta estas capas a una interfaz unificada y la única fricción restante será cambiar un campo model, algo que se resuelve al elegir tu modelo.

>_Directorio de modelos AIReiter

Acceso API rápido a modelos relacionados con esta guía

Claude Opus 5

Chat

Un modelo premium de Claude para razonamiento complejo, programación y trabajo profesional con contexto largo.

anthropicCrear API Key >

Claude Sonnet 5

Chat

Un modelo Claude equilibrado para razonamiento avanzado, programación y trabajo diario.

AnthropicCrear API Key >

Kimi K3

Chat

Un modelo de razonamiento de contexto largo para programación, escritura, análisis y flujos de trabajo de agentes.

moonshotCrear API Key >

GPT-5.6 Sol

Chat

Un modelo de texto GPT-5.6 premium para programación exigente, razonamiento y trabajo de agentes de larga duración.

OpenAICrear API Key >

Claude Fable 5

Chat

Un modelo premium de Claude para razonamiento profundo y trabajo complejo de formato largo.

AnthropicCrear API Key >

Publicaciones recientes

Recorte de precios de GPT-5.6: cuánto cuestan ahora Luna y Terra

2026-07-31

API key inválida: diagnostica el 401 y el 403 antes de corregir nada

2026-07-31

Cómo resolver el error 429 de OpenRouter: ¿proveedor o límite de tasa?

2026-07-31

DeepSeek V4 Flash vs GLM-5.2: prueba tras la actualización 0731

2026-07-31
AIREITER

¿Preguntas? Contáctanos en
[email protected]

LLM

Gemini 3.6 FlashGemini 3.1 ProKimi K3Gemini 3 ProGemini 2.5 Pro

Video IA

Kling 3.0 Motion ControlSora 2 ProKling 3.0 TurboSora 2Kling 3.0

Imagen IA

FLUX.2 ProGPT-Image 2Wan 2.7 Image ProGPT 4o ImageSeedream 5.0 Pro

Blog

Ver todo →

Compañía

Política de privacidadTérminos de servicioPolítica de reembolso

© 2026 AIReiter. Todos los derechos reservados.