turndown był najczęściej oznaczoną gwiazdką spośród czterech testowanych bibliotek w momencie wykonania zrzutu metadanych — miał 11 386 gwiazdek na GitHubie. Na czterech wspólnych próbkach HTML wygenerował zero tabel Markdown przy domyślnych ustawieniach i zużył o 24,6% więcej tokenów niż markdownify dla tych samych danych wejściowych.
Każda z tych czterech bibliotek odzyskała wszystkie sygnały treści. Różnice dotyczą wyłącznie tego, co dzieje się ze strukturą — i ile ta struktura kosztuje później.
Co było mierzone i na jakich próbkach
Ta baza badawcza miała już zestaw dla markitdown z pięcioma próbkami HTML i wcześniej zarejestrowanymi probe strings — dokładnymi ciągami sprawdzanymi pod kątem zachowania oraz ciągami pomocniczymi do wykrywania elementów chromu strony. Do porównania zbiorczego użyto czterech próbek wspólnych dla wszystkich czterech konwerterów: katalogu księgarni, strony z cytatami, tabeli statystyk hokejowych i artykułu Wikipedii o web scraping. Piąta próbka, Nothing but tables, służy wyłącznie jako diagnostyka mocno tabelaryczna i jest wyłączona z agregatu 24,6%.
Cztery narzędzia: turndown 7.2.4 (Node), markdownify 1.2.3, html2text 2025.4.15 oraz markitdown, którego opublikowane wyniki wykorzystano bez zmian. Strony: katalog księgarni, strona z cytatami, tabela statystyk hokejowych i artykuł Wikipedii o web scrapingu.
Każda nazwa metryki poniżej odpowiada dokładnie polu artefaktu markitdown, więc wiersze można zestawić obok siebie bez uzgadniania dwóch definicji tego samego pojęcia.
Tabela

| Konwerter | Sygnały treści | Znaki wyjściowe | Tokeny (o200k) | Bajty/token | Wiersze tabel Markdown | Linki |
|---|---|---|---|---|---|---|
| turndown | 16/16 | 95,188 | 26,236 | 3.63 | 0 | 611 |
| markdownify | 16/16 | 76,868 | 21,062 | 3.65 | 36 | 599 |
| html2text | 16/16 | 76,452 | 21,176 | 3.61 | 32 | 545 |
| markitdown | 16/16 | 76,995 | 21,336 | 3.61 | 36 | 598 |
Cztery próbki — te same, które uruchomiono również dla markitdown. Pełne wyniki dla każdej próbki znajdują się w fiveway-scores.json. Tokeny policzono z użyciem o200k_base; wiersze tabel markitdown przeliczone z jego własnego zapisanego Markdowna tym samym licznikiem, co pozostałe.
Zachowanie treści jest remisowe. Wszystkie szesnaście sygnałów treści na czterech próbkach przetrwało w każdym konwerterze. Jeśli jedyne pytanie brzmi: „czy tekst przejdzie dalej?”, każdy z tych czterech odpowiada: tak.
Struktura nie jest remisowa. Na czterech wspólnych próbkach markdownify i markitdown generują po 36 wierszy tabel Markdown; html2text generuje 32; turndown nie generuje żadnego. W osobnej diagnostyce zawierającej wyłącznie tabele markdownify wygenerował 62 wiersze, a html2text 59; tych wierszy nie wliczono do agregatu powyżej.
Koszt tokenów dla turndown jest o 24,6% wyższy, ale powód nie leży w tabelach. Początkowo tak zakładałem, jednak liczby dla poszczególnych próbek pokazują coś innego — patrz niżej.
Co turndown robi z tabelą
Oto próbka ze statystykami hokejowymi — te same wiersze pokazane na trzy sposoby.
turndown:

