PythonでHTMLをMarkdownに変換する:包括的なガイド

HTMLをクリーンでLLM対応のMarkdownに変換するためのPython

目次

HTMLをMarkdownに変換は、LLM(大規模言語モデル)やドキュメンテーションシステム、Hugoなどの静的サイトジェネレーター向けのウェブコンテンツ準備において、現代の開発ワークフローにおいて基本的なタスクです。このガイドは、2026年のドキュメンテーションツール: Markdown、LaTeX、PDFおよび印刷ワークフロー ハブの一部です。

HTMLは、豊富なスタイルと構造を持つウェブブラウザ向けに設計されており、Markdownは、テキスト処理、バージョン管理、AI消費に最適な読みやすいフォーマットを提供します。Markdownの構文に初めて触れる場合は、Markdownチートシートを確認して、包括的な参考資料を入手してください。

infographic: HTMLからMarkdownへのページ変換

この包括的なレビューでは、HTMLからMarkdownへの変換に使用できる6つのPythonパッケージを紹介し、実用的なコード例、パフォーマンスベンチマーク、実際の使用例を提供します。LLMトレーニングパイプラインの構築、ブログからHugoへの移行、ドキュメンテーションのスクレイピングなど、どのワークフローにも最適なツールが見つかります。

代替アプローチ: 複雑なレイアウトに対してAIによる変換を必要とする場合は、LLMとOllamaを使用してHTMLをMarkdownに変換を検討してください。これは、意味的理解を伴うよりスマートなコンテンツ抽出を提供します。

学ぶ内容:

  • 6つのライブラリの詳細な比較(それぞれの長所と短所を含む)
  • 実際のHTMLサンプルを使用したパフォーマンスベンチマーク
  • 一般的な使用ケース向けの生産性の高いコード例
  • LLM前処理ワークフローのベストプラクティス
  • ご要望に応じた具体的な推奨事項

なぜLLM前処理にはMarkdownなのか?

ツールに深く潜る前に、なぜMarkdownがLLMワークフローにおいて特に価値があるのか理解しましょう:

  1. トークン効率: 同じ内容でHTMLよりもMarkdownははるかに少ないトークンを使用します
  2. 意味の明確さ: Markdownは冗長なタグを使わずにドキュメント構造を保持します
  3. 読みやすさ: 人間とLLMの両方がMarkdownの構文を簡単に解析できます
  4. 一貫性: 標準化されたフォーマットにより、モデル入力の曖昧さが減少します
  5. ストレージ: トレーニングデータやコンテキストウィンドウのファイルサイズが小さくなります

Markdownの汎用性はHTML変換を超えて広がっています—you can also WordドキュメントをMarkdownに変換 ドキュメンテーションワークフローで、またはObsidianを個人知識管理に使用などの知識管理システムで使用できます。Markdown、LaTeX、PDFのドキュメント変換とフォーマットについてさらに詳しく知りたい場合は、ドキュメンテーションツールハブを参照してください。

TL;DR - 一覧表の簡単な比較

急いでいる場合は、6つのライブラリの包括的な比較を一目で確認してください。この表は、ご要望に合ったツールをすぐに特定するのに役立ちます:

フィーチャー html2text markdownify html-to-markdown trafilatura domscribe html2md
HTML5サポート 部分的 部分的 完全 完全 完全 完全
型ヒント なし なし あり 部分的 なし 部分的
カスタムハンドラー 限定的 すぐれもの 良好 限定的 良好 限定的
テーブルサポート 基本 基本 高度 良好 良好 良好
非同期サポート なし なし なし なし なし あり
コンテンツ抽出 なし なし なし すぐれもの なし 良好
メタデータ抽出 なし なし あり すぐれもの なし あり
CLIツール なし なし あり あり なし あり
速度 非常に快 非常に快
アクティブな開発 なし あり あり あり 限定的 あり
Pythonバージョン 3.6+ 3.7+ 3.9+ 3.6+ 3.8+ 3.10+
依存関係 なし BS4 lxml lxml BS4 aiohttp

簡単な選択ガイド:

  • 速さが必要? → trafilatura or html2md
  • カスタマイズが必要? → markdownify
  • 型安全性が必要? → html-to-markdown
  • シンプルさが必要? → html2text
  • コンテンツ抽出が必要? → trafilatura

