html2text instala un solo paquete y ocupa apenas 0.2 MiB: nueve veces menos que la alternativa más cercana en Python y cuarenta veces menos que la de Node. Completó las cuatro páginas del conjunto de conversión y conservó los 16 probes del cuerpo registrados. Esos probes verifican si determinadas cadenas del body sobreviven; no evalúan la jerarquía, el anidamiento de listas, los destinos de los enlaces, el contenido repetido ni la fidelidad total de las tablas.
Además, está bajo licencia GPL-3.0-or-later, que es la única característica de esta comparación que no aparece en ningún benchmark y puede dejar fuera por completo a una biblioteca.
Qué es html2text
html2text es una biblioteca de Python que convierte HTML en texto plano con apariencia de Markdown. Su origen se remonta al proyecto original de Aaron Swartz, y la línea mantenida actual está en 2025.4.15 — una versión fechada en abril de 2025, con 2,168 estrellas en GitHub, 95 incidencias abiertas y un último push en octubre de 2025.
Referencia oficial: repositorio oficial de html2text.
import html2text
h = html2text.HTML2Text()
h.body_width = 0 # ver más abajo; el valor por defecto te sorprenderá
md = h.handle(html)
pip install html2text descarga 1 paquete y 0.2 MiB, con una importación en frío de 0.077 s. Cero dependencias. En una imagen de contenedor o en una capa de Lambda, esa diferencia sí importa frente a los 1.8 MiB de markdownify y los 8.8 MiB de turndown.
El valor por defecto que cambia todos los números

body_width tiene un valor predeterminado de 78. html2text ajusta en duro cada línea de salida a 78 caracteres, a menos que lo desactives.
Es un valor razonable para una biblioteca cuya función original era generar texto legible para terminales y correo electrónico. Pero es una mala opción para cualquier flujo que alimente a un modelo o a un diff, donde los saltos de línea insertados cambian la tokenización, parten enlaces largos y vuelven inútil la comparación de resultados.
Más abajo he fijado body_width = 0 en todo, y lo señalo abiertamente: con el ajuste de ajuste automático activado, todos los conteos de caracteres y tokens de este artículo serían distintos. Si vas a medir convertidores por tu cuenta, este es el ajuste que puede volver incomparables tus números sin avisarte.
La medición
Ejecuté html2text sobre un conjunto de conversión de cuatro páginas, también usado en la comparación de markitdown, con cadenas de probe pre-registradas — cadenas seleccionadas del body que deben sobrevivir y cadenas de boilerplate cuya presencia indica que se conservó el chrome de la página. Los mismos cuatro archivos, los mismos probes, un único evaluador para los cuatro convertidores. La supervivencia de probes mide la presencia de cadenas registradas, no la corrección estructural; por eso las columnas de tablas y enlaces se evalúan por separado.
| Convertidor | Probes del body | Caracteres de salida | Tokens (o200k) | Filas de tabla Markdown | Enlaces |
|---|---|---|---|---|---|
| html2text | 16/16 | 76,452 | 21,176 | 32 | 545 |
| markdownify | 16/16 | 76,868 | 21,062 | 36 | 599 |
| markitdown | 16/16 | 76,995 | 21,336 | 36 | 598 |
| turndown | 16/16 | 95,188 | 26,236 | 0 | 611 |
fourway-scores.json. Cuatro fixtures, tokens contados con o200k_base.
La salida más pequeña de las cuatro con 76,452 caracteres, y prácticamente empatado en tokens con markdownify y markitdown — 21,176 frente a 21,062 y 21,336, una diferencia de 1.3% que no llamaría diferencia relevante.
32 filas de tabla frente a las 36 de markdownify y markitdown en el conjunto de cuatro páginas. La diferencia de cuatro filas aparece en el fixture irregular de Wikipedia, no en la diferencia de formato con pipes externos descrita más adelante.
El menor número de enlaces, 545, frente a 598 a 611 en los demás. Conviene comprobarlo con tus propias páginas si conservar enlaces es importante: es la única columna en la que html2text queda claramente por debajo del grupo, en lugar de alinearse con él.
Las tablas que mi regex no veía

Vale la pena contarlo porque casi publiqué una conclusión equivocada sobre esto.
Mi primer contador de filas de tabla exigía pipes iniciales y finales — ^\|.*\|$. Con esa regla, html2text obtuvo 1 fila de tabla en cinco archivos: el conjunto de conversión de cuatro páginas más un fixture sintético adicional de tabla compleja. Ese contador medía un estilo Markdown, no las tablas.

