goose3 no devolvió boilerplate etiquetado. Tampoco devolvió nada en dos ocasiones.

Última actualización: August 17, 2026
goose3 no devolvió boilerplate etiquetado. Tampoco devolvió nada en dos ocasiones.
Resumen con IA
En los fixtures donde una fuga siquiera puede definirse, goose3 logró 1.0000 de precisión en tokens de contenido y cero tokens contaminantes. Ni una sola palabra de navegación, anuncios, barra lateral, comentarios o promociones se coló en la salida. Ninguna otra herramienta en la comparación de seis librerías igualó eso. También presenta el peor recall de artículo del conjunto — 0.8243 en los 22 fixtures, frente a 1.0000 de Mozilla Readability — porque en dos casos devolvió una cadena vacía. Estas métricas están ligadas por la regla de puntuación: un resultado vacío no aporta nada a la precisión condicional, mientras que el recall sí registra la ausencia.

En los fixtures donde una fuga siquiera puede definirse, goose3 logró 1.0000 de precisión en tokens de contenido y cero tokens contaminantes. Ni una sola palabra de navegación, anuncios, barra lateral, comentarios o promociones se coló en la salida. Ninguna otra herramienta en la comparación de seis librerías igualó eso.

También presenta el peor recall de artículo del conjunto — 0.8243 en los 22 fixtures, frente a 1.0000 de Mozilla Readability — porque en dos casos devolvió una cadena vacía.

Estas métricas están ligadas por la regla de puntuación: un resultado vacío no aporta nada a la precisión condicional, mientras que el recall sí registra la ausencia.

Qué es goose3

goose3 es la continuidad en Python 3 de una línea que arranca con Goose de Gravity Labs en Scala y pasa por python-goose. Es un extractor de artículos con metadatos, no un volcador de texto: creas un Goose, llamas a extract() y recibes un objeto Article con alrededor de veintiocho campos accesibles: texto limpio, título, autores, fecha de publicación, imagen principal, meta description, etiquetas, enlaces, tweets y más.

Referencia oficial: repositorio oficial de goose3.

System diagram: From HTML to Article Fields

Versión probada: 3.1.22, con licencia Apache, 912 estrellas en GitHub, último push el 2026-07-23 — mantenido activamente al momento de la prueba. Python 3.14.2.

La API son dos llamadas y una obligación:

from goose3 import Goose
g = Goose()
try:
    article = g.extract(raw_html=html)
    text = article.cleaned_text
finally:
    g.close()          # cerrar explícitamente después de usarlo

Vale la pena subrayar ese close(), porque es fácil olvidarlo y nadie te avisa. Esta revisión no ejecutó una prueba en bucle para cuantificar sesiones retenidas, conexiones o memoria cuando se omite el cierre, así que hablar de “fuga de recursos” sería más fuerte de lo que permite la evidencia. Toma el cierre explícito como el requisito de ciclo de vida que muestra este uso de la API.

El intercambio, medido

Seis extractores, un conjunto de fixtures anotados, un evaluador. Cada bloque de cada fixture está etiquetado como article o boilerplate y lleva un token centinela único, así que “¿recuperó esta unidad?” se decide por pertenencia exacta de subcadenas, no por una similitud difusa.

LibreríaRecall de artículo (22 en total)Fuga de boilerplatePrecisión de tokens de contenidoTokens contaminantesSalida producida
Readability1.00000.23530.91093522/22
trafilatura0.98650.05880.9411422/22
newspaper4k0.98650.00000.9452022/22
resiliparse0.90540.05880.9381722/22
jusText0.83780.47060.87607419/22
goose30.82430.00001.0000020/22

sixway-scores.json. El recall se calcula sobre los 22 fixtures; la tasa de fuga y la precisión sobre los 11 que contienen tanto unidades de artículo como de boilerplate.