主な候補: 6つのPythonパッケージの比較

それぞれのライブラリを実用的なコード例、設定オプション、実際のインサイトとともに深く掘り下げましょう。各セクションには、インストール手順、使用パターン、強みと限界の誠実な評価が含まれます。

1. html2text - 伝統的な選択肢

Aaron Swartzによって最初に開発されたhtml2textは、10年以上にわたりPythonエコシステムで定番のツールです。クリーンで読みやすいMarkdown出力を生成することに焦点を当てています。

インストール:

pip install html2text

基本的な使用方法:

import html2text

# コンバーターインスタンスの作成
h = html2text.HTML2Text()

# 設定オプション
h.ignore_links = False
h.ignore_images = False
h.ignore_emphasis = False
h.body_width = 0  # 行を折り返さない

html_content = """
<h1>ウェブスクレイピングへようこそ</h1>
<p>これは <strong>包括的なガイド</strong> です。</p>
<ul>
    <li>簡単な使用</li>
    <li>戦闘済み</li>
    <li>広く採用されている</li>
</ul>
<a href="https://example.com">もっと詳しく見る</a>
"""

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

出力:

# ウェブスクレイピングへようこそ

これは **包括的なガイド** です。

  * 簡単な使用
  * 戦闘済み
  * 広く採用されている

[もっと詳しく見る](https://example.com)

高度な設定:

import html2text

h = html2text.HTML2Text()

# 特定の要素をスキップ
h.ignore_links = True
h.ignore_images = True

# フォーマットの制御
h.body_width = 80  # 80文字で折り返す
h.unicode_snob = True  # Unicode文字を使用
h.emphasis_mark = '*'  # 強調に*を使用
h.strong_mark = '**'

# テーブルの処理
h.ignore_tables = False

# プレフォーマットテキストの保護
h.protect_links = True

長所:

  • 15年以上の開発経験で熟成され、安定しています
  • 拡張可能な設定オプション
  • エッジケースをうまく処理
  • 外部依存なし

短所:

  • 限定的なHTML5サポート
  • 一貫した間隔が取れない場合がある
  • 活発なメンテナンスされていない(2020年以降の主要なアップデートなし)
  • 単一スレッドでのみ処理可能

最適な用途: 簡単なHTMLドキュメント、レガシーシステム、安定性が最優先される場合


2. markdownify - 高度な柔軟性を備えたオプション

markdownifyは、BeautifulSoup4を使用して、カスタマイズ可能なタグ処理を提供する柔軟なHTMLパーサーです。

インストール:

pip install markdownify

基本的な使用方法:

from markdownify import markdownify as md

html = """
<article>
    <h2>現代ウェブ開発</h2>
    <p>Pythonと<code>現代のフレームワーク</code>で構築。</p>
    <blockquote>
        <p>シンプルさが究極の洗練です。</p>
    </blockquote>
</article>
"""

markdown = md(html)
print(markdown)

出力:


## 現代ウェブ開発

Pythonと`現代のフレームワーク`で構築。

> シンプルさが究極の洗練です。

カスタムハンドラの高度な使用:

from markdownify import MarkdownConverter

class CustomConverter(MarkdownConverter):
    """
    特定のタグ処理を備えたカスタムコンバーターの作成
    """
    def convert_img(self, el, text, convert_as_inline):
        """画像ハンドラで代替テキストを含む"""
        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):
        """言語検出付きのコードブロック処理の強化"""
        code = el.find('code')
        if code:
            # class属性から言語を抽出(例: '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'

# カスタムコンバーターを使用
html = '<pre><code class="language-python">def hello():\n    print("world")</code></pre>'
markdown = CustomConverter().convert(html)
print(markdown)

Markdownコードブロックおよびシンタックスハイライトの詳細については、Markdownコードブロックの使用ガイドをご覧ください。

選択的なタグ変換:

from markdownify import markdownify as md

# 特定のタグを完全に削除
markdown = md(html, strip=['script', 'style', 'nav'])

# 特定のタグのみ変換
markdown = md(
    html,
    heading_style="ATX",  # ヘッディングに#を使用
    bullets="-",  # ボールドに-を使用
    strong_em_symbol="*",  # 強調に*を使用
)

長所:

  • BeautifulSoup4に基づいており、HTMLパーサーが強固
  • サブクラス化を通じて非常にカスタマイズ可能
  • 活発なメンテナンス
  • 良好なドキュメント