Sí lo hace. Las emite así:
Team Name | Year | Wins | Losses | Win %
---|---|---|---|---
Boston Bruins | 1990 | 44 | 24 | 0.55
Sin pipes externos. Es una sintaxis convencional de tabla con pipes, pero el harness no la validó entre renderizadores Markdown. Para una regex que espera el estilo con pipes exteriores, es invisible. Al reescribir el contador para buscar una secuencia de líneas con pipes y una fila separadora dentro, html2text pasó de 1 fila a 32 en el conjunto de cuatro páginas y 91 en los cinco archivos.
Así que la conclusión no es que html2text no tenga tablas. La conclusión es que dos de estos cuatro convertidores emiten pipes externos y uno no, lo cual importa si después procesas el Markdown con tus propias expresiones regulares. Es un dato útil de verdad, y lo habría pasado por alto por completo si me hubiera fiado de mi primer número.
Qué elimina y dónde pierde filas
Dos hallazgos que empujan en direcciones opuestas.
Elimina <script> y <style>. Medido por marcadores que solo aparecen dentro de esos elementos, la salida de html2text en los fixtures contiene cero marcadores de script y cero de style. La de turndown contiene 10 y 84 — en el fixture de Wikipedia, ocho líneas de la configuración JavaScript en línea y CSS de MediaWiki por un total de 14,644 caracteres (script-style-stripping.json). Para salida orientada a modelos, esa fue la mayor fuente observada de texto prescindible en ese fixture. No se midió ningún coste posterior.
Pierde filas de tabla en la página difícil. El conjunto de cuatro páginas se desglosa así:
| Fixture | html2text | markdownify |
|---|---|---|
| Books to Scrape | 0 filas | 0 filas |
| Quotes to Scrape | 0 filas | 0 filas |
| Hockey statistics | 27 filas | 27 filas |
| Wikipedia | 5 filas | 9 filas |
| Total cuatro páginas | 32 filas | 36 filas |
El fixture sintético complejo aparte añade 59 filas para html2text y 62 para markdownify, llevando los totales de cinco archivos a 91 y 98. No forma parte de la comparación principal de cuatro páginas. En la tabla de hockey, limpia, coinciden. En Wikipedia, donde las tablas son anidadas e irregulares, html2text emite cinco filas frente a las nueve de markdownify.
El patrón, entonces, es: tablas simples, iguales; tablas complicadas, html2text conserva menos. Si tus páginas contienen tablas como las de Wikipedia, compruébalo antes de decidir. Si tienen tablas como las de una página de estadísticas, ambos se comportan igual en este punto.
La licencia
| Biblioteca | Licencia | Paquetes | Disco |
|---|---|---|---|
| html2text | GPL-3.0-or-later | 1 | 0.2 MiB |
| markdownify | MIT | 5 | 1.8 MiB |
| turndown | MIT | 3 (npm) | 8.8 MiB |
Referencia oficial: html2text en PyPI.
Confirmado en tres lugares: los metadatos de PyPI, el repositorio de GitHub y el propio archivo METADATA del paquete instalado, que indica License-Expression: GPL-3.0-or-later.
Lo que eso significa depende de cómo se integre, se distribuya y se entregue el software. El uso interno o solo por red suele ser un escenario distinto del GPL respecto a distribuir software que incluye o combina ese paquete, pero este artículo no es un análisis legal. Los equipos que distribuyen software deberían pedir a su asesoría que revise el modelo exacto de integración y distribución.
La parte incómoda es la correlación. La biblioteca con menor huella, la que elegirías precisamente porque intentas mantener pequeño el artefacto distribuible, es la que tiene la licencia que más restringe la distribución. Ambas alternativas son MIT.
No soy abogado y esto no es asesoría — solo el dato, con fuente, porque es la propiedad que más puede importar y la que menos suele aparecer en una tabla comparativa.
Mantenimiento
Última versión 2025.4.15, último push al repositorio en octubre de 2025 — unos diez meses antes de la prueba, con 41 lanzamientos por detrás. requires_python >= 3.9, y se instaló y ejecutó sin problemas en Python 3.14.2.
Eso es más tranquilo que markdownify (última versión seis semanas antes de la prueba) y turndown (cuatro meses), y bastante más activo que nada. Para una biblioteca que convierte HTML a texto — un problema que no cambia demasiado — una brecha de diez meses parece estabilidad, no abandono. Las 95 incidencias abiertas son la señal más importante, y conviene revisarlas por si aparece algo parecido a tu caso de uso antes de decidirte.
Memoria y qué hace el HTML roto
Aquí se miden por separado dos preguntas operativas.
El contexto del test de estrés más amplio está en la comparación de memoria y HTML malformado entre diez bibliotecas.
Memoria residente máxima, mediante /usr/bin/time -l, un proceso nuevo por celda: el piso de importación es lo que cuesta la biblioteca cargada e inactiva; los picos incluyen el documento.
| Biblioteca | Runtime | Piso de importación | Pico 226 KB | Pico 10 MB |
|---|---|---|---|---|
| html2text | python3.14 | 18.7 | 19.9 | 71.2 |
| pyquery | python3.14 | 30.3 | 33.9 | 172.5 |
| resiliparse | python3.14 | 20.5 | 25.1 | 225.1 |
| markdownify | python3.14 | 23.9 | 28.9 | 278.5 |
| goose3 | python3.14 | 44.1 | 52.4 | 398.5 |
| cheerio | node22 | 66.8 | 76.5 | 398.5 |
| justext | python3.14 | 30.3 | 36.6 | 431.2 |
| newspaper4k | python3.14 | 52.6 | 61.8 | 668.5 |
| trafilatura | python3.14 | 52.5 | 64.8 | 927.1 |
| turndown | node22 | 47.8 | 68.4 | 2947.1 |
memory-results.json. Los baselines de Python y Node no son comparables entre sí; el intérprete está dentro de ambos.
html2text es la entrada más ligera aquí en ambos ejes medidos. Su piso de importación de 18.7 MiB y su pico de 71.2 MiB en el fixture de 10 MiB dan un RSS incremental de 52.5 MiB: (71.2 - 18.7) / 10 = 5.25× el tamaño del fixture. Compáralo con las filas absolutas e incrementales de la tabla, teniendo presente la advertencia sobre los baselines de Python y Node.
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 engañosa, 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 malformado si la biblioteca tampoco guarda silencio ante un documento limpio del mismo tamaño.
html2text lanzó excepción en 0 de 14 y no devolvió nada en 0, recuperando 33/33 sentinelas 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 sí es contenido de script, así que perderlo ahí es lo correcto y recuperarlo sería la desviación.
Ventajas y desventajas
A favor. Un paquete, 0.2 MiB, cero dependencias: con mucha diferencia, el más pequeño de la comparación. La salida más pequeña de las cuatro y prácticamente empatado en tokens con markdownify y markitdown. Emite una sintaxis de tabla con pipes reconocible. Funciona en Python 3.14. Trayectoria larga y estable.
En contra. GPL-3.0-or-later, cosa que las alternativas no son. body_width=78 por defecto, lo que ajusta la salida y altera mediciones o diffs salvo que lo desactives. Es el que menos enlaces conserva (545 frente a 598–611). Las tablas usan el estilo sin pipes externos, que rompe regex ingenuas aguas abajo. 95 incidencias abiertas y un ritmo de releases más tranquilo que markdownify.
Quién debería usarlo y quién no
Usa html2text cuando el presupuesto de dependencias sea realmente ajustado y el modelo de integración y distribución previsto ya haya pasado revisión de licencia. Un paquete con cero dependencias es una ventaja operativa real: una superficie de dependencias más pequeña para auditar y desplegar.
Ajusta body_width = 0 en la primera línea, salvo que quieras específicamente texto plano envuelto.
Sáltatelo si distribuyes software y el copyleft es un problema — markdownify es MIT, iguala los tokens y empata con markitdown en tablas por 1.6 MiB más. Sáltatelo si la conservación de enlaces te importa, porque fue el que menos guardó. Y sáltatelo si tu tooling downstream asume pipes externos en las filas de tabla.
Dónde encaja una API gestionada
html2text convierte HTML que ya tienes. No descarga páginas, no renderiza JavaScript ni maneja una capa anti-bot — ninguno de los cuatro convertidores lo hace, y en muchos objetivos reales esa es la mitad más difícil del trabajo.
Para los mismos fixtures en los cinco convertidores, consulta la comparación HTML a Markdown entre cinco opciones.
Un servicio alojado de fetch/render/extracción, incluido nuestro Thunderbit, opera en otra capa. Thunderbit no se evaluó aquí. La frontera relevante es conversión de HTML suministrado frente a un servicio que obtiene y procesa una URL; este artículo no ofrece una comparación equivalente en calidad, latencia o coste.
La lectura justa: si ya tienes el HTML, quieres Markdown y la GPL no es un problema para tu forma de distribuir, html2text es gratis y sorprendentemente pequeño. Si estás capturando páginas, o quieres filas en lugar de prosa, eso es otra compra.
Para una visión más amplia, nuestro resumen de APIs de web scraping cubre opciones alojadas y el pilar de scrapers open source las autoalojadas. Convertir HTML a Markdown en Python es la guía práctica.
Prueba Thunderbit para extraer datos web
¿Deberías usar html2text?
Es una opción sólida cuando la huella importa, el ajuste de línea se desactiva a propósito y el modelo de distribución supera la revisión de licencia.
Su conteo de tokens quedó dentro del 1.3% de markdownify y markitdown en el conjunto de cuatro páginas. Eso no significa que la calidad general sea equivalente: html2text conservó menos enlaces y menos filas en el fixture irregular de Wikipedia. Hay dos detalles operativos que importan de inmediato: body_width = 0 y el estilo de tabla sin pipes externos.
Si la revisión GPL lo descarta, markdownify es MIT, aquí tuvo tamaño de salida y conteo de tokens similares, conservó más enlaces y más filas irregulares de tabla, y usó 1.6 MiB más de disco en este entorno.
Prueba Thunderbit para extraer datos web Get Started Free
Preguntas frecuentes
¿html2text convierte tablas?
Sí. Mi primer contador dijo que producía una fila de tabla en cinco archivos, y ese contador estaba mal: exigía pipes al inicio y al final, mientras html2text emite Team Name | Year | Wins sin ellos. Es Markdown convencional de tabla con pipes, aunque este harness no ejecutó una prueba de compatibilidad entre renderizadores. Con el contador corregido, html2text produjo 32 filas frente a las 36 de markdownify en el conjunto de cuatro páginas y 91 frente a 98 cuando se incluye el fixture aparte de tabla compleja.
¿Qué hace body_width y por qué cambiarlo?
Ajusta en duro la salida a 78 caracteres por defecto, una elección sensata para texto plano legible en terminal y mala para casi todo lo demás. Ese ajuste inserta saltos de línea a mitad de frase, parte URLs largas y cambia la tokenización. Todos los números de esta revisión usaron body_width = 0; con el valor por defecto, serían distintos.
¿La licencia GPL es una restricción real?
Depende del modelo exacto de integración y distribución. El uso interno o solo por red y la entrega de software son escenarios de revisión distintos, pero este artículo no determina su resultado legal. Los equipos que distribuyen software deberían pedir a su asesoría que revise los términos GPL-3.0-or-later; markdownify y turndown son MIT. La expresión de licencia de html2text está confirmada en los metadatos de PyPI, GitHub y el archivo METADATA del paquete instalado.
¿Una versión de abril de 2025 es un problema? Probablemente no, por sí sola. La conversión de HTML a texto es un problema estable, la biblioteca se instaló y ejecutó correctamente en Python 3.14.2, y lleva 41 releases acumulados. Las 95 incidencias abiertas son el dato que yo sí revisaría: mira si hay algo parecido a tu caso de uso antes de decidirte, porque un repositorio silencioso puede acabar significando que tú serás quien lo arregle.
¿Qué no se probó aquí?
Cuatro fixtures de conversión y un fixture aparte de tabla compleja siguen siendo un conjunto pequeño. La prueba sí cubrió doce documentos sintéticos malformados más dos controles: html2text lanzó excepción en 0/14, no devolvió vacío en 0/14 y recuperó los 33 sentinelas evaluados. No cubrió páginas dañadas reales, patrones malformados más amplios, listas anidadas, listas de definición, notas al pie ni matemáticas. Toda la superficie de opciones — ignore_links, ignore_images, unicode_snob, single_line_break y el resto — se dejó en valores por defecto salvo body_width. La diferencia en enlaces se observó pero no se analizó, y no se probó la ida y vuelta de Markdown.