Hay que leer siempre la columna de precisión junto con la última columna. Aquí la precisión es condicional a producir salida: una librería que devuelve una cadena vacía en un fixture no suma ni al numerador ni al denominador, así que rendirse sale gratis en este promedio. El numerador es el solapamiento multiconjunto entre los tokens extraídos que no son stopwords y los tokens etiquetados como artículo; el denominador es todos los tokens extraídos que no son stopwords. “Tokens contaminantes” es más estricto: solo cuenta el solapamiento con los tokens etiquetados como boilerplate. Un token extra extraído que no coincida ni con artículo ni con boilerplate baja la precisión sin aumentar ese conteo de contaminación; los tokens repetidos por encima del multiconjunto del artículo pueden hacer lo mismo. Por eso newspaper4k puede mostrar 0 tokens contaminantes y una precisión inferior a 1.0000. En goose3, el 1.0000 se puntuó en 10 de los 11 fixtures; Readability, trafilatura, newspaper4k y resiliparse se puntuaron en 11 de 11.

El 1.0000 sigue siendo útil dentro de este conjunto sintético. En los diez fixtures puntuados, goose3 no emitió ninguno de los tokens de boilerplate etiquetados; Readability emitió 35 en las mismas páginas. Si un modelo consume la salida, eso significa cero gasto de tokens en las etiquetas de boilerplate registradas en esos diez fixtures. No demuestra cero desperdicio en páginas reales, y un resultado vacío puede añadir coste de fallback o reintento en otra parte del pipeline.

Los dos silencios, y qué significan

goose3 no devolvió nada en exactamente dos fixtures. Uno se puede defender y el otro es una limitación real.

El documento casi vacío. Una página con una sola unidad de artículo de 32 caracteres. goose3 se niega. jusText también. En este conjunto de fixtures, Readability produjo salida en las 22 páginas, así que su resultado no respalda el silencio de goose3 aquí. Que rechace este documento tan pequeño es aceptable o no según el contrato mínimo de contenido del llamador.

System diagram: Treat Empty Output as Failure

El artículo compuesto únicamente por elementos <li>. Seis unidades de artículo, ninguna dentro de una etiqueta <p>. goose3 devuelve una cadena vacía.

Ese segundo caso me llamó la atención, porque la configuración por defecto de goose3 incluye parse_lists=True. Así que lo probé — tres configuraciones frente a un control que sí funcionaba, porque una sola ejecución improductiva no basta para sacar conclusiones sobre una librería:

ConfiguraciónPágina solo con listasControl con <p>
valores por defecto0 caracteres937 caracteres
strict=False0 caracteres937 caracteres
parse_lists=True (explícito)0 caracteres937 caracteres

list-only-probe.json.

Cero en las tres configuraciones, mientras que el control devuelve 937 caracteres en las tres. Así que parse_lists=True gobierna si las listas se conservan dentro de un artículo que goose3 ya localizó; no hace que el clasificador de candidatos trate una lista como si fuera el artículo. El sistema de puntuación de nodos de goose3 necesita bloques con forma de párrafo para detectar el cuerpo, y una página cuyo cuerpo es una lista no los tiene.

El resultado que sí se puede afirmar es más estrecho: un cuerpo con esta forma sintética — seis unidades de artículo, todas <li>, sin candidato de párrafo — devolvió una cadena vacía. Changelogs, referencias de API, recetas, páginas de preguntas frecuentes y posts comparativos son muestras sensatas para probar en páginas reales porque pueden ser muy listas, pero este único fixture no prueba que esas categorías fallen de forma general.

La cadena vacía solo es detectable por la máquina si el llamador valida que la salida no esté vacía. Es más fácil de bloquear que un texto plausible que no contiene nada del artículo, pero sigue siendo un fallo silencioso si solo monitorizas excepciones. Un flujo de producción necesita un control de salida mínima y un fallback o un registro explícito de página fallida.

Realidad de la instalación

pip install goose3 instala 16 paquetes y 44.3 MiB en unos 6 a 9 segundos. La importación en frío medida en un subproceso limpio: 2.181 s.

Referencia oficial: goose3 en PyPI.

LibreríaPaquetessite-packagesImportación en fríoExtracción p50
resiliparse521.0 MiB0.015 s0.06 ms
jusText322.4 MiB0.777 s0.56 ms
goose31644.3 MiB2.181 s1.85 ms
newspaper4k2247.5 MiB2.812 s2.69 ms
trafilatura1769.9 MiB1.584 s0.51 ms