Team Name
Year
Wins
Losses
Boston Bruins
1990
44
24
markdownify:
| Team Name | Year | Wins | Losses | ... |
| --- | --- | --- | --- | --- |
| Boston Bruins | 1990 | 44 | 24 | ... |
html2text:
Team Name | Year | Wins | Losses | ...
---|---|---|---|---
Boston Bruins | 1990 | 44 | 24 | ...
Każda wartość przechodzi przez konwersję turndown, dlatego narzędzie zdobywa 16/16 w sygnałach. To, co ginie, to informacja o tym, do której kolumny należy dana wartość. Wystarczy spojrzeć na wynik turndown, a 44 staje się po prostu liczbą w osobnej linii; nie da się już odtworzyć, że chodzi o liczbę zwycięstw Bostonu, chyba że zaczniemy liczyć pozycje i założymy, że żadne pole nie było puste. W tej próbce niektóre pola są puste, więc samo liczenie pozycji też nie wystarczy.
Dla modelu czytającego wynik oznacza to różnicę między tabelą, na której da się odpowiadać na pytania, a listą liczb, które model będzie zgadywać.
To nie tyle wada, co udokumentowane ograniczenie — rdzeń turndown nie obsługuje tabel, a turndown-plugin-gfm istnieje właśnie po to, by je dodać. Jednak domyślna instalacja nie zawiera tego dodatku, a 11 386 gwiazdek sugeruje, że wiele osób korzysta właśnie z ustawień domyślnych.
Skąd naprawdę bierze się luka tokenowa
Napisałem akapit powyżej, zakładając, że różnica 24,6% tokenów wynika ze spłaszczonych tabel pojawiających się jako znaki. Potem spojrzałem na wyniki per próbka — i to nie jest prawda.
| Próbka | turndown tokeny ÷ markdownify tokeny |
|---|---|
| Strona z cytatami (bez tabel) | 0.99× |
| Katalog księgarni | 1.06× |
| Statystyki hokejowe (jedna duża tabela) | 1.37× |
| Wikipedia (głównie proza, 9 wierszy tabel) | 1.29× |
| Wyłącznie tabele | 0.78× |
W próbce, która zawiera wyłącznie tabele, turndown jest o 22% tańszy — ponieważ obramowanie w postaci pionowych kresek też kosztuje tokeny, a turndown ich po prostu nie generuje. Samo spłaszczenie tabeli nie jest więc automatycznie karą tokenową.
Próbka z Wikipedii stanowi 74% całości i zawiera dziewięć wierszy tabel. Jej luka licząca 15 378 znaków nie może wynikać z tabel. To jest to:
(function(){var className="client-js vector-feature-language-in-header-enabled…
.mw-parser-output cite.citation{font-style:inherit;word-wrap:break-word}…
(RLQ=window.RLQ||[]).push(function(){mw.config.set({"wgHostname":"mw-web…
turndown nie usuwa treści z <script> i <style>. markdownify i html2text usuwają ją oba. Zliczając znaczniki występujące wyłącznie wewnątrz tych elementów: wynik turndown zawiera 10 znaczników script i 84 znaczniki style we wszystkich próbkach; pozostałe dwa konwertery nie zawierają żadnego z nich. Na stronie Wikipedii osiem linii wewnętrznej konfiguracji JavaScript i CSS MediaWiki odpowiada za 14 644 znaki — 95% całej różnicy (script-style-stripping.json).
To jest wniosek, z którym faktycznie bym pracował. Spłaszczona tabela to problem struktury, który widać. Blok konfiguracji JavaScript w Markdownzie to czysty koszt bez żadnej informacji, a na rzeczywistej stronie internetowej przytłacza wszystko inne w tym porównaniu.
html2text zapisuje tabele, których możesz nie rozpoznać
html2text uzyskał 32 wiersze tam, gdzie markdownify i markitdown miały 36, a pierwsza wersja mojego licznika oceniła go na 1.
To była wada mojego liczenia, nie biblioteki. html2text generuje Team Name | Year | Wins bez zewnętrznych pionowych kresek — to poprawna forma tabeli Markdown, ale niewidoczna dla regexu, który wymaga ^\|.*\|$. Napisałem taki regex, uruchomiłem go i byłem gotów ogłosić, że html2text nie obsługuje tabel.
Obsługuje. Poprawiony licznik używa heurystyki: ciągu kolejnych linii zawierających pionowe kreski oraz wiersza separatora wewnątrz tego ciągu. Dzięki tej regule html2text przechodzi z 1 do 32. To nie jest pełny parser Markdown, więc liczbę wierszy trzeba czytać jako pomiar wykonany według opisanego licznika, a nie jako uniwersalny wynik renderowania.
Warto to wiedzieć, jeśli dalej przetwarzasz Markdown własnym regexem: dwie z tych czterech bibliotek dodają zewnętrzne kreski, a jedna nie.
O licencji, o której nikt nie mówi
| Konwerter | Licencja | Instalacja | Ciepły import | Gwiazdki | Ostatnie wydanie |
|---|---|---|---|---|---|
| turndown | MIT | 3 pakiety npm, 8,8 MiB | 0.056 s | 11,386 | 2026-04-03 |
| markdownify | MIT | 5 pakietów, 1.8 MiB | 0.046 s | 2,235 | 2026-06-30 |
| html2text | GPL-3.0-or-later | 1 pakiet, 0.2 MiB | 0.077 s | 2,168 | 2025-04-15 |
| markitdown | Zobacz metadane pakietu | Nie mierzone w tej instalacji | Nie mierzone | — | — |
install-and-import.json. Każdą bibliotekę zainstalowano w osobnym, pustym środowisku. Licencje potwierdzono w trzech miejscach: w metadanych rejestru, w repozytorium GitHub i w pliku METADATA samego zainstalowanego pakietu, który zawiera wpis License-Expression: GPL-3.0-or-later.
Najlżejsza biblioteka w tym porównaniu instalacji — 1 pakiet, 0.2 MiB — ma licencję GPL-3.0-or-later. Czy to ma znaczenie dla projektu, zależy od tego, jak oprogramowanie jest łączone i dystrybuowane. Traktuj to jako punkt decyzyjny dla osoby odpowiedzialnej za licencje; ten artykuł nie stanowi porady prawnej. markitdown pokazano tutaj jako niezmierzone, ponieważ jego instalacja i licencja nie zostały uchwycone przez ten konkretny artefakt.
Tę różnicę łatwo przeoczyć, bo licencja to jedyna właściwość, która nie pojawia się w benchmarku.
Wszystkie trzy są wyraźnie lżejsze niż biblioteki do ekstrakcji artykułów z tej samej kategorii — tamte zajmują od 21 do 70 MiB. Konwerter to dużo mniejszy element niż ekstraktor i warto rozdzielać je w budżecie zależności.
Dwa czynniki zakłócające, które musiałem naprawić, zanim ta tabela stała się prawdziwa
Powyższe liczby pochodzą z trzeciej wersji. Pierwsze dwie były błędne w sposób wart nazwania, bo oba błędy łatwo odtworzyć.
Pięć próbek kontra cztery. markitdown uruchomiono na czterech z tych pięciu plików; pozostałe trzy biblioteki przeszły wszystkie pięć. Zsumowanie wyników każdego narzędzia dla jego własnego zestawu dało markdownify 98 wierszy tabel wobec 36 markitdown i wyglądało jak luka w możliwościach. Na tych samych czterech próbkach wynik wynosi 36 wobec 36 — dokładny remis. Piąta próbka jest tą najbardziej tabelaryczną, więc zakłócenie działało w najgorszym możliwym kierunku, zawyżając wynik nowych narzędzi względem istniejącego niemal trzykrotnie.

Dwa liczniki, jedna kolumna. Opublikowane md_table_rows markitdown pochodziło z jego własnego kodu, którego nie czytałem. Porównywanie tej liczby z moją mogło oznaczać porównywanie dwóch liczników, a nie dwóch konwerterów. Jego Markdown był zapisany na dysku, więc poprawka polegała na uruchomieniu jednego licznika na wszystkich czterech — i gdy to zrobiłem, przeliczenie markitdown dało dokładnie opublikowaną wartość dla każdej próbki (0, 0, 27, 9). Definicje się zgadzały; po prostu nie mogłem tego wiedzieć bez sprawdzenia.
Żaden z tych błędów nie byłby widoczny w samym wyniku. Oba dałyby pewną siebie, błędną tabelę.
Kto powinien używać czego
Karmisz model albo zapisujesz ustrukturyzowaną treść z takich stron? Zacznij od markdownify. W tym liczniku ma taki sam wynik jak markitdown pod względem liczby wygenerowanych wierszy tabel, mieści się w najniższym klastrze tokenów, ma licencję MIT i instaluje się w 1.8 MiB. Zweryfikuj go na własnych typach stron, zanim ustandaryzujesz wybór.
Budżet zależności liczysz w kilobajtach i niczego nie dystrybuujesz? html2text. Jeden pakiet, 0.2 MiB, tabele zachowane. Najpierw sprawdź kwestię GPL i pamiętaj, że ostatnie wydanie było w kwietniu 2025.
Już pracujesz w stosie Node? turndown, z zainstalowanym obok turndown-plugin-gfm — i usuń <script> oraz <style> z HTML zanim przekażesz go dalej, bo turndown sam tego nie zrobi. Te dwa braki kosztują jedną czwartą więcej tokenów i strukturę tabel, a nie widać ich, dopóki nie zajrzysz do wyniku.
Już konwertujesz inne formaty dokumentów? markitdown obsługuje PDF, Office i inne formaty, a jego wynik HTML jest konkurencyjny wobec dedykowanych konwerterów. Jeden zależny komponent zamiast dwóch też ma swoją wartość.
Gdzie pasuje zarządzane API
Wszystkie cztery narzędzia pracują na HTML-u, który już masz. Żadne nie pobiera strony, nie renderuje JavaScriptu ani nie obsługuje warstwy anty-bot — a dla wielu rzeczywistych celów to właśnie trudniejsza połowa.
Nasz własny stack developerski w Thunderbit obejmuje tę stronę problemu. POST /distill przyjmuje URL i zwraca czysty Markdown gotowy dla LLM, z obsługą renderowania i pobierania; POST /extract zwraca ustrukturyzowany JSON dopasowany przez AI do dostarczonego przez Ciebie JSON Schema, czyli zupełnie inny kształt wyjścia — wiersze zamiast tabeli Markdown, którą trzeba by potem parsować. Oba są dostępne przez serwer MCP i CLI (npx @thunderbit/thunderbit-cli). Cennik znajduje się na stronie cennika Thunderbit.
Uczciwe porównanie: jeśli masz HTML i chcesz Markdown, markdownify jest darmowy i robi to dobrze, a ta tabela pokazuje, które z konkurencyjnych narzędzi też sobie z tym radzą. Jeśli to Ty pobierasz strony albo chcesz ustrukturyzowanych wierszy zamiast tekstu, to już inny zakup.
Szerzej o rynku piszemy w naszym zestawieniu API do web scrapingu, a przegląd open-source scraperów obejmuje rozwiązania self-hosted. Konwersja HTML do Markdown w Pythonie to praktyczny przewodnik, a czym ma być standaryzacja llms.txt pokazuje, dokąd zmierza cała ta kategoria.
Wypróbuj Thunderbit do ekstrakcji danych z sieci
Werdykt
W tym obciążeniu obejmującym cztery próbki najlepszym domyślnym wyborem jest markdownify: taka sama liczba wygenerowanych wierszy tabel jak markitdown przy wspólnym liczniku, liczba tokenów w granicach 1,3% od pozostałych wydajnych konwerterów, licencja MIT i instalacja zajmująca 1.8 MiB.
Ta rozbieżność między popularnością a zmierzonym zachowaniem jest właściwym wnioskiem. turndown to świetna biblioteka, którą bardzo wiele osób zainstalowało bez wtyczki, która dodaje obsługę tabel, a koszt tego wyboru widać jako o jedną czwartą więcej tokenów i strukturę tabel, której już nie ma. Żadna z tych liczb nie pojawia się nigdzie, dopóki się ich nie policzy.
Jeśli masz zapamiętać tylko jedno: sprawdź, co Twój konwerter robi z tabelą, zanim zaufasz jego wynikowi w modelu. Trzy z tych czterech robią coś sensownego. Najpopularniejszy — nie, chyba że wyraźnie o to poprosiłeś.
Wypróbuj Thunderbit do ekstrakcji danych z sieci Get Started Free
FAQ
Czy turndown naprawdę nie obsługuje tabel?
W swoim rdzeniu — nie. Tabele pochodzą z turndown-plugin-gfm, czyli osobnego pakietu, a zwykłe npm install turndown nie dołącza tego dodatku. Bez wtyczki każda komórka przechodzi jako osobny akapit — wartości są zachowane, ale relacje wiersz-kolumna już nie. W czterech próbkach dało to zero wierszy tabel Markdown i o 24,6% więcej tokenów niż markdownify dla tych samych danych.
Dlaczego html2text początkowo wyglądał tak, jakby nie miał tabel?
Bo mój licznik wymagał zewnętrznych pionowych kresek, a html2text ich nie generuje. Team Name | Year | Wins to poprawny Markdown i renderuje się prawidłowo; to po prostu inny styl niż | Team Name | Year |. Poprawiony licznik szuka ciągu linii zawierających pionowe kreski z wierszem separatora, tak jak robi to parser, i html2text przechodzi z 1 wiersza do 32. Jeśli przetwarzasz Markdown własnym regexem, właśnie na tej różnicy się potkniesz.
Czy GPL w html2text to realny problem?
To zależy od tego, jak łączysz i dystrybuujesz oprogramowanie. GPL-3.0-or-later może nakładać obowiązki, których MIT nie nakłada, więc przed wyborem do produktu dystrybuowanego skonsultuj to z osobą odpowiedzialną za licencje. To punkt zgodności, nie porada prawna; tożsamość licencji została potwierdzona w metadanych rejestru, repozytorium i pliku METADATA zainstalowanego pakietu.
Czy te liczby tokenów mają znaczenie także dla innych stron?
Różnica 24,6% wynika głównie z tego, że turndown zachowuje treść z <script> i <style>, więc skala zależy od tego, ile dana strona tego ma — dużo na nowoczesnym CMS-ie, niemal zero na statycznej. Tabele działają w drugą stronę: w próbce zawierającej wyłącznie tabele turndown był o 22% tańszy, bo nie generuje żadnego obramowania w postaci pionowych kresek. Bajty na token mieściły się między 3.61 a 3.65 we wszystkich czterech narzędziach, więc gęstość wyjścia jest wszędzie podobna, a różnica dotyczy ilości. Jeśli liczba ma wpływ na budżet, zmierz własny korpus.
Czego tutaj nie testowano?
Różnorodności z prawdziwego świata — cztery próbki to tylko cztery próbki. Zagnieżdżonych list, list definicyjnych, przypisów i matematyki. Błędnego HTML-a, bo właśnie tam konwertery historycznie najbardziej się różnią. Przetwarzania Markdown z powrotem do HTML. docling, który ma te same próbki na dysku, ale w opublikowanym przebiegu nie raportuje tych pól, więc został pominięty, a nie oszacowany. I konfiguracji: html2text uruchomiono z body_width=0, ponieważ domyślne 78 zawija każdą linię, co zmieniłoby każdy znak i każdą liczbę tokenów w tej tabeli.


