Convertir HTML a Markdown en PHP con league/html-to-markdown
Introducción
Convertir HTML a Markdown es una necesidad común al trabajar con web scraping, migraciones de CMS, procesamiento de feeds RSS o preparación de contenido para LLMs. La biblioteca league/html-to-markdown ofrece una solución robusta y probada, con más de 24 millones de descargas.
Este artículo cubre instalación, opciones de configuración, soporte de tablas y consideraciones de seguridad para entrada no confiable.
Instalación
Instala vía Composer:
composer require league/html-to-markdownLa biblioteca requiere PHP 7.2+ con las extensiones xml, libxml y dom (habilitadas por defecto en la mayoría de distribuciones).
Uso Básico
use League\HTMLToMarkdown\HtmlConverter;
$converter = new HtmlConverter();
$html = '<h1>Hola Mundo</h1><p>Esta es una <strong>prueba</strong>.</p>';
$markdown = $converter->convert($html);
echo $markdown;
// # Hola Mundo
//
// Esta es una **prueba**.Opciones de Configuración
El convertidor acepta un array de opciones:
$converter = new HtmlConverter([
'strip_tags' => true,
'remove_nodes' => 'script style',
'hard_break' => true,
'strip_placeholder_links' => true,
]);Principales Opciones Explicadas
| Opción | Predeterminado | Descripción |
|---|---|---|
strip_tags | false | Elimina tags HTML sin equivalente en Markdown, manteniendo su contenido |
remove_nodes | '' | Lista de tags separadas por espacio para eliminar completamente (incluyendo contenido) |
hard_break | false | Convierte <br> a \n en lugar de \n (estilo GFM) |
strip_placeholder_links | false | Elimina tags <a> sin atributo href |
header_style | 'setext' | Usa 'atx' para headers con # en H1/H2 |
preserve_comments | false | Mantiene comentarios HTML en la salida |
Configuración Recomendada para Web Scraping
Al convertir HTML extraído de la web, generalmente quieres eliminar navegación, scripts y otros elementos que no son contenido:
$converter = new HtmlConverter([
'strip_tags' => true,
'remove_nodes' => 'script head style noscript nav footer aside header',
'hard_break' => true,
'strip_placeholder_links' => true,
]);Agregando Soporte de Tablas
La conversión de tablas no está habilitada por defecto porque las tablas no son parte de la especificación original de Markdown. Agrega soporte con el TableConverter:
use League\HTMLToMarkdown\HtmlConverter;
use League\HTMLToMarkdown\Converter\TableConverter;
$converter = new HtmlConverter(['strip_tags' => true]);
$converter->getEnvironment()->addConverter(new TableConverter());
$html = '
<table>
<tr><th>Nombre</th><th>Rol</th></tr>
<tr><td>Alice</td><td>Desarrolladora</td></tr>
<tr><td>Bob</td><td>Diseñador</td></tr>
</table>';
echo $converter->convert($html);
// | Nombre | Rol |
// | --- | --- |
// | Alice | Desarrolladora |
// | Bob | Diseñador |Ejemplo Práctico: Pipeline de Web Scraping
Aquí hay una función utilitaria completa para convertir HTML extraído a Markdown limpio:
use League\HTMLToMarkdown\Converter\TableConverter;
use League\HTMLToMarkdown\HtmlConverter;
function htmlAMarkdown(string $html): string
{
$converter = new HtmlConverter([
'strip_tags' => true,
'remove_nodes' => 'script head style noscript nav footer aside header',
'hard_break' => true,
'strip_placeholder_links' => true,
]);
$converter->getEnvironment()->addConverter(new TableConverter());
return $converter->convert($html);
}
// Uso
$html = file_get_contents('https://ejemplo.com/articulo');
$markdown = htmlAMarkdown($html);Preprocesamiento: Limpiando Código con Syntax Highlighting
Al extraer sitios de documentación, los bloques de código frecuentemente contienen tags <span> para resaltado de sintaxis. Esto puede ensuciar tu salida Markdown. Limpia antes de la conversión:
function removerSpansDelCode(string $html): string
{
$dom = new DOMDocument('1.0', 'UTF-8');
libxml_use_internal_errors(true);
$dom->loadHTML($html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
libxml_clear_errors();
$xpath = new DOMXPath($dom);
$spans = $xpath->query('//pre//span | //code//span');
foreach ($spans as $span) {
while ($span->childNodes->length > 0) {
$span->parentNode->insertBefore($span->childNodes->item(0), $span);
}
$span->parentNode->removeChild($span);
}
return trim($dom->saveHTML());
}
// Uso: limpia el HTML antes de convertir
$htmlLimpio = removerSpansDelCode($html);
$markdown = htmlAMarkdown($htmlLimpio);Consideraciones de Seguridad
Importante
Por defecto, la biblioteca preserva tags no reconocidas como <script>, <iframe> y <div>. Al procesar entrada de usuarios no confiables, siempre habilita strip_tags o remove_nodes.
Para contenido generado por usuarios, combina con HTML Purifier para seguridad adicional:
use HTMLPurifier;
use HTMLPurifier_Config;
use League\HTMLToMarkdown\HtmlConverter;
function htmlSeguroAMarkdown(string $htmlNoConfiable): string
{
// Primero, sanitiza con HTML Purifier
$config = HTMLPurifier_Config::createDefault();
$purifier = new HTMLPurifier($config);
$htmlLimpio = $purifier->purify($htmlNoConfiable);
// Luego convierte a Markdown
$converter = new HtmlConverter([
'strip_tags' => true,
'remove_nodes' => 'script style iframe object embed',
]);
return $converter->convert($htmlLimpio);
}Problemas Comunes
DOMDocument No Encontrado
En CentOS o instalaciones PHP mínimas, puedes ver:
Fatal error: Class 'DOMDocument' not foundCorrige instalando la extensión PHP XML:
# CentOS/RHEL
sudo yum install php-xml
# Ubuntu/Debian
sudo apt-get install php-xmlAdvertencias de HTML Malformado
Suprime advertencias para HTML malformado (común con contenido extraído):
$converter = new HtmlConverter(['suppress_errors' => true]);Conclusión
La biblioteca league/html-to-markdown maneja la complejidad de la conversión HTML-a-Markdown con valores por defecto sensatos y amplia personalización. Puntos clave:
- Usa
strip_tagsyremove_nodespara limpiar elementos no deseados - Agrega
TableConverterpara soporte de tablas - Siempre sanitiza entrada no confiable antes de procesar
- Preprocesa bloques de código con syntax highlighting para salida más limpia
Para pipelines de LLM o procesamiento de contenido, esta combinación de opciones de configuración proporciona Markdown limpio y legible de casi cualquier fuente HTML.