install-and-import.json. Cada librería en un entorno virtual vacío distinto, así que no hereda huella de ninguna otra.

Está en la mitad de la tabla en peso y en velocidad. Se instaló e importó sin problemas en Python 3.14.2, algo que no es universal en esta categoría.

Tres valores por defecto que conviene conocer antes de desplegarlo

System diagram: Three defaults worth knowing before you deploy

Leer el objeto Configuration que trae la librería, en vez de la documentación, revela diecinueve ajustes. Tres de ellos sorprenderán a más de uno.

Se delata a sí mismo. browser_user_agent por defecto es Goose/3.1.22. Si dejas que goose3 haga sus propias peticiones, todos los servidores que toque registrarán el nombre de la librería y su versión exacta. Eso es honesto, pero también deja huella. Defínelo tú o descarga el HTML por tu cuenta y pásalo mediante raw_html.

Apunta a un binario de MacPorts. imagemagick_convert_path por defecto es /opt/local/bin/convert y imagemagick_identify_path es /opt/local/bin/identify. En mi máquina ninguno existe — /opt/local es MacPorts, que la mayoría no tiene; Homebrew coloca los binarios en /opt/homebrew. Ese valor por defecto no hace nada mientras no actives la obtención de imágenes (enable_image_fetching está en False por defecto, sensato), pero si la activas esperando que la extracción de imagen principal funcione, aquí es donde silenciosamente no lo hará.

Asume inglés. target_language viene en en con use_meta_language=True, así que seguirá la declaración del propio sitio cuando exista y volverá a inglés cuando no la haya. Bien para trabajo en inglés; conviene fijarlo explícitamente para cualquier otro idioma.

El resto es razonable: parser_class es lxml, http_timeout 30 segundos, strict activado, log_level ERROR, parse_headers y keep_footnotes activados, images_min_bytes 4,000.

Memoria, y cómo el HTML roto la afecta

Dos cosas que en cada revisión de este bloque figuraban como no probadas, ahora medidas.

El contexto más amplio de estrés está en la comparación de memoria y HTML malformado entre diez librerías.

Memoria residente pico, mediante /usr/bin/time -l, un proceso nuevo por celda — el piso de importación es lo que cuesta la librería cargada e inactiva; los picos incluyen el documento.

LibreríaRuntimePiso de importaciónPico 226 KBPico 10 MB
html2textpython3.1418.719.971.2
pyquerypython3.1430.333.9172.5
resiliparsepython3.1420.525.1225.1
markdownifypython3.1423.928.9278.5
goose3python3.1444.152.4398.5
cheerionode2266.876.5398.5
justextpython3.1430.336.6431.2
newspaper4kpython3.1452.661.8668.5
trafilaturapython3.1452.564.8927.1
turndownnode2247.868.42947.1

memory-results.json. Los valores base de Python y Node no son comparables entre sí; el intérprete está dentro de ambos.

goose3 tiene un piso de 44.1 MiB y llega a 398.5 MiB en un documento de 10 MB. Su piso de importación es el tercero más alto entre las librerías Python mostradas, algo importante si te preocupa el arranque en frío.

HTML roto. Doce documentos, cada uno rompiendo exactamente una cosa — etiquetas sin cerrar, elementos inline mal anidados, atributos sin comillas con espacios, cierres sobrantes, ausencia total de <html>, atributos duplicados, un documento truncado a mitad de etiqueta, entidades inválidas, un <script> sin cerrar, una declaración de charset falsa, un comentario que contiene marcado y 600 niveles de anidamiento — más dos controles bien formados con tamaños equivalentes, porque “no devolvió nada” solo dice algo sobre el HTML malformado si la librería tampoco calla en un documento limpio del mismo tamaño.

goose3 lanzó excepción en 0 de 14 y no devolvió nada en 10, recuperando 2/33 centinelas en los fixtures rotos (malformed-results.json). Un fixture se excluye de ese conteo: según HTML5, todo lo que sigue a un <script> sin cerrar es contenido de script, así que perderlo ahí es correcto y recuperarlo sería la desviación.