短所:

  • BeautifulSoup4依存が必要
  • 大規模なドキュメントでは遅くなる可能性
  • テーブルサポートが限定的

最適な用途: カスタム変換ロジック、BeautifulSoup4を使用しているプロジェクト


3. html-to-markdown - 現代的なパワフルなライブラリ

html-to-markdownは、完全な型指定、現代的なライブラリで、包括的なHTML5サポートと拡張可能な設定オプションを備えています。

インストール:

pip install html-to-markdown

基本的な使用方法:

from html_to_markdown import convert

html = """
<article>
    <h1>技術ドキュメンテーション</h1>
    <table>
        <thead>
            <tr>
                <th>機能</th>
                <th>サポート</th>
            </tr>
        </thead>
        <tbody>
            <tr>
                <td>HTML5</td>
                <td>✓</td>
            </tr>
            <tr>
                <td>テーブル</td>
                <td>✓</td>
            </tr>
        </tbody>
    </table>
</article>
"""

markdown = convert(html)
print(markdown)

高度な設定:

from html_to_markdown import convert, Options

# カスタムオプションの作成
options = Options(
    heading_style="ATX",
    bullet_style="-",
    code_language_default="python",
    strip_tags=["script", "style"],
    escape_special_chars=True,
    table_style="pipe",  # テーブルに|を使用
    preserve_whitespace=False,
    extract_metadata=True,  # メタタグを抽出
)

markdown = convert(html, options=options)

コマンドラインインターフェース:

# 単一ファイルの変換
html-to-markdown input.html -o output.md

# オプション付きの変換
html-to-markdown input.html \
    --heading-style atx \
    --strip-tags script,style \
    --extract-metadata

# バッチ変換
find ./html_files -name "*.html" -exec html-to-markdown {} -o ./markdown_files/{}.md \;

長所:

  • 完全なHTML5サポート(セマンティック要素も含む)
  • 標準的な型ヒント付きで、現代的なコードベース
  • テーブル処理の強化(セルのマージ、配置)
  • メタデータ抽出機能
  • 活発な開発と現代的なコードベース

短所:

  • Python 3.9+が必要
  • 依存関係の足跡が大きめ
  • 学習曲線が急

最適な用途: 複雑なHTML5ドキュメント、型安全なプロジェクト、生産システム


4. trafilatura - コンテンツ抽出の専門家

trafilaturaはHTMLからMarkdownへの変換ツール以上のものです。ウェブスクレイピングと記事抽出のために特別に設計されたスマートなコンテンツ抽出ライブラリです。

インストール:

pip install trafilatura

基本的な使用方法:

import trafilatura

# URLからダウンロードして抽出
url = "https://example.com/article"
downloaded = trafilatura.fetch_url(url)
markdown = trafilatura.extract(downloaded, output_format='markdown')
print(markdown)

注: Trafilaturaには組み込みのURLフェッチ機能がありますが、APIや認証されたエンドポイントで作業する際には、cURLチートシートが役立ちます。

高度なコンテンツ抽出:

import trafilatura
from trafilatura.settings import use_config

# カスタム設定の作成
config = use_config()
config.set("DEFAULT", "EXTRACTION_TIMEOUT", "30")

html = """
<html>
<head><title>記事タイトル</title></head>
<body>
    <nav>ナビゲーションメニュー</nav>
    <article>
        <h1>主な記事</h1>
        <p>重要なコンテンツがここにあります。</p>
    </article>
    <aside>広告</aside>
    <footer>フッター内容</footer>
</body>
</html>
"""

# 本コンテンツのみ抽出
markdown = trafilatura.extract(
    html,
    output_format='markdown',
    include_comments=False,
    include_tables=True,
    include_images=True,
    include_links=True,
    config=config
)

# メタデータ付き抽出
result = trafilatura.extract(
    html,
    output_format='markdown',
    with_metadata=True
)

if result:
    print(f"タイトル: {result.get('title', 'N/A')}")
    print(f"著者: {result.get('author', 'N/A')}")
    print(f"日付: {result.get('date', 'N/A')}")
    print(f"\n内容:\n{result.get('text', '')}")

バッチ処理:

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

