Konwersja HTML na Markdown za pomocą Pythona: Kompletny przewodnik

Python do konwersji HTML na czysty, gotowy do użycia przez LLM Markdown

Page content

Konwersja HTML na Markdown to podstawowe zadanie w współczesnych przepływach pracy programistycznych, szczególnie przygotowując treści internetowe do Large Language Models (LLM), systemów dokumentacji lub generatorów stron statycznych takich jak Hugo.

Choć HTML jest zaprojektowany do przeglądarek internetowych z bogatym stylizowaniem i strukturą, Markdown oferuje czysty, czytelny format, który jest idealny do przetwarzania tekstu, kontroli wersji i konsumpcji przez AI. Jeśli jesteś nowy w składni Markdown, sprawdź nasz Markdown Cheatsheet dla kompletnego odniesienia.

infografika: konwersja strony z html na markdown

W tej szczegółowej recenzji omówimy sześć pakietów Pythona do konwersji HTML na Markdown, oferując praktyczne przykłady kodu, benchmarki wydajnościowe i rzeczywiste przypadki użycia. Niezależnie od tego, czy budujesz pipeline treningowy LLM, czy migrujesz bloga do Hugo, czy skrapujesz dokumentację, znajdziesz idealne narzędzie do swojej pracy.

Alternatywny podejście: Jeśli potrzebujesz bardziej inteligentnego wyodrębniania treści z zrozumieniem semantycznym, możesz również rozważyć konwersję HTML na Markdown za pomocą LLM i Ollama, która oferuje AI-powered konwersję dla złożonych układów.

Co się nauczysz:

  • Szczegółowa analiza 6 bibliotek z zaletami i wadami każdej
  • Benchmarki wydajnościowe z rzeczywistymi przykładami HTML
  • Przykłady kodu gotowych do użycia w typowych przypadkach użycia
  • Najlepsze praktyki dla przepływów pracy przygotowania danych do LLM
  • Konkretnne rekomendacje w zależności od Twoich wymagań

Dlaczego Markdown dla przygotowania danych do LLM?

Przed zanurzeniem się w narzędziach, zrozummy, dlaczego Markdown jest szczególnie wartościowy dla przepływów pracy LLM:

  1. Efektywność tokenów: Markdown wykorzystuje znacznie mniej tokenów niż HTML dla tej samej treści
  2. Jasność semantyczna: Markdown zachowuje strukturę dokumentu bez zbędnych tagów
  3. Czytelność: I ludzie, i LLM mogą łatwo przetwarzać składnię Markdown
  4. Spójność: Standardowy format zmniejsza niejednoznaczność we wejściach modelu
  5. Przechowywanie: Mniejsze rozmiary plików dla danych treningowych i okien kontekstowych

Zalety Markdown rozciągają się poza konwersję HTML – możesz również konwertować dokumenty Word na Markdown dla przepływów pracy dokumentacji, lub używać go w systemach zarządzania wiedzą takich jak Obsidian do zarządzania wiedzą osobistą.

TL;DR - Macierz szybkiego porównania

Jeśli jesteś w pośpiechu, oto kompletny przegląd wszystkich sześciu bibliotek na szybko. Ta tabela pomoże Ci szybko zidentyfikować, które narzędzie odpowiada Twoim konkretnym wymaganiom:

Funkcja html2text markdownify html-to-markdown trafilatura domscribe html2md
Wsparcie HTML5 Częściowe Częściowe Pełne Pełne Pełne Pełne
Typy wskazówek Nie Nie Tak Częściowe Nie Częściowe
Własne procedury obsługi Ograniczone Wspaniałe Dobre Ograniczone Dobre Ograniczone
Wsparcie dla tabel Podstawowe Podstawowe Zaawansowane Dobre Dobre Dobre
Wsparcie asynchroniczne Nie Nie Nie Nie Nie Tak
Wyodrębnianie treści Nie Nie Nie Wspaniałe Nie Dobre
Wyodrębnianie metadanych Nie Nie Tak Wspaniałe Nie Tak
Narzędzie CLI Nie Nie Tak Tak Nie Tak
Szybkość Średnia Wolna Szybka Bardzo szybka Średnia Bardzo szybka
Aktywne rozwijanie Nie Tak Tak Tak Ograniczone Tak
Wersja Pythona 3.6+ 3.7+ 3.9+ 3.6+ 3.8+ 3.10+
Zależności Brak BS4 lxml lxml BS4 aiohttp

Szybki przewodnik wyboru:

  • Potrzebujesz szybkości? → trafilatura lub html2md
  • Potrzebujesz dostosowania? → markdownify
  • Potrzebujesz bezpieczeństwa typów? → html-to-markdown
  • Potrzebujesz prostoty? → html2text
  • Potrzebujesz wyodrębniania treści? → trafilatura

Konkurenci: Porównanie 6 pakietów Pythona