Pros y contras

A su favor. Cero tokens de boilerplate etiquetados en los diez fixtures de fidelidad de contenido donde produjo salida. Hay alrededor de veintiocho campos de artículo disponibles, aunque su exactitud se inventarió pero no se puntuó. Valor por defecto sensato para obtención de imágenes (desactivada). Instalación limpia en Python 3.14. Mantenimiento activo. Apache-2.0. Un resultado vacío se puede bloquear de forma sencilla si el llamador lo comprueba explícitamente.

En contra. El peor recall de artículo del conjunto, 0.8243, impulsado por devolver nada en absoluto y no por devolver la cosa equivocada. Una página cuyo artículo es una lista produce una cadena vacía sin importar la configuración. 44.3 MiB y un arranque en frío de 2.2 segundos pesan bastante frente a los 21.0 MiB y 15 ms de resiliparse. Requiere close(). Dos valores por defecto apuntan a rutas incorrectas en la mayoría de las máquinas.

Quién debería usarlo y quién no

Usa goose3 como candidato cuando el texto extraído vaya a un modelo o una base de datos donde el boilerplate etiquetado sea costoso y las páginas sean artículos convencionales con párrafos. En este conjunto de fixtures no emitió tokens de boilerplate etiquetados cuando respondió. La superficie de metadatos está disponible, pero aquí no se validó; título, autor, fecha e imagen necesitan fixtures de verdad aparte antes de que puedan considerarse una ventaja de selección.

Evítalo si tu corpus está lleno de listas — obtendrás cadenas vacías y ninguna explicación. Evítalo si el coste del arranque importa, porque resiliparse importa 145 veces más rápido. Y evítalo si necesitas respuesta en todas las páginas, porque aquí “no respuesta” es un resultado real: dos de 22 fixtures, y ambos en silencio, en el sentido de que una cadena vacía no es una excepción.

Una combinación que merece pruebas: goose3 como principal con un fallback cuando cleaned_text esté vacío o por debajo de tu regla de contenido mínimo. Readability recuperó todas las unidades de artículo en este conjunto de 22 fixtures, incluidos los dos casos vacíos de goose3. Ese resultado sintético respalda el patrón de arquitectura, no la promesa de que el fallback nunca falle en páginas reales.

Dónde encaja una API gestionada

Este benchmark probó la ruta de extracción raw_html de goose3: el HTML ya se había obtenido antes de que goose3 lo viera. goose3 también tiene su propia ruta de obtención en red, como muestra el ajuste de User-Agent, pero esa ruta no se probó aquí. Tampoco se probaron la renderización JavaScript ni el comportamiento anti-bot.

Para ver los mismos fixtures en los seis extractores, consulta la comparación de extracción entre seis librerías.

Un servicio gestionado de obtención/renderizado/extracción, incluido nuestro Thunderbit, cubre un perímetro de responsabilidad distinto. Thunderbit no se incluyó en esta prueba. La distinción relevante es extracción de artículos a partir de HTML suministrado frente a un servicio alojado que obtiene y procesa una URL; este artículo no ofrece una comparación de rendimiento o calidad con métricas equivalentes.

La comparación justa: el conjunto de campos de goose3 es fijo y orientado a artículos, justo lo que quieres cuando tus páginas son artículos y justo lo contrario cuando son listados de productos. Si ya tienes el HTML y tus páginas son artículos, goose3 es gratis y muy limpio.

Para el terreno alojado, nuestro resumen de APIs de web scraping ofrece una visión más amplia; para alternativas autohospedadas, el pilar de scrapers open source. Si el texto va a terminar en un modelo, convertir HTML a Markdown en Python cubre dónde se pierde realmente la fidelidad.

Prueba Thunderbit para extraer datos web

¿Deberías usar goose3?

Sí, si los artículos con forma de párrafo encajan con tu carga de trabajo y el llamador trata una salida vacía como una extracción fallida, no como un éxito.