def process_url(url):
    """URLからMarkdownを抽出"""
    downloaded = trafilatura.fetch_url(url)
    if downloaded:
        return trafilatura.extract(
            downloaded,
            output_format='markdown',
            include_links=True,
            include_images=True
        )
    return None

# 複数のURLを並列処理
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')

長所:

  • 智能的なコンテンツ抽出(不要な要素を除去)
  • 組み込みのURLフェッチ機能と堅牢なエラーハンドリング
  • メタデータ抽出(タイトル、著者、日付)
  • 言語検出
  • ニュース記事やブログ投稿に最適化
  • Cベースのパーサーで高速

短所:

  • 一般的なHTMLから過剰にコンテンツを削除する可能性
  • 記事抽出に特化(汎用的ではない)
  • エッジケースの設定複雑さ

最適な用途: ウェブスクレイピング、記事抽出、LLMトレーニングデータの準備


5. domscribe - セマンティックの保存者

domscribeは、HTMLのセマンティックな意味を保ちながらMarkdownに変換することに焦点を当てています。

インストール:

pip install domscribe

基本的な使用方法:

from domscribe import html_to_markdown

html = """
<article>
    <header>
        <h1>セマンティックHTMLの理解</h1>
        <time datetime="2024-10-24">2024年10月24日</time>
    </header>
    <section>
        <h2>導入</h2>
        <p>セマンティックHTMLは<mark>意味</mark>をコンテンツに提供します。</p>
    </section>
    <aside>
        <h3>関連トピック</h3>
        <ul>
            <li>アクセシビリティ</li>
            <li>SEO</li>
        </ul>
    </aside>
</article>
"""

markdown = html_to_markdown(html)
print(markdown)

カスタムオプション:

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)

長所:

  • セマンティックHTML5構造を保持
  • 現代のウェブコンポーネントをうまく処理
  • クリーンなAPI設計

短所:

  • 開発初期段階(APIが変更される可能性あり)
  • 成熟した代替品と比較してドキュメントが限定的
  • コミュニティが小さく、例が少ない

最適な用途: セマンティックHTML5ドキュメント、アクセシビリティに焦点を当てたプロジェクト、セマンティックHTML5構造の保存が重要な場合

注意: domscribeは他のツールよりも戦闘経験が少なく、セマンティックHTMLの保存に特化したニッチな用途を満たしています。


6. html2md - 非同期のパワフルなライブラリ

html2mdは、非同期処理で高パフォーマンスのバッチ変換を設計しています。

インストール:

pip install html2md

コマンドラインでの使用:

# 全ディレクトリの変換
m1f-html2md convert ./website -o ./docs

# カスタム設定付き
m1f-html2md convert ./website -o ./docs \
    --remove-tags nav,footer \
    --heading-offset 1 \
    --detect-language

# 単一ファイルの変換
m1f-html2md convert index.html -o readme.md

プログラム的な使用:

import asyncio
from html2md import convert_html

async def convert_files():
    """非同期バッチ変換"""
    html_files = [
        'page1.html',
        'page2.html',
        'page3.html'
    ]

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

# 変換を実行
results = asyncio.run(convert_files())

長所:

  • 非同期処理による高パフォーマンス
  • 智能的なコンテンツセレクターの検出
  • YAMLフロントマター生成(Hugo向けに最適!)
  • コード言語の検出
  • 並列処理サポート

短所:

  • Python 3.10+が必要
  • CLIに焦点を当てている(柔軟なAPIが少ない)
  • ドキュメントがより包括的であるべき

最適な用途: 大規模な移行、バッチ変換、Hugo/Jekyllの移行


パフォーマンスベンチマーク

パフォーマンスは、LLMトレーニングや大規模な移行時に数千のドキュメントを処理する際に重要です。ライブラリ間の相対的な速度の違いを理解することで、ワークフローに適した選択ができます。

比較パフォーマンス分析:

一般的な使用パターンに基づき、これらのライブラリが3つの現実的なシナリオでどのように比較されているかを以下に示します:

  1. シンプルなHTML: テキスト、ヘッディング、リンクを持つ基本的なブログ投稿(5KB)
  2. 複雑なHTML: ネストされたテーブルとコードブロックを持つ技術ドキュメンテーション(50KB)
  3. 実際のウェブサイト: ナビゲーション、フッター、サイドバー、広告を含むフルページ(200KB)

以下は、これらのライブラリをテストするために使用できる例のベンチマークコードです:

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

