turndown は、メタデータ取得時点で確認した4つのライブラリの中でいちばん GitHub スター数が多く、11,386 スターを獲得していました。ただし、4つの共通 HTML フィクスチャに対しては、標準設定では Markdown テーブルを1つも出力せず、同じ入力に対して markdownify より 24.6% 多くのトークン を使っていました。
4つとも、コンテンツ検出用のプローブ文字列はすべて保持できています。差が出るのは構造の扱いだけで、その構造が後工程でどれだけコストになるか、という点です。
何を、どのフィクスチャで測ったのか
この調査ベースにはすでに markitdown 用のパックがあり、5つの HTML フィクスチャと、あらかじめ登録されたプローブ文字列が含まれていました。つまり、完全一致で残っているかを確認する文字列と、ページの装飾や余計な要素を見つけるための定型文字列です。集計比較では、4つのコンバーターすべてに共通する4つのフィクスチャ を使っています。対象は、書店カタログ、引用サイト、ホッケー統計の表、そして Web スクレイピングに関する Wikipedia 記事です。5つ目のフィクスチャである Nothing but tables は、テーブル比重が高い診断用としてのみ使い、24.6% の集計からは外しています。
対象の4つは、turndown 7.2.4(Node)、markdownify 1.2.3、html2text 2025.4.15、そして公開済みの行をそのまま使う markitdown です。ページは、書店カタログ、引用サイト、ホッケー統計テーブル、Web スクレイピングの Wikipedia 記事です。
以下の各指標名は、markitdown 自身の成果物フィールド名と1対1で対応しています。そのため、同じ言葉の定義をすり合わせなくても、各行を並べて比較できます。
比較表