En este conjunto de fixtures, goose3 no emitió tokens de boilerplate etiquetados cuando respondió y devolvió dos cadenas vacías. Una fue una página casi vacía y la otra el cuerpo sintético compuesto solo por listas. Eso es un intercambio entre precisión y cobertura, no una prueba de temperamento general del producto.

Si el recall importa más, prueba un fallback con una regla explícita de salida mínima. Readability recuperó todas las unidades de artículo en estos 22 fixtures; newspaper4k mostró cero fuga de unidades de boilerplate etiquetadas y 0.9865 de recall, produciendo salida en los 22 casos. Esos resultados sitúan este conjunto sintético en el terreno de los valores por defecto, no en el de cargas de producción desconocidas.

goose3 gana su lugar cuando el coste de una palabra errónea es mayor que el coste de una página perdida.

Prueba Thunderbit para extraer datos web Get Started Free

Preguntas frecuentes

¿La precisión perfecta de goose3 es real o es un efecto de que se abstiene? Ambas cosas, y son separables. Se puntuó sobre 10 de los 11 fixtures que contienen boilerplate, así que un fixture queda fuera del promedio — esa parte sí es consecuencia de abstenerse. Pero en esos diez devolvió cero tokens contaminantes frente a un boilerplate deliberadamente adversarial, donde Readability filtró 35. La precisión es real en las páginas a las que responde; el recall es donde se nota la abstención.

¿Por qué goose3 no devuelve nada en una página cuyo artículo es una lista? Su puntuación de candidatos necesita bloques con forma de párrafo para localizar el cuerpo del artículo, y una página construida con <li> no los tiene. El valor por defecto parse_lists=True no cambia eso — lo probé explícitamente, junto con strict=False, y obtuve cero caracteres en las tres configuraciones, mientras que un control basado en <p> devolvió 937 en las tres. parse_lists decide si las listas se conservan dentro de un artículo que ya se ha encontrado.

¿Tengo que llamar a close()? Ciérralo explícitamente con try/finally, como se muestra arriba. Esta revisión no midió qué se acumula cuando se omite el cierre, así que no afirma una fuga cuantificada en bucle; sí establece que Goose tiene un ciclo de vida que el llamador debe gestionar.

¿Qué User-Agent envía goose3? Goose/3.1.22 por defecto: el nombre de la librería y la versión exacta. Eso solo aplica cuando le dejas hacer la obtención; si pasas raw_html, lo evitas por completo. Si lo dejas obtener, fija el User-Agent de forma deliberada; el valor por defecto le dice a cada servidor exactamente qué está llamando.

¿Qué no probó esta revisión? Páginas reales, en absoluto — estos son fixtures controlados. Extracción multilingüe, a pesar de que target_language es un ajuste de primera clase. Los campos de metadatos (título, autores, fecha, imagen principal) se inventariaron, pero no se puntuaron por exactitud. La obtención de imágenes, que está desactivada por defecto y cuyas rutas de ImageMagick apuntan a un gestor de paquetes que la mayoría no tiene. El comportamiento de memoria bajo concurrencia o carga sostenida, además del throughput bajo carga; la tabla de memoria midió un proceso nuevo manejando un documento.

Ke
Ke
CTO en Thunderbit | Científico de datos sénior y experto en ML Con casi una década de experiencia en aprendizaje automático y ciencia de datos, Ke Shen es exalumno de la Universidad de Columbia y antiguo científico de datos sénior en Walmart Labs. Con una sólida experiencia, reconocida por sus pares, en Python, R, Java y estadística, comparte conocimientos probados en el campo sobre cómo llevar algoritmos complejos de IA desde la teoría hasta una arquitectura lista para producción.
Tabla de contenidos
Thunderbit · Agente de datos web con IA

Extrae datos de cualquier página en 1 clic

Con la confianza de más de 250,000 usuarios
plan gratuito disponible
De la página web a la hoja de cálculo
Describe lo que necesitas: el agente de IA de Thunderbit lo extrae y lo exporta a Excel, Google Sheets, Airtable o Notion. Empieza gratis.
Chrome Store Rating
PRODUCT HUNT#1 Product of the Week