def benchmark(html_content, iterations=100):
    """変換速度のベンチマーク"""

    # 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
    }

一般的なパフォーマンス特性(代表的な相対速度):

パッケージ シンプル(5KB) 複雑(50KB) 実際のサイト(200KB)
html2text 遅い 遅い
markdownify 遅い 遅い 最も遅い
html-to-markdown
trafilatura 非常に快 非常に快
html2md(非同期) 非常に快 非常に快 最も速い

主な観察点:

  • html2mdtrafilaturaは複雑なドキュメントで最も速く、バッチ処理に最適です
  • html-to-markdownは生産性の高い使用に最適な速度と機能のバランスを提供します
  • markdownifyは遅いが最も柔軟で、カスタムハンドラが必要な場合にトレードオフが価値があります
  • html2textはシンプルな使用ケースでは安定していますが、年齢のためパフォーマンスが遅い

注: パフォーマンスの違いは、数百または数千のファイルを処理する場合に顕著になります。偶発的な変換ではどのライブラリでも問題ありません。機能とカスタマイズオプションに注目してください。


実際の使用ケース

理論は役立ちますが、これらのツールがどのように生産環境で動作するかを示す実際の例が重要です。ここでは、ご自身のプロジェクトに適応できる4つの一般的なシナリオと、完全な生産性の高いコードを紹介します。

使用ケース1: LLMトレーニングデータの準備

要件: 千のドキュメンテーションページからクリーンなテキストを抽出

推奨: trafilatura + 並列処理

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

def process_html_file(html_path):
    """HTMLファイルをMarkdownに変換"""
    html = Path(html_path).read_text(encoding='utf-8')
    markdown = trafilatura.extract(
        html,
        output_format='markdown',
        include_links=False,  # よりクリーンなトレーニングデータのためにリンクを削除
        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

# 10,000ファイルを並列処理
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"処理済みファイル数: {len(html_files)}")
print(f"合計文字数: {sum(token_counts):,}")

使用ケース2: Hugoブログの移行

要件: WordPressブログをHugoに移行し、フロントマターを含める

推奨: html2md CLI

Hugoは、Markdownを使用してコンテンツを管理する人気のある静的サイトジェネレーターです。Hugoに関するより詳しいヒントについては、Hugoチートシートを確認し、Hugoサイトに構造化データマークアップを追加を学び、SEO改善に役立ててください。ドキュメンテーションツールハブには、Markdownワークフローとドキュメンテーション変換に関するさらなるガイドが含まれています。

# フロントマター付きですべての投稿を変換
m1f-html2md convert ./wordpress-export \
    -o ./hugo/content/posts \
    --generate-frontmatter \
    --heading-offset 0 \
    --remove-tags script,style,nav,footer

またはプログラム的に:

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

def migrate_post(html_file):
    """WordPress HTMLをHugo Markdownに変換"""
    html = Path(html_file).read_text()

    # HTMLからタイトルと日付を抽出
    from bs4 import BeautifulSoup
    soup = BeautifulSoup(html, 'html.parser')
    title = soup.find('h1').get_text() if soup.find('h1') else 'Untitled'

    # Markdownに変換
    options = Options(strip_tags=['script', 'style', 'nav', 'footer'])
    markdown = convert(html, options=options)

    # Hugoフロントマターを追加
    frontmatter = {
        'title': title,
        'date': '2024-10-24',
        'draft': False,
        'tags': []
    }

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

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

# すべての投稿を処理
for html_file in Path('./wordpress-export').glob('*.html'):
    migrate_post(html_file)

使用ケース3: カスタムフォーマットを持つドキュメンテーションスクレイパー

要件: 技術ドキュメンテーションをスクレイピングし、カスタムコードブロック処理を実行

推奨: markdownify とカスタムコンバーター

このアプローチは、wikiシステムからドキュメンテーションを移行する際に特に有用です。ドキュメンテーションを管理している場合は、DokuWiki - セルフホスト型のwikiと代替案に興味があるかもしれません。

from markdownify import MarkdownConverter
import requests