Zanurzmy się głębiej w każdy z bibliotek z praktycznymi przykładami kodu, opcjami konfiguracji i rzeczywistymi wskazówkami. Każda sekcja zawiera instrukcje instalacji, wzorce użycia i szczere oceny zalet i ograniczeń.

1. html2text - Klasyczna opcja

Oryginalnie opracowany przez Aaron Swartz, html2text był stalowym elementem ekosystemu Pythona przez ponad dekada. Skupia się na generowaniu czystego, czytelnego kodu Markdown.

Instalacja:

pip install html2text

Podstawowe użycie:

import html2text

# Utwórz instancję konwertera
h = html2text.HTML2Text()

# Skonfiguruj opcje
h.ignore_links = False
h.ignore_images = False
h.ignore_emphasis = False
h.body_width = 0  # Nie zawijaj linii

html_content = """
<h1>Witaj w Scrapingu Internetowym</h1>
<p>To jest <strong>kompleksowy przewodnik</strong> po wyodrębnianiu treści.</p>
<ul>
    <li>Łatwe w użyciu</li>
    <li>Testowane w praktyce</li>
    <li>Szeroko stosowane</li>
</ul>
<a href="https://example.com">Dowiedz się więcej</a>
"""

markdown = h.handle(html_content)
print(markdown)

Wyjście:

# Witaj w Scrapingu Internetowym

To jest **kompleksowy przewodnik** po wyodrębnianiu treści.

  * Łatwe w użyciu
  * Testowane w praktyce
  * Szeroko stosowane