| コンバーター | 本文プローブ | 出力文字数 | トークン数 (o200k) | 1トークンあたりのバイト数 | Markdown テーブル行数 | リンク数 |
|---|---|---|---|---|---|---|
| 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 |
4つのフィクスチャのみが対象です。markitdown も同じ4つで実行しています。各フィクスチャごとの詳細は fiveway-scores.json にあります。トークン数は o200k_base で数え、markitdown のテーブル行数は保存済み Markdown から同じカウンターで再集計しています。
コンテンツ保持は引き分けです。 4つのフィクスチャ全体で、16個の本文プローブはすべてのコンバーターで保持されました。つまり、「テキストがちゃんと通るか」だけが論点なら、4つとも答えはイエスです。
構造保持は引き分けではありません。 共通の4フィクスチャでは、markdownify と markitdown がどちらも Markdown テーブル行を36行出力し、html2text は32行、turndown は0行です。別のテーブル専用診断では、markdownify が62行、html2text が59行を出力しましたが、これらは上の集計には含めていません。
turndown のトークンコストは24.6%高い のですが、その原因はテーブルではありません。最初はそう思っていましたが、フィクスチャ別の数値を見ると違いました。詳しくは下で説明します。
turndown がテーブルをどう扱うか
以下はホッケー統計のフィクスチャです。同じ行を3つの方法で出力したものを示します。
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 | ...
turndown の変換でも値そのものはすべて残るので、本文プローブは 16/16 になります。残らないのは、各値がどの列に属するか という構造です。turndown の出力を読むと、44 はただの行中の数字にしか見えません。Boston の勝利数だと復元するには、位置を数えて、しかも途中に空セルがないことを期待する必要があります。このフィクスチャでは空セルが実際に存在するため、その方法も通用しません。
モデルが出力を読む場合、これは「質問に答えられるテーブル」と「推測で読むしかない数列」の違いです。
これは欠陥というより、turndown のコアがテーブルを扱わないという既知の境界です。テーブルを追加するために turndown-plugin-gfm が用意されています。ただし、標準インストールには含まれていません。11,386 スターということは、かなりの人がデフォルトのまま使っていると考えられます。
トークン差の本当の原因
私は最初、24.6% のトークン差は、平坦化されたテーブルが文字数として膨らむせいだと思っていました。ところがフィクスチャ別に見ると、そうではありません。
| フィクスチャ | turndown のトークン数 ÷ markdownify のトークン数 |
|---|---|
| 引用サイト(テーブルなし) | 0.99× |
| 書店カタログ | 1.06× |
| ホッケー統計(大きなテーブル1つ) | 1.37× |
| Wikipedia(ほぼ本文、テーブル行9行) | 1.29× |
| Nothing but tables | 0.78× |
テーブルだけの フィクスチャでは、turndown は 22% 安く なっています。というのも、パイプ記号の足場もトークンを消費しますが、turndown はそれを一切出力しないからです。テーブルを平坦化すること自体は、必ずしもトークン増にはなりません。
Wikipedia のフィクスチャは全体の74%を占め、テーブル行は9行しかありません。15,378 文字の差がテーブル由来であるはずがありません。原因はこれです。
(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 は <script> と <style> の内容を削除しません。markdownify と html2text はどちらも削除します。 それぞれの要素内にだけ現れるマーカーで数えると、turndown の出力には4つのフィクスチャ全体で script マーカーが10個、style マーカーが84個含まれていました。ほかの2つはどちらも0です。Wikipedia ページでは、MediaWiki のインライン JavaScript 設定と CSS の 8行 が 14,644文字 を占め、差分全体の 95% に達しています(script-style-stripping.json)。
これこそ、実際に注目すべき発見です。平坦化されたテーブルは、目に見える構造上の問題です。一方、Markdown に JavaScript の設定塊が混ざるのは、情報としては何の価値もない純コストであり、実ページではこの比較の他要素を圧倒します。
html2text のテーブルは一見わかりにくい
html2text は markdownify と markitdown の36行に対して32行でしたが、私の最初のカウンターでは 1行 と判定されていました。
それはライブラリの問題ではなく、私の数え方の問題でした。html2text は Team Name | Year | Wins のように 先頭と末尾のパイプを付けずに 出力します。これは一般的な Markdown テーブル形式ですが、^\|.*\|$ を要求する正規表現では見えません。私はその正規表現を書き、そのまま実行して、「html2text はテーブルを出さない」と報告しかけていました。
実際は出しています。修正版のカウンターでは、連続するパイプ入りの行と、その中にある区切り行をまとめて検出するヒューリスティックを使っています。このルールでは、html2text は1行から32行になります。これは完全な Markdown パーサーではないので、行数は「明示したカウンターで測った結果」として読むべきで、普遍的なレンダリング結果ではありません。
Markdown を自前の正規表現で後処理する場合には重要です。4つのライブラリのうち2つは外側のパイプを出し、1つは出しません。
誰も話題にしないライセンス
| コンバーター | ライセンス | インストール内容 | コールドインポート | スター数 | 最終リリース |
|---|---|---|---|---|---|
| turndown | MIT | npm パッケージ3つ、8.8 MiB | 0.056 秒 | 11,386 | 2026-04-03 |
| markdownify | MIT | 5パッケージ、1.8 MiB | 0.046 秒 | 2,235 | 2026-06-30 |
| html2text | GPL-3.0-or-later | 1パッケージ、0.2 MiB | 0.077 秒 | 2,168 | 2025-04-15 |
| markitdown | パッケージのメタデータ参照 | このインストールでは未計測 | 未計測 | — | — |
install-and-import.json。各ライブラリはそれぞれ空の環境に個別インストールしています。ライセンスは、レジストリのメタデータ、GitHub リポジトリ、そしてインストール済みパッケージ自身の METADATA ファイルの3箇所で確認しました。そこには License-Expression: GPL-3.0-or-later とあります。
このインストール比較でいちばん軽いライブラリ、1パッケージ・0.2 MiB のものは GPL-3.0-or-later です。これがプロジェクトに影響するかどうかは、ソフトウェアをどう組み合わせ、どう配布するかによります。ライセンス管理を担う人の判断材料として扱ってください。この記事は法的助言ではありません。markitdown は、この成果物ではインストールやライセンスが記録されていないため、未計測として表示しています。
このトレードオフが見落とされやすいのは、ライセンスだけがベンチマークに現れない属性だからです。
ただし、3つとも同カテゴリの文書抽出ライブラリよりはかなり軽量です。そちらは 21〜70 MiB あります。コンバーターは抽出器よりずっと小さい存在なので、依存コストを考えるなら分けて扱うべきです。
この表が正しくなる前に修正した2つの混乱要因
上の数値は3版目です。最初の2回は間違っていました。どちらも再現しやすいタイプのミスだったので、明示しておきます。
5つのフィクスチャを4つに対して比較していた。 markitdown はこの5ファイルのうち4つしか実行していませんでしたが、ほかの3つは5つすべてを実行していました。それぞれのツールを自分の対象セットで合計すると、markdownify は 98 行、markitdown は 36 行になり、能力差があるように見えてしまいます。しかし、同じ4つ で揃えると 36 対 36 の完全な引き分けです。5つ目のフィクスチャはテーブル比重が高いため、この混乱は最悪の方向に働き、新しいものを既存のものと比べてほぼ3倍に見せていました。

2つのカウンターを1列で比べていた。 markitdown が公開している md_table_rows は、その内部コードから得た数値で、私はまだ読んでいませんでした。そこに自分の数値をそのまま比べると、変換器同士ではなく、カウンター同士を比べてしまう可能性がありました。markitdown の Markdown 出力はディスクに保存されているので、修正方法は全4件に同じカウンターをかけることでした。その結果、markitdown の再集計値は公開値と各フィクスチャで完全一致しました(0, 0, 27, 9)。定義は一致していましたが、それは確認しない限りわからなかったのです。
どちらのミスも、出力を見ただけでは気づけません。どちらも、自信満々の誤った表を生み出していたはずです。
どれを使うべきか
モデルに入力したい、またはこの種のページから構造化コンテンツを保存したい? まずは markdownify を試してください。このカウンターでは markitdown と同じテーブル行数を出し、トークン数は最も少ないグループに入り、MIT ライセンスで、インストールサイズも 1.8 MiB です。実際のページ形状で検証してから標準化してください。
依存コストをキロバイト単位で見ていて、再配布はしない? html2text です。1パッケージ、0.2 MiB、テーブルも保持されます。まず GPL の扱いを確認し、最終リリースが 2025 年4月である点にも注意してください。
すでに Node スタックにいる? turndown に turndown-plugin-gfm を併用し、HTML を渡す前に <script> と <style> を削除してください。turndown はそれをやってくれません。これら2つの欠落が、トークンを4分の1余計に消費し、テーブル構造を消し去ります。しかも、出力を見ない限り気づけません。
他の文書形式もすでに変換している? markitdown は PDF や Office などにも対応しており、HTML 出力も専用コンバーターと比べて競争力があります。依存関係を1つにまとめられる価値はあります。
管理型 API の出番
ここまでの4つは、すでに手元にある HTML を変換するものです。ページの取得、JavaScript のレンダリング、ボット対策の処理はしていません。実際の対象では、後者のほうが難しいことがよくあります。
Thunderbit の開発者向けスタックは、その領域をカバーします。POST /distill は URL を受け取り、レンダリングと取得を処理したうえで、LLM 向けのきれいな Markdown を返します。POST /extract は、指定した JSON Schema に基づいて AI がスキーマ一致の構造化 JSON を返すもので、出力形式がまた別です。つまり、後でパースする必要のある Markdown テーブルではなく、行データをそのまま返します。どちらも MCP サーバーと CLI(npx @thunderbit/thunderbit-cli)から利用できます。料金は Thunderbit pricing page を参照してください。
率直に言うと、HTML を持っていて Markdown が欲しいだけなら、markdownify は無料で十分よく働きます。そしてこの表は、競合のどれも同じように使えるかを示しています。一方で、ページを取得したい、あるいは文章ではなく構造化された行データが欲しいなら、それは別の選択です。
関連分野全体については、web scraping API roundup でホスト型オプションを、open-source scraper pillar でセルフホスト型を扱っています。実践的な手順は Converting HTML to Markdown in Python に、そしてこの分野がどこへ向かっているかは what llms.txt is trying to standardise にまとまっています。
結論
この4フィクスチャのワークロードでは、markdownify がいちばん有力なデフォルトです。共通カウンターでは markitdown と同じテーブル行数を出し、トークン数は他の効率的なコンバーターと比べて 1.3% 差以内、MIT ライセンスで、インストールサイズは 1.8 MiB です。
人気と実測挙動の間にあるこの差が、今回の発見です。turndown は優れたライブラリですが、テーブル対応に必要なプラグインを入れずに使っている人がかなり多く、その代償はトークンが4分の1増えることと、テーブル構造が消えることとして表れます。この2つは、数えなければ見えません。
1つだけ持ち帰るなら、モデルに渡す前に、コンバーターがテーブルをどう変えるかを必ず確認してください。4つのうち3つは妥当な処理をします。いちばん人気のものだけは、追加指示がなければそうなりません。
Thunderbit で Web データ抽出を試す Get Started Free
FAQ
turndown は本当にテーブルをサポートしていないのですか?
コア機能ではサポートしていません。テーブル対応は別パッケージの turndown-plugin-gfm で追加されますが、普通の npm install turndown には含まれません。プラグインなしでは、各セルは独立した段落として残るだけです。値はすべて残りますが、行と列の関係は失われます。4つのフィクスチャでは Markdown テーブル行数は0で、同じ内容に対して markdownify より 24.6% 多くトークンを使っていました。
なぜ html2text は最初、テーブルなしに見えたのですか?
私のカウンターが先頭と末尾のパイプを要求していたのに、html2text はそれを出さないからです。Team Name | Year | Wins は有効な Markdown で、正しくレンダリングされます。ただ、| Team Name | Year | とは書き方が違うだけです。修正版のカウンターは、パーサーのように、パイプを含む行が連続し、その中に区切り行があるかを見ます。その結果、html2text は1行から32行になります。Markdown を自前の正規表現で後処理するなら、この違いに引っかかります。
html2text の GPL は本当に問題ですか?
ソフトウェアをどう組み合わせて、どう配布するかによります。GPL-3.0-or-later は、MIT にはない義務を生む場合があるため、配布型製品に採用する前に、ライセンス管理の責任者を必ず関与させてください。これは法務確認の論点であって、法的助言ではありません。ライセンスの種類は、レジストリのメタデータ、リポジトリ、インストール済みパッケージの METADATA で確認済みです。
このトークン数は他のページにも当てはまりますか?
24.6% の差は主に turndown が <script> と <style> の内容を残すことに由来するため、その量に応じて変動します。最新の CMS ページでは大きく、静的ページではほぼゼロです。テーブルは逆方向に働きます。テーブルだけのフィクスチャでは turndown のほうが 22% 安く なりました。パイプの足場を出さないからです。1トークンあたりのバイト数は4つすべてで 3.61〜3.65 に収まっており、密度はほぼ同じで、差は量にあります。予算に関わるなら、自分のコーパスで測ってください。
ここでテストしていないものは何ですか?
現実世界の多様性です。4フィクスチャはあくまで4フィクスチャです。ネストされたリスト、定義リスト、脚注、数式。変換器の違いが最も出やすい壊れた HTML。Markdown から HTML への往復変換。docling は同じフィクスチャがディスクにありますが、公開実行ではこれらのフィールドを報告していないため、除外しており、推定もしていません。さらに設定面では、html2text は body_width=0 で実行しています。デフォルトの 78 だと全行が強制改行され、この表の文字数とトークン数がすべて変わってしまうからです。