class DocsConverter(MarkdownConverter):
    """技術ドキュメンテーション用のカスタムコンバーター"""

    def convert_pre(self, el, text, convert_as_inline):
        """シンタックスハイライト付きのコードブロックの強化"""
        code = el.find('code')
        if code:
            # classから言語を抽出
            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):
        """特殊なドキュメンテーションブロックの処理"""
        classes = el.get('class', [])

        # 警告ブロック
        if 'warning' in classes:
            return f'\n> ⚠️ **警告**: {text}\n'

        # 情報ブロック
        if 'info' in classes or 'note' in classes:
            return f'\n> 💡 **注意**: {text}\n'

        return text

def scrape_docs(url):
    """ドキュメンテーションページをスクレイピングして変換"""
    response = requests.get(url)
    markdown = DocsConverter().convert(response.text)
    return markdown

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

使用ケース4: ニュースレターをMarkdownアーカイブに変換

要件: HTMLメールニュースレターを読みやすいMarkdownに変換

推奨: html2text と特定の設定

import html2text
import email
from pathlib import Path

def convert_newsletter(email_file):
    """HTMLメールをMarkdownに変換"""
    # メールを解析
    with open(email_file, 'r') as f:
        msg = email.message_from_file(f)

    # 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

    # コンバーターを設定
    h = html2text.HTML2Text()
    h.ignore_images = False
    h.images_to_alt = True
    h.body_width = 0
    h.protect_links = True
    h.unicode_snob = True

    # 変換
    markdown = h.handle(html_content)

    # メタデータを追加
    subject = msg.get('Subject', 'No Subject')
    date = msg.get('Date', '')

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

    return output

# ニュースレターのアーカイブを処理
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')

シナリオごとの推奨

まだどのライブラリを選択すべきか悩んでいる場合、特定の使用ケースに基づいたガイドがあります。

ネットスクレイピングおよびLLM前処理向け

優勝者: trafilatura

Trafilaturaは、不要な要素を除去しながらクリーンなコンテンツを抽出するのに優れています。以下のような用途に最適です:

  • LLMトレーニングデータセットの構築
  • コンテンツの集約
  • 研究論文の収集
  • ニュース記事の抽出

Hugo/Jekyll移行向け

優勝者: html2md

非同期処理とフロントマター生成により、大規模な移行が迅速かつ容易になります:

  • バッチ変換
  • 自動メタデータ抽出
  • YAMLフロントマター生成
  • ヘッディングレベルの調整

カスタム変換ロジック向け

優勝者: markdownify

コンバーターをサブクラス化して完全なコントロールを得られます:

  • カスタムタグハンドラ
  • ドメイン固有の変換
  • 特殊なフォーマット要件
  • 既存のBeautifulSoupコードとの統合

型安全な生産システム向け

優勝者: html-to-markdown

現代的、型安全、機能が完全なライブラリです:

  • 完全なHTML5サポート
  • 継続的な型ヒント
  • 高度なテーブル処理
  • 活発なメンテナンス

簡単で安定した変換向け

優勝者: html2text

「ただ機能する」ことを必要とする場合に最適です:

  • 外部依存なし
  • 戦闘済み
  • 拡張可能な設定
  • 幅広いプラットフォームサポート

LLM前処理のベストプラクティス

どのライブラリを選択しても、これらのベストプラクティスに従うことで、LLMの消費に最適化された高品質なMarkdown出力が得られます。これらのパターンは、数百万のドキュメントを処理する生産性ワークフローにおいて、実証済みのものです。

1. 変換前のクリーンアップ

変換前に不要な要素を削除することで、出力をよりクリーンにし、パフォーマンスを向上させます。

from bs4 import BeautifulSoup
import trafilatura

def clean_and_convert(html):
    """変換前の不要な要素の削除"""
    soup = BeautifulSoup(html, 'html.parser')

    # 不要な要素の削除
    for element in soup(['script', 'style', 'nav', 'footer', 'header', 'aside']):
        element.decompose()

    # 広告とトラッキングの削除
    for element in soup.find_all(class_=['ad', 'advertisement', 'tracking']):
        element.decompose()

    # クリーンアップされたHTMLを変換
    markdown = trafilatura.extract(
        str(soup),
        output_format='markdown'
    )

    return markdown

2. ウェイトスペースの正規化

異なるコンバーターは、空白の処理方法が異なります。出力を正規化することで、コロパス全体での一貫性を確保できます。

import re

