Skip to content

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:

bash
composer require league/html-to-markdown

La biblioteca requiere PHP 7.2+ con las extensiones xml, libxml y dom (habilitadas por defecto en la mayoría de distribuciones).

Uso Básico

php
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:

php
$converter = new HtmlConverter([
    'strip_tags' => true,
    'remove_nodes' => 'script style',
    'hard_break' => true,
    'strip_placeholder_links' => true,
]);

Principales Opciones Explicadas

OpciónPredeterminadoDescripción
strip_tagsfalseElimina tags HTML sin equivalente en Markdown, manteniendo su contenido
remove_nodes''Lista de tags separadas por espacio para eliminar completamente (incluyendo contenido)
hard_breakfalseConvierte <br> a \n en lugar de \n (estilo GFM)
strip_placeholder_linksfalseElimina tags <a> sin atributo href
header_style'setext'Usa 'atx' para headers con # en H1/H2
preserve_commentsfalseMantiene 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:

php
$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:

php
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:

php
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:

php
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:

php
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 found

Corrige instalando la extensión PHP XML:

bash
# CentOS/RHEL
sudo yum install php-xml

# Ubuntu/Debian
sudo apt-get install php-xml

Advertencias de HTML Malformado

Suprime advertencias para HTML malformado (común con contenido extraído):

php
$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_tags y remove_nodes para limpiar elementos no deseados
  • Agrega TableConverter para 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.