[Dowiedz się więcej](https://example.com)

Zaawansowana konfiguracja:

import html2text

h = html2text.HTML2Text()

# Pominięcie konkretnych elementów
h.ignore_links = True
h.ignore_images = True

# Kontrola formatowania
h.body_width = 80  # Zawijaj przy 80 znakach
h.unicode_snob = True  # Użyj znaków unicode
h.emphasis_mark = '*'  # Użyj * dla podkreślania zamiast _
h.strong_mark = '**'

# Obsługa tabel
h.ignore_tables = False

# Ochrona tekstu sformatowanego
h.protect_links = True

Zalety:

  • Dojrzała i stabilna (15+ lat rozwoju)
  • Rozszerzona konfiguracja
  • Dobrze radzi sobie z przypadkami granicznymi
  • Brak zależności zewnętrznych

Wady:

  • Ograniczone wsparcie dla HTML5
  • Może generować niezgodne odstępy
  • Nie jest aktywnie utrzymywane (ostatnia duża aktualizacja w 2020 roku)
  • Tylko przetwarzanie jednowątkowe

Najlepsze do: Prostych dokumentów HTML, systemów legacy, kiedy stabilność jest kluczowa


2. markdownify - Opcja elastyczna

markdownify korzysta z BeautifulSoup4, aby zapewnić elastyczne parsowanie HTML z dostosowalną obsługą tagów.

Instalacja:

pip install markdownify

Podstawowe użycie:

from markdownify import markdownify as md

html = """
<article>
    <h2>Nowoczesne rozwój internetowy</h2>
    <p>Budowanie z <code>Python</code> i <em>nowoczesnymi frameworkami</em>.</p>
    <blockquote>
        <p>Prostota to najwyższa sofistykacja.</p>
    </blockquote>
</article>
"""

markdown = md(html)
print(markdown)

Wyjście:


## Nowoczesne rozwój internetowy

Budowanie z `Python` i *nowoczesnymi frameworkami*.

> Prostota to najwyższa sofistykacja.

Zaawansowane użycie z dostosowanymi procedurami obsługi:

from markdownify import MarkdownConverter

class CustomConverter(MarkdownConverter):
    """
    Utwórz niestandardowy konwerter z konkretną obsługą tagów
    """
    def convert_img(self, el, text, convert_as_inline):
        """Niestandardowy handler obrazu z tekstem alternatywnym"""
        alt = el.get('alt', '')
        src = el.get('src', '')
        title = el.get('title', '')

        if title:
            return f'![{alt}]({src} "{title}")'
        return f'![{alt}]({src})'

    def convert_pre(self, el, text, convert_as_inline):
        """Zwiększone obsługę bloków kodu z wykrywaniem języka"""
        code = el.find('code')
        if code:
            # Wyodrębnij język z atrybutu klasy (np. 'language-python')
            classes = code.get('class', [''])
            language = classes[0].replace('language-', '') if classes else ''
            return f'\n```{language}\n{code.get_text()}\n```\n'
        return f'\n```\n{text}\n```\n'

# Użyj niestandardowego konwertera
html = '<pre><code class="language-python">def hello():\n    print("world")</code></pre>'
markdown = CustomConverter().convert(html)
print(markdown)

Dla więcej szczegółów na temat pracy z blokami kodu Markdown i podświetlania składni, zobacz nasz przewodnik Użycie bloków kodu Markdown.

Wybórowy konwersja tagów:

from markdownify import markdownify as md

# Usuń konkretne tagi całkowicie
markdown = md(html, strip=['script', 'style', 'nav'])

# Konwertuj tylko konkretne tagi
markdown = md(
    html,
    heading_style="ATX",  # Użyj # dla nagłówków
    bullets="-",  # Użyj - dla punktów
    strong_em_symbol="*",  # Użyj * dla podkreślania
)

Zalety:

  • Oparty na BeautifulSoup4 (solidne parsowanie HTML)
  • Bardzo elastyczny dzięki dziedziczeniu
  • Aktywne utrzymanie
  • Dobra dokumentacja

Wady:

  • Wymaga zależności BeautifulSoup4
  • Może być wolniejszy dla dużych dokumentów
  • Ograniczona wbudowana obsługa tabel

Najlepsze do: Niestandardowa konwersja, projekty już korzystające z BeautifulSoup4


3. html-to-markdown - Nowoczesna potęga

html-to-markdown to kompletnie typowany, nowoczesny pakiet z pełnym wsparciem dla HTML5 i szerokimi opcjami konfiguracji.

Instalacja:

pip install html-to-markdown

Podstawowe użycie:

from html_to_markdown import convert

html = """
<article>
    <h1>Dokumentacja techniczna</h1>
    <table>
        <thead>
            <tr>
                <th>Funkcja</th>
                <th>Wsparcie</th>
            </tr>
        </thead>
        <tbody>
            <tr>
                <td>HTML5</td>
                <td>✓</td>
            </tr>
            <tr>
                <td>Tabele</td>
                <td>✓</td>
            </tr>
        </tbody>
    </table>
</article>
"""

markdown = convert(html)
print(markdown)

Zaawansowana konfiguracja:

from html_to_markdown import convert, Options

# Utwórz niestandardowe opcje
options = Options(
    heading_style="ATX",
    bullet_style="-",
    code_language_default="python",
    strip_tags=["script", "style"],
    escape_special_chars=True,
    table_style="pipe",  # Użyj | dla tabel
    preserve_whitespace=False,
    extract_metadata=True,  # Wyodrębnij tagi meta
)

markdown = convert(html, options=options)

Interfejs wiersza poleceń:

# Konwertuj pojedynczy plik
html-to-markdown input.html -o output.md

# Konwertuj z opcjami
html-to-markdown input.html \
    --heading-style atx \
    --strip-tags script,style \
    --extract-metadata

# Konwertuj w partii
find ./html_files -name "*.html" -exec html-to-markdown {} -o ./markdown_files/{}.md \;

Zalety:

  • Pełne wsparcie dla HTML5 w tym elementów semantycznych
  • Typowe bezpieczeństwo z komprehensywnymi wskazówkami typów
  • Zwiększone obsługa tabel (scalane komórki, wyrównanie)
  • Możliwość wyodrębniania metadanych
  • Aktywne rozwijanie i nowoczesna baza kodu

Wady:

  • Wymaga Pythona 3.9+
  • Większy zasób zależności
  • Wyższy poziom nauki

Najlepsze do: Złożonych dokumentów HTML5, projektów typowo bezpiecznych, systemów produkcyjnych


4. trafilatura - Ekspert w wyodrębnianiu treści

trafilatura nie jest tylko konwerterem HTML na Markdown – to inteligentna biblioteka wyodrębniania treści specjalnie zaprojektowana do skrapowania internetowego i ekstrakcji artykułów.

Instalacja:

pip install trafilatura

Podstawowe użycie:

import trafilatura

# Pobierz i wyodrębnij z adresu URL
url = "https://example.com/article"
downloaded = trafilatura.fetch_url(url)
markdown = trafilatura.extract(downloaded, output_format='markdown')
print(markdown)

Uwaga: Trafilatura zawiera wbudowane pobieranie URL, ale dla bardziej złożonych operacji HTTP, możesz znaleźć pomocny nasz cURL Cheatsheet przy pracy z API lub punktami końcowymi uwierzytelnionymi.

Zaawansowane wyodrębnianie treści:

import trafilatura
from trafilatura.settings import use_config

# Utwórz niestandardową konfigurację
config = use_config()
config.set("DEFAULT", "EXTRACTION_TIMEOUT", "30")

html = """
<html>
<head><title>Tytuł artykułu</title></head>
<body>
    <nav>Menu nawigacyjne</nav>
    <article>
        <h1>Główny artykuł</h1>
        <p>Ważna treść tutaj.</p>
    </article>
    <aside>Reklama</aside>
    <footer>Treść stopki</footer>
</body>
</html>
"""

# Wyodrębnij tylko główną treść
markdown = trafilatura.extract(
    html,
    output_format='markdown',
    include_comments=False,
    include_tables=True,
    include_images=True,
    include_links=True,
    config=config
)

# Wyodrębnij z metadane
result = trafilatura.extract(
    html,
    output_format='markdown',
    with_metadata=True
)

if result:
    print(f"Tytuł: {result.get('title', 'N/A')}")
    print(f"Autor: {result.get('author', 'N/A')}")
    print(f"Data: {result.get('date', 'N/A')}")
    print(f"\nTreść:\n{result.get('text', '')}")

Przetwarzanie w partii:

import trafilatura
from concurrent.futures import ThreadPoolExecutor
from pathlib import Path

def process_url(url):
    """Wyodrębnij markdown z adresu URL"""
    downloaded = trafilatura.fetch_url(url)
    if downloaded:
        return trafilatura.extract(
            downloaded,
            output_format='markdown',
            include_links=True,
            include_images=True
        )
    return None

# Przetwarzaj wiele adresów URL równolegle
urls = [
    "https://example.com/article1",
    "https://example.com/article2",
    "https://example.com/article3",
]

with ThreadPoolExecutor(max_workers=5) as executor:
    results = list(executor.map(process_url, urls))

for i, markdown in enumerate(results):
    if markdown:
        Path(f"article_{i}.md").write_text(markdown, encoding='utf-8')

Zalety:

  • Inteligentne wyodrębnianie treści (usuwanie zbędnych elementów)
  • Wbudowane pobieranie URL z solidnym obsługą błędów
  • Wyodrębnianie metadanych (tytuł, autor, data)
  • Wykrywanie języka
  • Optymalizacja dla artykułów i blogów
  • Szybkie parsowanie oparte na C

Wady:

  • Może zbyt bardzo usuwać treści dla ogólnego HTML
  • Skupia się na ekstrakcji artykułów (nie jest ogólnym narzędziem)
  • Złożoność konfiguracji dla przypadków granicznych

Najlepsze do: Skrapowanie internetowe, ekstrakcja artykułów, przygotowanie danych treningowych dla LLM


5. domscribe - Przechowujący znaczenie

domscribe skupia się na zachowaniu znaczenia HTML podczas konwersji na Markdown.

Instalacja:

pip install domscribe

Podstawowe użycie:

from domscribe import html_to_markdown

html = """
<article>
    <header>
        <h1>Zrozumienie semantycznego HTML</h1>
        <time datetime="2024-10-24">24 października 2024</time>
    </header>
    <section>
        <h2>Wprowadzenie</h2>
        <p>Semantyczne HTML nadaje <mark>znaczenie</mark> treści.</p>
    </section>
    <aside>
        <h3>Powiązane tematy</h3>
        <ul>
            <li>Dostępność</li>
            <li>SEO</li>
        </ul>
    </aside>
</article>
"""

markdown = html_to_markdown(html)
print(markdown)

Niestandardowe opcje:

from domscribe import html_to_markdown, MarkdownOptions

options = MarkdownOptions(
    preserve_semantic_structure=True,
    include_aria_labels=True,
    strip_empty_elements=True
)

markdown = html_to_markdown(html, options=options)

Zalety:

  • Zachowuje strukturę semantyczną HTML5
  • Dobrze radzi sobie z nowoczesnymi komponentami sieciowymi
  • Czysty projekt API

Wady:

  • Nadal w wczesnym rozwoju (API może się zmienić)
  • Mniejsza dokumentacja w porównaniu do dojrzałych alternatyw
  • Mniejsza społeczność i mniej dostępnych przykładów

Najlepsze do: Dokumentów HTML5 semantycznych, projektów skupionych na dostępności, kiedy zachowanie struktury semantycznej HTML5 jest krytyczne

Uwaga: Choć domscribe jest nowszy i mniej testowany niż alternatywy, wypełnia konkretny niszowy wymóg dla zachowania semantycznego HTML, który inne narzędzia nie priorytetyzują.


6. html2md - Potęga asynchroniczna

html2md jest zaprojektowany do wysokiej wydajnościowej konwersji w partii z asynchronicznym przetwarzaniem.

Instalacja:

pip install html2md

Użycie wiersza poleceń:

# Konwertuj cały katalog
m1f-html2md convert ./website -o ./docs

# Z ustawieniami niestandardowymi
m1f-html2md convert ./website -o ./docs \
    --remove-tags nav,footer \
    --heading-offset 1 \
    --detect-language

# Konwertuj pojedynczy plik
m1f-html2md convert index.html -o readme.md

Użycie programistyczne:

import asyncio
from html2md import convert_html

async def convert_files():
    """Asynchroniczne przetwarzanie w partii"""
    html_files = [
        'page1.html',
        'page2.html',
        'page3.html'
    ]

    tasks = [convert_html(file) for file in html_files]
    results = await asyncio.gather(*tasks)
    return results

# Uruchom konwersję
results = asyncio.run(convert_files())

Zalety:

  • Asynchroniczne przetwarzanie dla wysokiej wydajności
  • Inteligentne wykrywanie selektorów treści
  • Generowanie YAML frontmatter (wspaniałe dla Hugo!)
  • Wykrywanie języka kodu
  • Wsparcie dla przetwarzania równoległego

Wady:

  • Wymaga Pythona 3.10+
  • Skupia się na CLI (mniej elastyczny API)
  • Dokumentacja mogłaby być bardziej kompletna

Najlepsze do: Dużych migracji, konwersji w partii, migracji Hugo/Jekyll


Benchmarkowanie wydajności

Wydajność ma znaczenie, szczególnie przy przetwarzaniu tysięcy dokumentów dla treningu LLM lub dużych migracji. Zrozumienie różnic w prędkości pomiedzy bibliotekami pomaga w podejmowaniu świadomych decyzji dla Twojej pracy.

Porównanie wydajności:

Na podstawie typowych wzorców użycia, oto jak te biblioteki porównują się w trzech realistycznych scenariuszach:

  1. Prosty HTML: Prosty wpis blogowy z tekstem, nagłówkami i linkami (5KB)
  2. Złożony HTML: Dokumentacja techniczna z zagnieżdżonymi tabelami i blokami kodu (50KB)
  3. Rzeczywista strona internetowa: Pełna strona internetowa w tym nawigacja, stopka, boczny panel i reklamy (200KB)

Oto przykład kodu benchmarkowania, którego możesz użyć, aby samodzielnie przetestować te biblioteki:

import time
import html2text
from markdownify import markdownify
from html_to_markdown import convert
import trafilatura

def benchmark(html_content, iterations=100):
    """Benchmarkuj szybkość konwersji"""

    # html2text
    start = time.time()
    h = html2text.HTML2Text()
    for _ in range(iterations):
        _ = h.handle(html_content)
    html2text_time = time.time() - start

    # markdownify
    start = time.time()
    for _ in range(iterations):
        _ = markdownify(html_content)
    markdownify_time = time.time() - start

    # html-to-markdown
    start = time.time()
    for _ in range(iterations):
        _ = convert(html_content)
    html_to_markdown_time = time.time() - start

    # trafilatura
    start = time.time()
    for _ in range(iterations):
        _ = trafilatura.extract(html_content, output_format='markdown')
    trafilatura_time = time.time() - start

    return {
        'html2text': html2text_time,
        'markdownify': markdownify_time,
        'html-to-markdown': html_to_markdown_time,
        'trafilatura': trafilatura_time
    }

Typowe cechy wydajności (przykładowe względne prędkości):

Pakiet Prosty (5KB) Złożony (50KB) Rzeczywista strona (200KB)
html2text Średnia Wolniejsza Najwolniejsza
markdownify Wolniejsza Wolniejsza Najwolniejsza
html-to-markdown Szybka Szybka Szybka
trafilatura Szybka Bardzo szybka Bardzo szybka
html2md (asynchroniczny) Bardzo szybki Bardzo szybki Najbardziej szybki

Główne obserwacje:

  • html2md i trafilatura są najbardziej szybkie dla złożonych dokumentów, idealne do przetwarzania w partii
  • html-to-markdown oferuje najlepszy balans szybkości i funkcji dla użycia produkcyjnego
  • markdownify jest wolniejszy, ale najbardziej elastyczny – koszt-wartość warte, kiedy potrzebujesz niestandardowych procedur obsługi
  • html2text pokazuje swoje wiekowe ograniczenia z wolniejszą wydajnością, ale nadal stabilny dla prostych przypadków użycia

Uwaga: Różnice w wydajności stają się znaczące tylko przy przetwarzaniu setek lub tysięcy plików. Dla rzadkich konwersji, dowolna biblioteka będzie działać dobrze. Skup się na funkcjach i możliwości dostosowania zamiast na wydajności.

Przykłady zastosowań w praktyce

Teoria jest pomocna, ale praktyczne przykłady pokazują, jak te narzędzia działają w środowisku produkcyjnym. Oto cztery typowe scenariusze z kompletnym, gotowym do użycia kodem, który możesz dostosować do własnych projektów.

Przypadek użycia 1: Przygotowanie danych treningowych dla LLM

Wymagania: Wyodrębnienie czystego tekstu z tysięcy stron dokumentacji

Zalecane: trafilatura + przetwarzanie równoległe

import trafilatura
from pathlib import Path
from concurrent.futures import ProcessPoolExecutor

def process_html_file(html_path):
    """Konwersja pliku HTML na markdown"""
    html = Path(html_path).read_text(encoding='utf-8')
    markdown = trafilatura.extract(
        html,
        output_format='markdown',
        include_links=False,  # Usuń, aby uzyskać czystsze dane treningowe
        include_images=False,
        include_comments=False
    )

    if markdown:
        output_path = html_path.replace('.html', '.md')
        Path(output_path).write_text(markdown, encoding='utf-8')
        return len(markdown)
    return 0

# Przetwarzanie 10 000 plików równolegle
html_files = list(Path('./docs').rglob('*.html'))

with ProcessPoolExecutor(max_workers=8) as executor:
    token_counts = list(executor.map(process_html_file, html_files))

print(f"Przetworzono {len(html_files)} plików")
print(f"Łączna liczba znaków: {sum(token_counts):,}")

Przypadek użycia 2: Migracja bloga Hugo

Wymagania: Przeniesienie bloga WordPress do Hugo z frontmatter

Zalecane: html2md CLI

Hugo to popularny generator statycznych stron internetowych, który korzysta z Markdown do zawartości. Dla dodatkowych wskazówek specyficznych dla Hugo, sprawdź nasz Hugo Cheat Sheet oraz dowiedz się, jak dodać strukturalne oznaczenia danych do Hugo w celu poprawienia SEO.

# Konwersja wszystkich wpisów z frontmatter
m1f-html2md convert ./wordpress-export \
    -o ./hugo/content/posts \
    --generate-frontmatter \
    --heading-offset 0 \
    --remove-tags script,style,nav,footer

Lub programowo:

from html_to_markdown import convert, Options
from pathlib import Path
import yaml

def migrate_post(html_file):
    """Konwersja HTML z WordPressa na markdown dla Hugo"""
    html = Path(html_file).read_text()

    # Wyodrębnienie tytułu i daty z HTML
    from bs4 import BeautifulSoup
    soup = BeautifulSoup(html, 'html.parser')
    title = soup.find('h1').get_text() if soup.find('h1') else 'Bez tytułu'

    # Konwersja na markdown
    options = Options(strip_tags=['script', 'style', 'nav', 'footer'])
    markdown = convert(html, options=options)

    # Dodanie frontmatter dla Hugo
    frontmatter = {
        'title': title,
        'date': '2024-10-24',
        'draft': False,
        'tags': []
    }

    output = f"---\n{yaml.dump(frontmatter)}---\n\n{markdown}"

    # Zapis
    output_file = html_file.replace('.html', '.md')
    Path(output_file).write_text(output, encoding='utf-8')

# Przetwarzanie wszystkich wpisów
for html_file in Path('./wordpress-export').glob('*.html'):
    migrate_post(html_file)

Przypadek użycia 3: Skraper dokumentacji z niestandardowym formatowaniem

Wymagania: Scrapowanie technicznych dokumentacji z niestandardowym obsługą bloków kodu

Zalecane: markdownify z niestandardowym konwerterem

Ten podejście jest szczególnie przydatny przy migracji dokumentacji z systemów wiki. Jeśli zarządzasz dokumentacją, możesz być również zainteresowany DokuWiki - samozhostowany wiki i alternatywy dla rozwiązań dokumentacji samozhostowanych.

from markdownify import MarkdownConverter
import requests

class DocsConverter(MarkdownConverter):
    """Niestandardowy konwerter dla dokumentacji technicznej"""

    def convert_pre(self, el, text, convert_as_inline):
        """Zwiększone bloki kodu z podświetleniem składni"""
        code = el.find('code')
        if code:
            # Wyodrębnienie języka z klasy
            classes = code.get('class', [])
            language = next(
                (c.replace('language-', '') for c in classes if c.startswith('language-')),
                'text'
            )
            return f'\n```{language}\n{code.get_text()}\n```\n'
        return super().convert_pre(el, text, convert_as_inline)

    def convert_div(self, el, text, convert_as_inline):
        """Obsługa specjalnych bloków dokumentacji"""
        classes = el.get('class', [])

        # Bloki ostrzeżeń
        if 'warning' in classes:
            return f'\n> ⚠️ **Ostrzeżenie**: {text}\n'

        # Bloki informacji
        if 'info' in classes or 'note' in classes:
            return f'\n> 💡 **Uwaga**: {text}\n'

        return text

def scrape_docs(url):
    """Scrapowanie i konwersja strony dokumentacji"""
    response = requests.get(url)
    markdown = DocsConverter().convert(response.text)
    return markdown

# Użycie
docs_url = "https://docs.example.com/api-reference"
markdown = scrape_docs(docs_url)
Path('api-reference.md').write_text(markdown)

Przypadek użycia 4: Newsletter do archiwum Markdown

Wymagania: Konwersja HTML newsletterów do czytelnego markdown

Zalecane: html2text z konfiguracją specyficzną

import html2text
import email
from pathlib import Path

def convert_newsletter(email_file):
    """Konwersja HTML newslettera na markdown"""
    # Parsowanie e-maila
    with open(email_file, 'r') as f:
        msg = email.message_from_file(f)

    # Pobranie części HTML
    html_content = None
    for part in msg.walk():
        if part.get_content_type() == 'text/html':
            html_content = part.get_payload(decode=True).decode('utf-8')
            break

    if not html_content:
        return None

    # Konfiguracja konwertera
    h = html2text.HTML2Text()
    h.ignore_images = False
    h.images_to_alt = True
    h.body_width = 0
    h.protect_links = True
    h.unicode_snob = True

    # Konwersja
    markdown = h.handle(html_content)

    # Dodanie metadanych
    subject = msg.get('Subject', 'Brak tytułu')
    date = msg.get('Date', '')

    output = f"# {subject}\n\n*Data: {date}*\n\n---\n\n{markdown}"

    return output

# Przetwarzanie archiwum newsletterów
for email_file in Path('./newsletters').glob('*.eml'):
    markdown = convert_newsletter(email_file)
    if markdown:
        output_file = email_file.with_suffix('.md')
        output_file.write_text(markdown, encoding='utf-8')

Zalecenia według scenariusza

Wciąż nie wiesz, który bibliotekę wybrać? Oto moja ostateczna wskazówka oparta na konkretnych przypadkach użycia. Te rekomendacje wynikają z doświadczenia praktycznego z każdej biblioteki w środowiskach produkcyjnych.

Dla scrapowania sieci i przetwarzania LLM

Zwycięzca: trafilatura

Trafilatura wyróżnia się w ekstrakcji czystego tekstu, jednocześnie usuwając zbędny materiał. Idealna do:

  • Budowania zestawów danych treningowych dla LLM
  • Agregacji treści
  • Zbierania prac naukowych
  • Ekstrakcji artykułów prasowych

Dla migracji Hugo/Jekyll

Zwycięzca: html2md

Asynchroniczne przetwarzanie i generowanie frontmatter sprawia, że masowe migracje są szybkie i łatwe:

  • Konwersje w partii
  • Automatyczne wyodrębnianie metadanych
  • Generowanie frontmatter w formacie YAML
  • Dostosowanie poziomu nagłówków

Dla niestandardowej logiki konwersji

Zwycięzca: markdownify

Dziedziczenie konwertera pozwala na pełną kontrolę:

  • Niestandardowe obsługiwane tagi
  • Konwersje specyficzne dla dziedziny
  • Wymagania dotyczące formatowania
  • Integracja z istniejącym kodem BeautifulSoup

Dla systemów produkcyjnych z typowym bezpieczeństwem

Zwycięzca: html-to-markdown

Nowoczesny, typowo bezpieczny i pełen funkcji:

  • Pełna obsługa HTML5
  • Kompleksowe wskazówki typowe
  • Zaawansowane obsługiwane tabele
  • Aktywne utrzymanie

Dla prostych, stabilnych konwersji

Zwycięzca: html2text

Kiedy potrzebujesz czegoś, co “działa”:

  • Brak zależności
  • Testowane w praktyce
  • Rozszerzalna konfiguracja
  • Wsparcie na szerokim zakresie platform

Najlepsze praktyki dla przetwarzania LLM

Niezależnie od wybranego przez Ciebie biblioteki, przestrzeganie tych najlepszych praktyk zapewni wysokiej jakości wyjście w formacie Markdown zoptymalizowane do konsumpcji przez LLM. Te wzorce udowodniły swoje znaczenie w przepływach pracy produkcyjnych przetwarzających miliony dokumentów.

1. Oczyść przed konwersją

Zawsze usuwaj niechciane elementy przed konwersją, aby uzyskać czystszy wynik i lepszą wydajność:

from bs4 import BeautifulSoup
import trafilatura

def clean_and_convert(html):
    """Usuń niechciane elementy przed konwersją"""
    soup = BeautifulSoup(html, 'html.parser')

    # Usuń niechciane elementy
    for element in soup(['script', 'style', 'nav', 'footer', 'header', 'aside']):
        element.decompose()

    # Usuń reklamy i śledzenie
    for element in soup.find_all(class_=['ad', 'advertisement', 'tracking']):
        element.decompose()

    # Konwertuj wyczyszczony HTML
    markdown = trafilatura.extract(
        str(soup),
        output_format='markdown'
    )

    return markdown

2. Normalizuj białe znaki

Różne konwertery obsługują białe znaki inaczej. Normalizuj wynik, aby zapewnić spójność w całym zbiorze:

import re

def normalize_markdown(markdown):
    """Wyczyść spacje w markdownie"""
    # Usuń wielokrotne puste linie
    markdown = re.sub(r'\n{3,}', '\n\n', markdown)

    # Usuń końcowe białe znaki
    markdown = '\n'.join(line.rstrip() for line in markdown.split('\n'))

    # Upewnij się, że jest jedna linia końcowa
    markdown = markdown.rstrip() + '\n'

    return markdown

3. Waliduj wynik

Kontrola jakości jest kluczowa. Zaimplementuj walidację, aby wczesnie wykrywać błędy konwersji:

def validate_markdown(markdown):
    """Walidacja jakości markdownu"""
    issues = []

    # Sprawdź resztki HTML
    if '<' in markdown and '>' in markdown:
        issues.append("Wykryto tagi HTML")

    # Sprawdź uszkodzone linki
    if '[' in markdown and ']()' in markdown:
        issues.append("Wykryto pusty link")

    # Sprawdź nadmierną liczbę bloków kodu
    code_block_count = markdown.count('```')
    if code_block_count % 2 != 0:
        issues.append("Nie zamknięty blok kodu")

    return len(issues) == 0, issues

4. Szablon przetwarzania w partii

Podczas przetwarzania dużych zbiorów dokumentów, użyj tego gotowego do użycia szablonu z odpowiednim obsługiwaniem błędów, logowaniem i przetwarzaniem równoległym:

from pathlib import Path
from concurrent.futures import ProcessPoolExecutor
import trafilatura
import logging

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

def process_file(html_path):
    """Przetwarzanie pojedynczego pliku HTML"""
    try:
        html = Path(html_path).read_text(encoding='utf-8')
        markdown = trafilatura.extract(
            html,
            output_format='markdown',
            include_links=True,
            include_images=False
        )

        if markdown:
            # Normalizacja
            markdown = normalize_markdown(markdown)

            # Walidacja
            is_valid, issues = validate_markdown(markdown)
            if not is_valid:
                logger.warning(f"{html_path}: {', '.join(issues)}")

            # Zapis
            output_path = Path(str(html_path).replace('.html', '.md'))
            output_path.write_text(markdown, encoding='utf-8')

            return True

        return False

    except Exception as e:
        logger.error(f"Błąd przetwarzania {html_path}: {e}")
        return False

def batch_convert(input_dir, max_workers=4):
    """Konwersja wszystkich plików HTML w katalogu"""
    html_files = list(Path(input_dir).rglob('*.html'))
    logger.info(f"Znaleziono {len(html_files)} plików HTML")

    with ProcessPoolExecutor(max_workers=max_workers) as executor:
        results = list(executor.map(process_file, html_files))

    success_count = sum(results)
    logger.info(f"Pomyślnie przekonwertowano {success_count}/{len(html_files)} plików")

# Użycie
batch_convert('./html_docs', max_workers=8)

Podsumowanie

Ekosystem Pythona oferuje dojrzałe, gotowe do użycia narzędzia do konwersji HTML na Markdown, każde zoptymalizowane dla różnych scenariuszy. Twój wybór powinien być zgodny z Twoimi konkretnymi wymaganiami:

  • Szybkie konwersje: Użyj html2text z powodu prostoty i braku zależności
  • Niestandardowa logika: Użyj markdownify dla maksymalnej elastyczności poprzez dziedziczenie
  • Scrapowanie sieci: Użyj trafilatura do inteligentnej ekstrakcji treści z usuwaniem zbędnych elementów
  • Masowe migracje: Użyj html2md do asynchronicznej wydajności w dużych projektach
  • Systemy produkcyjne: Użyj html-to-markdown do bezpieczeństwa typów i pełnej obsługi HTML5
  • Zachowanie semantyki: Użyj domscribe do utrzymania struktury semantycznej HTML5

Zalecenia dla przepływów pracy LLM

Dla przepływów pracy LLM, zaleca się dwuetapowy podejście:

  1. Zacznij od trafilatura do początkowej ekstrakcji treści – inteligentnie usuwa nawigację, reklamy i zbędne elementy, zachowując główną treść
  2. Przejdź do html-to-markdown dla skomplikowanych dokumentów wymagających precyzyjnego zachowania struktury, takich jak dokumentacja techniczna z tabelami i blokami kodu

To połączenie skutecznie obsługuje 95% rzeczywistych scenariuszy.

Kolejne kroki

Wszystkie te narzędzia (oprócz html2text) są aktywnie utrzymywane i gotowe do użycia w środowisku produkcyjnym. Lepsze jest:

  1. Zainstalowanie 2-3 bibliotek dopasowanych do Twojego przypadku użycia
  2. Testowanie ich z Twoimi rzeczywistymi próbkami HTML
  3. Testowanie wydajności z typowymi rozmiarami dokumentów
  4. Wybór na podstawie jakości wyników, a nie tylko prędkości

Ekosystem Pythona dla konwersji HTML na Markdown dojrzał znacząco, i nie możesz się pomylić z żadnym z tych wyborów dla ich przeznaczenia.

Dodatkowe zasoby

Uwaga: Ta analiza opiera się na analizie oficjalnej dokumentacji, opinii społeczności i architekturze bibliotek. Charakterystyka wydajności jest reprezentatywna dla typowych wzorców użycia. Dla konkretnych przypadków użycia, uruchom własne testy wydajnościowe z Twoimi rzeczywistymi próbkami HTML.

Inne przydatne artykuły