- Se probó un scraper web asistido por IA que extrae tablas HTML como datos estructurados usando structured outputs de la API de OpenAI, y GPT-4o mostró una calidad de extracción mejor de lo esperado en algunas tablas complejas
- En tablas con una estructura de visualización compleja como el pronóstico de 10 días de Weather.com, pudo distinguir entre pronósticos diurnos y nocturnos, y también encontró en el HTML fuente valores que no eran visibles en pantalla
- En tablas como el Human Development Index de Wikipedia, donde los valores repetidos aparecen en filas combinadas, la cantidad de valores por columna quedaba desalineada y era difícil reconstruir la tabla, y no se resolvió solo ajustando el prompt
- Para reducir el costo de las llamadas a la API también se intentó la generación de XPath, pero produjo XPath incorrectos o vacíos, y fue más estable extraer primero los datos y luego pedir el XPath usando esos valores como referencia
- En dos días se gastaron $24; al reducir atributos del HTML, la cantidad de caracteres se redujo a la mitad y no se observó una baja de rendimiento, aunque el costo limitó verificaciones adicionales
Extracción de tablas HTML con structured outputs
- Se implementó un scraper web asistido por IA usando la función structured outputs de la API de OpenAI
- El primer experimento consistió en pasar una cadena HTML a GPT-4o y pedirle que extrajera los datos de la tabla en un formato estructurado
- El modelo de Pydantic usado tenía una estructura
ParsedTable, que contiene el nombre de la tabla y la lista de columnas, yParsedColumn, que contiene el nombre de la columna y la lista de valores - En el prompt del sistema se le asignó el rol de scraper web especializado en extraer datos estructurados de tablas HTML
- También se probó GPT-4o mini, pero el resultado fue mucho peor, así que los experimentos posteriores se hicieron con GPT-4o
Fortalezas observadas en tablas complejas
- Después de tablas simples, se ingresó la tabla de pronóstico del tiempo de 10 días de Weather.com
- Esta tabla tiene una fila grande en la parte superior y los otros 9 días están compuestos por filas más pequeñas
- GPT-4o reconoció la estructura de pronóstico diurno/nocturno de esos 9 días restantes y agregó una columna
Day/Night - Al principio, la columna
Conditionextraída parecía una alucinación, pero al revisar el HTML fuente se confirmó que realmente existía en etiquetas no visibles en pantalla
Fallo en filas combinadas
- La tabla de Human Development Index de Wikipedia parece simple a primera vista, pero como las filas con valores repetidos están combinadas, GPT-4o no pudo procesarla correctamente
- El modelo extrajo columnas individuales según las instrucciones, pero como cada columna tenía una cantidad distinta de valores, fue difícil representar el resultado como una tabla
- Se modificó el prompt del sistema con una instrucción del tipo “extrae las filas combinadas como múltiples valores JSON para que todas las columnas tengan la misma cantidad de filas”, pero no funcionó
- Aún no se ha probado un prompt que indique extracción por filas en lugar de por columnas
Limitaciones del enfoque de generación de XPath
- Como llamar a la API de OpenAI cada vez puede elevar mucho el costo, se intentó devolver XPath en lugar de los datos extraídos
- El objetivo era volver a obtener datos actualizados de la misma página mediante scraping con XPath, sin llamar al modelo
- El prompt se diseñó para recibir el contenido HTML y los nombres de las columnas, y devolver una cadena XPath evaluable en
driver.find_elements(By.XPATH, xpath)de Selenium - Este enfoque no fue estable
- Hubo casos en los que GPT-4o devolvió XPath incorrectos
- Mencionar Selenium en la instrucción ayudó en parte, pero aun así aparecieron XPath que devolvían datos incorrectos o resultados vacíos
Combinación de extracción de datos y generación de XPath
- El siguiente intento fue hacer que GPT-4o extrajera primero los datos y luego pedir el XPath usando ese resultado como valor de referencia
- Esta combinación funcionó mucho mejor que pedir solo XPath desde el principio
- Como a veces el XPath generado no devolvía resultados, se agregó una lógica simple de reintento para volver a probar cuando no hubiera resultados
- En las tablas probadas, este enfoque de reintento fue efectivo
- También quedaron problemas nuevos
- En la primera etapa de extracción de datos, a veces se convertían imágenes en texto
- Por ejemplo, una imagen de flecha hacia arriba podía extraerse como texto tipo
arrow-upwards - La segunda etapa terminaba buscando texto que en realidad no existe en el HTML y fallaba
- Este problema no se corrigió por separado
Costos y limpieza de HTML
- Al hacer web scraping con GPT-4o, incluso una tabla HTML pequeña puede incluir muchos caracteres y elevar el costo
- En dos días de experimentación ya se habían gastado $24
- Para reducir el costo, se agregó una lógica de limpieza que elimina datos innecesarios de la cadena HTML antes de enviarla al modelo
- Al eliminar todos los atributos excepto
class,idydata-testid, que eran los más usados por el XPath generado, la cantidad de caracteres de la tabla se redujo a la mitad - Después de esta limpieza no se observó una caída de rendimiento, e incluso se considera posible que la calidad de extracción mejore
- Actualmente, la etapa de generación de XPath hace una llamada al modelo por cada columna de la tabla
- Sería posible mejorar esto generando varios XPath a la vez, pero aún no se ha intentado ni evaluado su rendimiento
Demo e ideas para más experimentos
- La calidad de extracción de GPT-4o fue impresionante, pero también se sintió alto el costo a pagar a OpenAI
- Se puede ver una demo simple hecha con Streamlit en https://orange-resonance-9766.ploomberapp.io
- El código fuente está publicado en GitHub y viene con la advertencia de no esperar una herramienta muy pulida
- Se quería probar con más tablas, pero por el aumento de costos de OpenAI solo se experimentó con unas pocas
- Si hubiera más tiempo, se planea probar lo siguiente
- La demo actual es un proceso de una sola vez en el que el usuario ingresa una URL y un XPath inicial; una mejor experiencia de usuario podría ser permitir que el usuario haga clic en la tabla a extraer y proporcione una fila de ejemplo
- En tablas complejas puede ser difícil extraer toda una columna con un solo XPath, así que se quiere experimentar con pedir al LLM que devuelva un programa como Python
- Como usar GPT-4o es caro y da la impresión de que se están enviando muchos datos innecesarios, hace falta seguir experimentando con métodos de limpieza de HTML
1 comentarios
Opiniones en Hacker News
Me funcionó mejor convertir primero el HTML a un formato simple como Markdown en vez de pasarlo directo al LLM
Las herramientas que he usado son Extractus https://github.com/extractus y dom-to-semantic-markdown https://github.com/romansky/dom-to-semantic-markdown
Dentro de Magic Loops https://magicloops.dev/, que corre en la nube, usan Apify https://apify.com/ y Firecrawl https://www.firecrawl.dev/, y en la extensión de Chrome usan dom-to-semantic-markdown
Ahora están probando generar XPath específicos para cada sitio como flujo asistido para el usuario y luego extraer solo los elementos necesarios antes de llamar al LLM; al simplificar el problema, incluso GPT-4o mini dio resultados bastante buenos
Permite ejecutar extensiones de Chrome en un navegador headless, así que puedes hacer la conversión a Markdown semántico dentro del navegador antes de sacar los datos
También tiene una vista en vivo del navegador en tiempo real que puede mostrarse en un iFrame, así que el usuario puede recibir retroalimentación inmediata sobre el XPath que se está generando: https://docs.browserbase.com/features/session-live-view#give...
En mi experiencia, el rendimiento fue bastante parecido al de Markdown, pero la conversión fue más sencilla y con menos casos especiales
La página que encontré dice “Alpha Draft”, así que probablemente no haya mucho corpus de contenido en Semantic Markdown, y la falta de datos de entrenamiento podría dificultar que el LLM lo entienda
Aun así, es un formato lo bastante legible como para que el LLM pueda tratar los metadatos estructurados como aclaraciones entre paréntesis y procesarlo bastante bien
OpenAI anunció recientemente la Batch API, así que puedes preparar todos los prompts y ejecutarlos en lote, además de reducir el costo al 50%: https://platform.openai.com/docs/guides/batch
Antes la usaba mucho con GPT-4o mini, y podía procesar 3,000 elementos en menos de 5 minutos
Puede ser bastante útil para aplicaciones que no necesitan tiempo real
vLLM ya agregó algo de soporte para un “offline batch mode” del mismo estilo, pero todavía no llega a implementar el endpoint de OpenAI
Se siente como algo demasiado natural
Para contenido estructurado, por ejemplo listas de elementos o tablas simples, en realidad no hace falta un LLM
Hace poco construí un scraper web que funciona automáticamente en cualquier sitio https://easyscraper.com; la primera versión usaba AI, pero al final las heurísticas basadas en atributos y posición de los elementos resultaron más rápidas, más baratas y más precisas
En la mayoría de los sitios web, un enfoque sin AI funciona muy bien, así que conviene comprobar primero si de verdad necesitas AI, por ejemplo cuando los datos son no estructurados o cuando tienes que inferir el formato de salida a partir de los datos de la página
Como menciona el autor, puedes hacer que el LLM genere un XPath y luego usar ese XPath para el scraping normal; si se rompe, haces que el LLM lo actualice
Y si aun así los datos dejan de fluir otra vez o algo se rompe más adelante en el pipeline por un formato inesperado, entonces ya le avisas a una persona
Siempre me había preguntado por qué no existía algo así
Me pregunto si ya existe algo como un “HTML reducer”.
Si miras el código fuente de una página tal cual, el 90% de los tokens es basura por JavaScript aleatorio, anuncios, atributos innecesarios y anidamiento excesivo para renderizado.
Si se recorre con un parser del DOM y se dejan solo los nodos con texto, la estructura HTML y los atributos de etiquetas necesarios (
class/id, por ejemplo), parece que se podría reducir mucho el costo, y el enfoque con XPath también podría funcionar mejor.También uso Readability, pero se pierde la estructura del DOM, y en sitios con mucho JavaScript o páginas donde el texto se expande, como “continue reading”, la calidad baja.
Me pregunto cuál sería la herramienta más cercana a un estándar para este uso.
Si hay interés, podríamos publicarlo como open source, y fue sorprendente ver cuánto mejoraba la salida del LLM después de pasar por el reducer.
Si le agregas https://r.jina.ai/ delante de cualquier URL, te devuelve una versión en Markdown del contenido principal de esa página, lista para meterla en un LLM.
Un ejemplo es https://r.jina.ai/https://simonwillison.net/2024/Sep/2/anato... y la página original es https://simonwillison.net/2024/Sep/2/anatomy-of-a-textual-us...
El código es open source y se puede ejecutar directamente: https://github.com/jina-ai/reader
Está escrito en TypeScript y usa Puppeteer y https://github.com/mozilla/readability.
Yo usé solo Readability, sin convertir a Markdown, para extraer el título y el cuerpo de la página, y también hay una receta para ejecutarlo con Playwright y shot-scraper: https://shot-scraper.datasette.io/en/stable/javascript.html#...
Es un enfoque tomado de vimium y modificado, que destila el HTML para dejar solo las partes importantes y también maneja varias situaciones excepcionales.
Me sorprende que el autor haya hecho el 99% del trabajo y de la escritura, pero no haya probado un LLM local decente descargando ese 1% restante, como ollama o un motor basado en llama.cpp.
Para este caso de uso, incluso un modelo de 7B o 30B podría hacerlo bien, y el costo de ejecución es lo bastante bajo como para que GPT-4o no sea necesario.
Recién estoy empezando a experimentar con LLMs, y también pienso revisar modelos alojados localmente.
En Kadoa https://kadoa.com hemos trabajado en scraping web automático con IA, y los experimentos iniciales fueron similares al artículo.
Empezamos en la época en que solo existía GPT-3, caro y lento, así que necesitábamos una solución rentable a gran escala.
Al final, en lugar de usar un LLM en cada extracción, usamos generación de código para crear selectores CSS o código de extracción con XPath, y luego hacer que el scraper ajustara ese código cuando cambiara el sitio web.
Para la limpieza y transformación usamos LLMs pequeños ajustados con fine-tuning, y para la validación evaluamos la calidad de los datos con métodos tradicionales como búsqueda inversa, junto con LLM-as-a-judge.
Aplicarlo a unas pocas fuentes de datos simples y hacerlo funcionar de manera estable, escalable y rentable en miles de sitios web eran problemas completamente distintos, y el enfoque correcto fue mezclar ingeniería ETL tradicional con pasos pequeños de LLM bien evaluados.
Si le das un ejemplo del HTML que quieres scrapear y le pides un fragmento de código con BeautifulSoup, ha funcionado bastante bien.
Normalmente la estructura que quieres extraer se mantiene tal cual, pero escribir uno mismo las cadenas enrevesadas para parsearla es tedioso.
Dejar el parseo real en manos del LLM es excesivo, y además existe el riesgo de que las alucinaciones contaminen el resultado.
Si primero preprocesas el HTML, puedes obtener resultados mejores y más baratos.
No creo que todavía lo hayan mencionado, pero personalmente me ha ido bien con trafilatura https://trafilatura.readthedocs.io/en/latest/
Como al LLM solo le mandas texto, el costo puede bajar muchísimo.
También lo usé en un proyecto reciente https://github.com/philippe2803/contentmap, una librería simple de Python para crear un vector store de cualquier sitio web usando como punto de partida el sitemap XML del dominio.
Como la estructura HTML cambia según el dominio, había que extraer solo el contenido real y quitar etiquetas HTML y demás, y Trafilatura resolvía eso para casi todas las URLs con solo unas pocas líneas de código.
Es la primera vez que veo una publicación con tantas etiquetas naranjas
En NewsCatcher están haciendo muchas pruebas con GPT-4o y, después de rastrear más de 100 mil sitios web de noticias, tienen que parsear el contenido noticioso
Un modelo basado en reglas para extraer datos de cualquier artículo funcionaba bastante bien, y no encontraron una forma de mejorarlo más con GPT
Lo más interesante está del lado del crawling: hay que saber todas las ubicaciones donde puede publicarse un artículo de noticias y a veces hay más de 50 subsecciones
Como la estructura de cada sitio web no cambia con frecuencia, creen que en muchos proyectos puede bastar con generar código de extracción
Por eso están viendo la opción de generar código de parsing de HTML con LLM, y si a alguien le interesa, puede escribir a artem [at] newscatcherapi.com
Ojalá hubiera registro por cuenta propia
El web scraping fue el motivo real por el que mi cofundador y yo terminamos creando openpipe.ai
GPT-4 hace este trabajo realmente bien, pero es demasiado caro
Eso sí, la capacidad de scrapear ciertos tipos de sitios es bastante fácil de destilar en modelos fine-tuned mucho más baratos, y en ese tipo de sitios extraen contenido de forma estable y confiable
Nosotros también llevamos bastante tiempo trabajando en este problema y te voy a contactar para mostrarte hasta dónde hemos llegado