def normalize_markdown(markdown):
    """Markdownの空白の整理"""
    # 複数の空行の削除
    markdown = re.sub(r'\n{3,}', '\n\n', markdown)

    # 末尾の空白の削除
    markdown = '\n'.join(line.rstrip() for line in markdown.split('\n'))

    # 終端に1行の改行を保証
    markdown = markdown.rstrip() + '\n'

    return markdown

3. 出力の検証

品質管理は不可欠です。変換エラーを早期に検出するために検証を実装してください。

def validate_markdown(markdown):
    """Markdownの品質の検証"""
    issues = []

    # HTMLの残りの確認
    if '<' in markdown and '>' in markdown:
        issues.append("HTMLタグが検出されました")

    # 破損リンクの確認
    if '[' in markdown and ']()' in markdown:
        issues.append("空のリンクが検出されました")

    # 過剰なコードブロックの確認
    code_block_count = markdown.count('```')
    if code_block_count % 2 != 0:
        issues.append("閉じられていないコードブロックが検出されました")

    return len(issues) == 0, issues

4. バッチ処理テンプレート

大規模なドキュメントコレクションを処理する際には、適切なエラーハンドリング、ロギング、並列処理を備えたこの生産性に適したテンプレートを使用してください。

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):
    """単一の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:
            # 正規化
            markdown = normalize_markdown(markdown)

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

            # 保存
            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"{html_path}の処理中にエラーが発生しました: {e}")
        return False

def batch_convert(input_dir, max_workers=4):
    """ディレクトリ内のすべてのHTMLファイルの変換"""
    html_files = list(Path(input_dir).rglob('*.html'))
    logger.info(f"{len(html_files)}個のHTMLファイルが見つかりました")

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

    success_count = sum(results)
    logger.info(f"{success_count}/{len(html_files)}ファイルが成功して変換されました")

# 使用例
batch_convert('./html_docs', max_workers=8)

結論

Pythonエコシステムには、HTMLからMarkdownへの変換に最適化された、成熟した生産性に適したツールが豊富に存在します。ご自分の特定の要件に合わせて選択してください:

  • 迅速な変換: html2textを使用してください。シンプルでゼロ依存です。
  • カスタムロジック: markdownifyを使用してください。サブクラス化を通じて最大限の柔軟性が得られます。
  • ウェブスクレイピング: trafilaturaを使用してください。不要な要素を除去しながら、スマートにコンテンツを抽出します。
  • 大規模な移行: html2mdを使用してください。大規模プロジェクトで非同期パフォーマンスが得られます。
  • 生産性システム: html-to-markdownを使用してください。型安全性と包括的なHTML5サポートが可能です。
  • 意味の保持: domscribeを使用してください。HTML5の意味構造を保持できます。

LLMワークフロー向けの推奨事項

LLM前処理ワークフローでは、二段階のアプローチが推奨されます:

  1. trafilaturaから開始して、初期のコンテンツ抽出を行ってください。ナビゲーション、広告、不要な要素をスマートに除去しながら、主なコンテンツを保持します。
  2. html-to-markdownにフォールバックして、テーブルやコードブロックを含む技術ドキュメントなどの正確な構造の保持が必要な複雑なドキュメントを処理してください。

この組み合わせは、実際のシナリオの95%を効果的に処理します。

次のステップ

Markdown、LaTeX、PDF処理、ドキュメント印刷ワークフローに関するガイドについては、2026年のドキュメンテーションツール: Markdown、LaTeX、PDF & プリンティングワークフローをご覧ください。

これらのツール(html2textを除く)はすべて、積極的にメンテナンスされており、生産性に適しています。以下の手順が推奨されます:

  1. 使用ケースに合ったライブラリを2〜3つインストールしてください。
  2. 実際のHTMLサンプルでそれらをテストしてください。
  3. 通常のドキュメントサイズでパフォーマンスをベンチマークしてください。
  4. 出力品質に基づいて選択してください。速度だけではなく。

HTMLからMarkdownへの変換のためのPythonエコシステムは、大幅に成熟しており、それぞれの目的に応じて選択したツールは間違いありません。

その他のリソース

注意: この比較は、公式ドキュメンテーション、コミュニティのフィードバック、ライブラリのアーキテクチャの分析に基づいています。パフォーマンス特性は、典型的な使用パターンを代表しています。特定の使用ケースでは、実際のHTMLサンプルを使用して独自のベンチマークを実行することをお勧めします。

その他の役に立つ記事