結論

MarkItDown は、PDF・Word・PowerPoint・Excel・HTML などのファイルを Markdown に変換する、Microsoft 製の Python ツールです。pip install 'markitdown[all]' で入れ、markitdown 資料.pdf -o 資料.md の1行で変換できます。

この記事でわかること

  • 自作の docx・pptx・xlsx・pdf・html を変換した入力と出力の実物
  • CLI・Python API・MCP サーバーの使い方と、uv で前の版が入る問題
  • 表・見出し・画像がどこまで残るかの比較表と、別のツールを選ぶ判断表

2026年10月29日更新|MarkItDown 0.1.9・Python 3.13 で実行確認

MarkItDown は、いろいろな形式のファイルを読み、見出し・リスト・表・リンクをできるだけ残した Markdown のテキストにします。主な使い道は、LLM(大規模言語モデル)や RAG(検索して答える仕組み)に文書を渡す前の下ごしらえです。

flowchart TD
    A[PDF・Word・PowerPoint<br>Excel・HTML・CSV など] --> B[MarkItDown<br>形式ごとの変換器]
    B --> C[Markdown のテキスト]
    C --> D[LLM に貼る・要約<br>RAG の索引に入れる<br>MCP で AI から呼ぶ]

よく調べられることの答えを先にまとめます。

知りたいこと 答え 詳しい節
MarkItDown とは ファイルを Markdown に変換する Microsoft の Python ツール(MIT ライセンス) MarkItDownとは
markitdown のインストール Python 3.10〜3.14 で pip install 'markitdown[all]' インストール
markitdown の使い方(コマンド) markitdown 入力 -o 出力.md。標準入力も読める コマンドライン
Python から使う MarkItDown().convert(パス).markdown Python API
Word・Excel・PowerPoint はきれいに変換できるか 見出し・表は残る。結合セル・未計算の数式・箇条書きの階層は崩れる Word・PowerPoint・Excel
PDF はどうなるか 文字は取れるが見出しの # は付かない。スキャンした PDF は空になる PDFの変換結果
日本語の CSV が文字化けする -c cp932 を付ける コマンドライン
uv で入れると版が古くなる --prerelease=allow か、形式を指定して入れる インストール
Claude などから使いたい markitdown-mcp を MCP サーバーとして登録する MCPサーバー

確認環境:Linux(x86_64・2コア)の上で、作業用の venv に Python 3.13.18 と MarkItDown 0.1.9(markitdown[all])、markitdown-mcp 0.0.1a8 を入れて実行しました。変換したファイルは、python-docx 1.2.0・python-pptx 1.0.2・openpyxl 3.1.5・reportlab 5.1.0・Pillow で自作した架空の文書(docx・pptx・xlsx・pdf・画像だけの pdf・html・Shift_JIS の csv・ipynb・zip・jpg)です。比較に pandoc 3.1.3、数式の再計算と以前の形式(.doc・.xls)の作成に LibreOffice、画像のメタデータの読み取りに exiftool 12.76 を使いました。uv 0.11.32 では依存関係の解決だけを試しています。LLM での画像の説明・Azure Document Intelligence・音声の文字起こしは外部にデータを送るため実行せず、LLM は外部に送らない偽のクライアントで「何が渡されるか」だけを確かめ、ほかは GitHub の README・PyPI・ソースコードで確かめました(確認日 2026年10月29日)。

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「MarkItDownとは?使い方とPDF・Word・Excelの変換結果を実物で比較」

MarkItDownとは(PDF・WordをMarkdownにするPythonツール)

この節では、MarkItDown が何をするツールで、何に向いていて何に向かないのかが分かります。

MarkItDown は、Microsoft が GitHub で公開している、ファイルや Office 文書を Markdown に変換する Python のツールです。 README は目的を「LLM やテキスト分析のパイプラインで使うこと」とし、見出し・リスト・表・リンクなどの文書の構造をできるだけ残す、と説明しています。名前は Markdown と「mark it down(書き留める)」を掛けたもので、日本語では「マークイットダウン」と読まれています。

0.1.9最新版PyPI・2026年10月21日公開
368MB[all] を入れた venv手元で計測。キャッシュを除く
1.7秒import にかかった時間変換は1ファイル 35〜392ms
  • 向いている:AI に読ませる・検索の索引に入れる・差分を取るなど、文字と構造が大事な使い方。README も、人が読むための見た目どおりの変換には向かない場合がある、と書いています。
  • 向かない:レイアウトや書式を保ったまま人が編集し直す文書の変換、スキャンした紙の書類の文字起こし(外部の OCR や LLM を足す必要がある)。
  • ライセンス:MIT(PyPI の表記)。商用でも使えますが、プラグインや依存するライブラリには別のライセンスのものがあります(判断表の節)。

Markdown の記法そのものは、関連記事「Markdown記法一覧|マークダウンの書き方早見表と表示されない原因」で扱っています。

対応形式とインストールの種類([all]・[pdf]・[docx])

この節では、どの形式を変換できるかと、形式ごとに何を足して入れるか(optional dependencies)が分かります。

MarkItDown は、形式ごとの部品を「追加の依存(extras)」として分けています。 何も付けずに入れると、Word や PDF は変換できません。手元で pip install --dry-run を使い、それぞれの extras で増えるパッケージを確かめました。

形式 extras 中で使うライブラリ(手元で確認)
PDF [pdf] pdfminer.six・pdfplumber
Word(.docx) [docx] mammoth(docx を HTML にしてから Markdown へ)
PowerPoint(.pptx) [pptx] python-pptx
Excel(.xlsx) [xlsx] openpyxl・pandas
Excel(.xls) [xls] xlrd・pandas
Outlook のメール(.msg) [outlook] olefile
音声(wav・mp3)の文字起こし [audio-transcription] SpeechRecognition・pydub(Google の音声認識に送る)
YouTube の字幕 [youtube-transcription] youtube-transcript-api
Azure の解析サービス [az-doc-intel]・[az-content-understanding] Azure の SDK
HTML・CSV・JSON・XML・ipynb・EPUB・ZIP・画像 不要(本体だけで読める) beautifulsoup4・markdownify など
  • 本体だけ(pip install markitdown)でも19個のパッケージが入りました。 ファイルの種類を中身から推定する magika が、onnxruntime と numpy を連れてくるためです。
  • [all] を入れた venv は 368MB でした(pip のキャッシュ 136MB は別)。大きさを抑えたいときは、'markitdown[pdf,docx,pptx,xlsx]' のように使う形式だけを指定します。
  • 音声の文字起こしは、ソースコード(_transcribe_audio.py)で recognize_google を呼んでいます。音声ファイルを変換すると、音声が Google の音声認識サービスに送られます。 社外に出せない会議の録音には使わないようにします。

MarkItDownのインストール(pip・uv・Docker)

この節では、MarkItDown を入れる手順と、uv で入れたときに前の版が入ってしまう問題の直し方が分かります。

README の推奨は、Python 3.10〜3.14 の仮想環境(venv)に pip で入れる方法です。 手元では次の順で入れました。

1

Python の版を確かめる

python3 --version が 3.10〜3.14 であること。PyPI の Requires-Python は <3.15, >=3.10 です。

3.9 以前では入らない

2

venv を作る

python3 -m venv .venv のあと、Linux・Mac は source .venv/bin/activate、Windows の PowerShell は .venv\Scripts\Activate.ps1 で有効にする。

ほかのツールと依存がぶつからない

3

pip で入れる

pip install 'markitdown[all]'。角かっこが特別な意味を持つシェルがあるため、引用符で囲む。PowerShell では pip install "markitdown[all]"。

形式を絞るなら [pdf,docx] など

4

版を確かめる

markitdown --version で markitdown 0.1.9 と出れば最新版(2026年10月29日時点)。

-v でも同じ

uv で入れると 0.1.5 になる(エラーは出ない)

uv で markitdown[all] を指定すると、エラーも警告も出ずに 0.1.5 が選ばれました。 uv 0.11.32 で依存関係の解決だけを試した結果です。

$ echo 'markitdown[all]' | uv pip compile - --python-version 3.13 | grep ^markitdown
markitdown==0.1.5

$ echo 'markitdown[all]' | uv pip compile - --python-version 3.13 --prerelease=allow | grep -E '^(markitdown|azure-ai-content)'
azure-ai-contentunderstanding==1.2.0b3
markitdown==0.1.9

$ echo 'markitdown[pdf,docx,pptx,xlsx]' | uv pip compile - --python-version 3.13 | grep ^markitdown
markitdown==0.1.9

版を固定すると、理由がはっきり出ます。

$ echo 'markitdown[all]==0.1.9' | uv pip compile - --python-version 3.13
  × No solution found when resolving dependencies:
  ╰─▶ Because only azure-ai-contentunderstanding<1.2.0b1
      is available and markitdown[all]>=0.1.9 depends on
      azure-ai-contentunderstanding>=1.2.0b1, we can conclude that
      markitdown[all]>=0.1.9 cannot be used.
...
hint: `azure-ai-contentunderstanding` was requested with a pre-release marker (e.g., azure-ai-contentunderstanding>=1.2.0b1), but pre-releases weren't enabled (try: `--prerelease=allow`)

原因は、[all] に含まれる Azure Content Understanding の SDK がベータ版(プレリリース)しか無いことです。 pip は依存の中で指定されたプレリリースを受け入れて 0.1.9 を入れました。uv の公式ドキュメントによると、uv は既定(if-necessary)で安定版を優先し、条件を満たす安定版がすべて使えないときだけプレリリースを使います。そのため、ベータ版を必要としない前の版(0.1.5)が「条件を満たす安定版」として選ばれます。直し方は3つです。

  • uv pip install --prerelease=allow 'markitdown[all]' とする。
  • Azure を使わないなら 'markitdown[pdf,docx,pptx,xlsx]' のように形式を指定する(手元で 0.1.9 になった)。
  • 版を 'markitdown[all]==0.1.9' と固定し、解決できないときにエラーで気づけるようにする。

Python 3.9 を指定したときは、次のように「Python の版が合わない」と出ました。

  × No solution found when resolving dependencies:
  ╰─▶ Because the requested Python version (>=3.9) does not satisfy
      Python>=3.10,<3.15 and you require markitdown[all]==0.1.9, we can
      conclude that your requirements are unsatisfiable.

Docker・pipx・Homebrew

  • Docker:README には、リポジトリで docker build -t markitdown:latest . を実行し、docker run --rm -i markitdown:latest < ~/your-file.pdf > output.md で変換する例があります(この環境では Docker を動かしていません)。
  • pipx:コマンドとしてだけ使うなら、pipx install 'markitdown[all]' で専用の環境に入れる方法もあります。
  • Homebrew:README のインストール手順は pip と Docker だけで、Homebrew の手順は書かれていません。

MarkItDownの使い方(コマンドライン)

この節では、markitdown コマンドの書き方と、オプションの意味、日本語の CSV が文字化けしたときの直し方が分かります。

基本は markitdown 入力ファイル で、結果は標準出力に出ます。 -o でファイルに保存し、ファイル名を省くと標準入力から読みます。

markitdown sample.pdf               # 画面に出す
markitdown sample.pdf -o sample.md  # ファイルに保存
markitdown sample.pdf > sample.md   # リダイレクトでも同じ
cat sample.docx | markitdown        # 標準入力から読む
markitdown http://127.0.0.1:47261/sample.html   # URL も読める

markitdown --help に出たオプションです(0.1.9)。

オプション 意味 使う場面
-o・--output 出力するファイル名 結果を .md に保存する
-x・--extension 拡張子のヒント 標準入力から読むとき
-m・--mime-type MIME タイプのヒント 拡張子の無いファイル
-c・--charset 文字コードのヒント Shift_JIS(cp932)の CSV・テキスト
-d・-e Azure Document Intelligence を使う・その接続先 スキャンした PDF(外部に送る)
--use-cu・--cu-endpoint Azure Content Understanding を使う 動画・音声・項目の抽出(外部に送る)
-p・--list-plugins プラグインを使う・一覧を出す 他の人が作った変換器を使う
--keep-data-uris 埋め込み画像の base64 を省略しない 画像も Markdown に残したいとき

Shift_JIS の CSV は -c cp932 を付ける

Excel から「CSV」で保存した日本語のファイルは、多くの場合 Shift_JIS(Windows では cp932)です。文字コードを付けずに変換すると、エラーにはならず、ハングルのような文字に化けました。

$ markitdown sjis.csv
| 롊덒붥뜂 | 럞뼹 | 븫룓 |
| --- | --- | --- |
| 1001 | 랹밹뫞쁚 | 뎑떾븫 |
| 1002 | 績떞됓럔 | 둎뵯븫 |

$ markitdown -c cp932 sjis.csv
| 社員番号 | 氏名 | 部署 |
| --- | --- | --- |
| 1001 | 山田太郎 | 営業部 |
| 1002 | 髙橋花子 | 開発部 |

標準入力から読むときは、cat sjis.csv | markitdown -x csv -c cp932 のように拡張子のヒントも付けます。-c shift_jis を指定しても、cp932 だけにある「髙」を含むこのファイルは、エラーにならずに全体が化けました(「髙」を含まないファイルは shift_jis で読めた)。読めない文字コードのヒントは黙って捨てられ、推定した文字コードで変換されるためです。Windows で作ったファイルには cp932 を指定します。docx は、ヒントが無くても標準入力から正しく変換できました(中身から形式を推定するため)。

コマンドラインが向く

1〜数ファイルを手で変換する

シェルスクリプトや別の言語から呼ぶ

1回ごとに約2.5〜3.7秒かかった(起動込み)

Python API が向く

フォルダーの中をまとめて変換する

失敗した件だけ記録して続ける

import は1回(1.7秒)で、あとは1件数十ms

MarkItDownの使い方(Python API)

この節では、Python のコードから MarkItDown を呼ぶ書き方と、convert・convert_local・convert_stream の使い分けが分かります。

MarkItDown() を作り、convert() の戻り値の .markdown を読みます。

from markitdown import MarkItDown, StreamInfo

md = MarkItDown(enable_plugins=False)   # プラグインは既定で無効

result = md.convert("sample.docx")       # パス・URL・ファイルオブジェクトを受け付ける
print(result.markdown)                   # 変換した Markdown
print(result.title)                      # HTML なら <title> の中身、docx は None

# 文字コードや形式を指定して、開いたファイルから変換する
with open("sjis.csv", "rb") as fp:
    result = md.convert_stream(fp, stream_info=StreamInfo(extension=".csv", charset="cp932"))

手元で動かした結果です。

import: 1.71s
DocumentConverterResult | title: None | markdown == text_content: True
# 社内勉強会の案内\n\nこの資料は MarkItDown の変換テスト用に作った
pptx title: None
html title: 製品ページ
| 社員番号 | 氏名 | 部署 |
no hint: | 롊덒붥뜂 | 럞뼹 | 븫룓 |
メソッド 受け付けるもの 使う場面
convert() パス・URL・ファイルオブジェクト・requests の応答 手元で何でも変換する
convert_local() ローカルのパスだけ URL を読ませたくない処理
convert_stream() バイナリで開いたファイルオブジェクト アップロードされた中身・メモリ上のデータ
convert_response() requests.get() の応答 URL の取得を自分で制御する
  • result.text_content は、result.markdown と同じ文字列でした(以前の版の書き方で、記事やサンプルによく出てくる)。新しく書くコードは .markdown を使います。
  • README は、MarkItDown が実行したプロセスの権限でファイルやネットワークを読むことを注意しています。 利用者が渡したパスや URL を変換するサービスでは、convert() ではなく、目的に合う一番狭いメソッド(ローカルだけなら convert_local()、中身だけなら convert_stream())を使い、内部のアドレスへの接続を止めます。

Word・PowerPoint・Excelの変換結果(入力と出力)

この節では、自作の Word・PowerPoint・Excel を変換したとき、どの要素がどう残り、どこが崩れるのかが実物で分かります。

Word(.docx)

入力は、見出し1・見出し2、太字と斜体、箇条書き、番号付きリスト、3列の表(「開発部」の2行を縦に結合)、画像、URL の段落を含む文書です。markitdown sample.docx の出力は次のとおりでした。

# 社内勉強会の案内

この資料は MarkItDown の変換テスト用に作った架空の文書です。

**太字の語**と*斜体の語*を含む段落です。

## 日程

* 第1回:11月5日(水)
* 第2回:11月12日(水)

## 手順

1. 会議室を予約する
2. 資料を共有する

## 参加者

|  |  |  |
| --- | --- | --- |
| 部署 | 氏名 | 人数 |
| 開発部 | 山田 | 5 |
| 佐藤 | 3 |
| 営業部 | 鈴木 | 2 |

## 図

![](data:image/png;base64...)

参考:https://example.com/study
  • 見出し・太字・斜体・リスト・番号付きリストは、Word のスタイルどおりに Markdown になりました。
  • 表の1行目が空の見出し行になりました。 Word の表に「見出し行」の指定が無いと、すべての行が普通の行として扱われ、Markdown の表の形を作るために空の行が足されます。
  • 縦に結合したセルの次の行は、列が1つ足りなくなりました(「佐藤 | 3」)。佐藤が「部署」の列にずれて読めてしまいます。
  • 画像は data:image/png;base64... に省略されます。--keep-data-uris を付けると base64 がすべて残り、出力は 531 バイトから 11,825 バイトに増えました。

同じ docx を pandoc 3.1.3(pandoc -t gfm)で変換すると、表は次のようになりました。結合セルは空のセルとして列数が保たれ、1行目は見出し行になっています。

| 部署   | 氏名 | 人数 |
|--------|------|------|
| 開発部 | 山田 | 5    |
|        | 佐藤 | 3    |
| 営業部 | 鈴木 | 2    |

PowerPoint(.pptx)

入力は3枚のスライドです。1枚目はタイトルと2段階の箇条書きと発表者ノート、2枚目は表と棒グラフ、3枚目は画像だけです。

<!-- Slide number: 1 -->
# 四半期の振り返り
売上は前期比 112%
新規顧客 8 社
うち紹介 3 社

### Notes:
社内メモ:数字は速報値。外に出さない。

<!-- Slide number: 2 -->
# 月別の件数
| 項目 | 7月 | 8月 | 9月 |
| --- | --- | --- | --- |
| 問い合わせ | 12 | 15 | 21 |
| 受注 | 3 | 4 | 6 |

### Chart

| Category | 受注 |
|---|---|
| 7月 | 3.0 |
| 8月 | 4.0 |
| 9月 | 6.0 |

<!-- Slide number: 3 -->

![chart.png](Picture1.jpg)
  • スライドの区切りは HTML のコメント(<!-- Slide number: 1 -->)、タイトルは # の見出しになりました。
  • 箇条書きは、行頭の記号も階層(「うち紹介 3 社」は1段下げていた)も消え、ただの行になりました。
  • 表はそのまま表に、グラフは元の数値が表として出ました(整数の 3 が 3.0 になる)。グラフの画像だけを貼ったスライドでは、数値は取れません。
  • 発表者ノートは ### Notes: の下にすべて出ます。 社外に出せないメモがノートにあると、そのまま AI や検索の索引に入ります。
  • 画像は代わりの文字(alt)と、ファイル内の名前(Picture1.jpg)だけになります。

Excel(.xlsx)

入力は2枚のシートです。「売上」シートは、合計の列に数式(=B2+C2)、商品Bの8月を空のセル、6行目に A〜D を結合した注記を入れました。openpyxl で作ったままのファイルを変換した結果です。

## 売上
| 月 | 商品A | 商品B | 合計 |
| --- | --- | --- | --- |
| 2026-07 | 1200.0 | 800.0 | NaN |
| 2026-08 | 1500.0 | NaN | NaN |
| 2026-09 | 1800.0 | 950.0 | NaN |
| NaN | NaN | NaN | NaN |
| ※ 金額の単位は千円 | NaN | NaN | NaN |

## 担当
| 氏名 | 担当 |
| --- | --- |
| 山田 | 商品A |
| 佐藤 | 商品B |
  • シートごとに ## シート名 の見出しと表になりました。
  • 空のセル・空の行・結合セルの残りは NaN になりました。 空のセルがある列は小数として読まれ、1200 が 1200.0 になります(中で pandas を使うため)。
  • 数式の列はすべて NaN でした。 MarkItDown は数式を計算せず、ファイルに保存された計算結果を読みます。プログラムで作ったファイルには計算結果が入っていません。

同じファイルを LibreOffice で開いて保存し直す(soffice --headless --convert-to xlsx)と、合計の列に値が入りました。

| 2026-07 | 1200.0 | 800.0 | 2000.0 |
| 2026-08 | 1500.0 | NaN | 1500.0 |
| 2026-09 | 1800.0 | 950.0 | 2750.0 |

Excel の数字を AI に読ませるとき

やってはいけないプログラムで作った xlsx や、NaN の混ざった表をそのまま渡して「合計は?」と聞く
→
代わりにExcel か LibreOffice で一度保存して計算結果を入れる。集計そのものは pandas・openpyxl で読んで行う

MarkItDown は「読ませる」ための変換。数値の計算は元のデータで行う

Excel を Python で読み書きする方法は、関連記事「Python openpyxlでExcel操作|読み書き・書式・グラフのコード一覧」で扱っています。

PDFの変換結果(テキストのPDFとスキャンしたPDF)

この節では、PDF を変換したときに見出し・表・文章がどう出るかと、スキャンした PDF が空になる理由が分かります。

入力は、reportlab で作った日本語の PDF です。見出し(Heading1・Heading2 のスタイル)、段落、罫線つきの4列の表、「・」で始まる行を入れました。

月次報告書(架空)
1. 概要
今月の問い合わせは21件で、前月より6件増えました。主な理由は、展示会での紹介です。
2. 件数の内訳
| 項目    | 7月 8月 | 9月  |
| ----- | ----- | --- |
| 問い合わせ | 12 15 | 21  |
| 受注    | 3 4   | 6   |
3. 次の打ち手
・紹介の多い業種に絞って案内を送る
・問い合わせフォームの項目を減らす
  • 文字は正しく取れましたが、見出しに # は付きませんでした。 PDF には「ここは見出し」という情報が無いことが多く、文字の大きさだけでは見出しと判断されません。
  • 表は Markdown の表として出ましたが、4列が3列になり、「7月 8月」が1つのセルにまとまりました。 数字の位置がずれるので、表の多い PDF は変換後に列の数を確かめます。
  • 段落の区切りの空行も無くなり、1行ずつのテキストになりました。

スキャンした PDF は空になる

文字を画像として貼っただけの PDF(紙をスキャンした書類と同じ形)を変換すると、エラーは出ず、出力は空でした(終了コード 0・0文字)。MarkItDown の PDF の変換は、PDF に埋め込まれた文字を取り出すだけで、画像の中の文字は読みません(OCR をしない)。

$ markitdown scan.pdf

$ echo $?
0

スキャンした PDF の文字を取るには、OCR のプラグイン(markitdown-ocr)や Azure Document Intelligence を足します(画像の説明・OCR の節)。一括で変換するときは、出力が空のファイルを数えると、スキャンした PDF を見つけられます。

HTML・CSV・画像・ZIPなどの変換結果

この節では、HTML・ノートブック・ZIP・画像・URL を変換したときの出力が分かります。

HTML

入力は、<nav>・<style>・<script>・<footer> を含む製品ページです。

[ホーム](/) | [会社概要](/about)

# 製品の使い方

インストールは `pip install foo` です。[ドキュメント](https://example.com/docs)も読めます。

## 料金

| プラン | 月額 |
| --- | --- |
| 無料 | 0円 |
| 有料 | 1,000円 |

```
foo --help
```

![ロゴ](logo.png)
© 2026 Example
  • <script> と <style> の中身は消え、見出し・表・リンク・コードはきれいに Markdown になりました。
  • メニュー(nav)とフッターは残りました。本文だけを取り出す機能は無いので、Web ページを AI に読ませるときは、メニューの文言が混ざることを前提にします。
  • 127.0.0.1 に立てた HTTP サーバーの URL を markitdown http://127.0.0.1:47261/sample.html と渡しても、同じ結果になりました(PDF の URL も変換できた)。

ノートブック・JSON・ZIP

$ markitdown sample.ipynb
# 分析メモ
合計を出す

```python
print(sum([1, 2, 3]))
```

$ markitdown sample.json
{"name": "サンプル", "items": [1, 2, 3]}

$ markitdown bundle.zip
Content from the zip file `bundle.zip`:

## File: docs/sample.html
(HTML の変換結果)

## File: data/sjis.csv
| 롊덒붥뜂 | 럞뼹 | 븫룓 |
...
  • ipynb は Markdown のセルとコードのセルが残り、実行結果(出力の「6」)は入りませんでした。
  • JSON はそのままのテキストです。
  • ZIP は中のファイルを1つずつ変換して ## File: パス でつなげます。中の Shift_JIS の CSV は文字化けしました(ZIP の中のファイルには -c のヒントが届かない)。

画像(jpg・png)

画像は、何も足さないと出力が空でした。exiftool を入れると、MarkItDown が自動で見つけ、メタデータを出力しました。タイトル・作成者・撮影日時・位置情報を書き込んだ jpg の結果です。

$ markitdown photo.jpg
ImageSize: 480x200
Title: 売上グラフ
Artist: Sample
DateTimeOriginal: 2026:10:29 10:00:00
GPSPosition: 35 deg 40' 48.00" N, 139 deg 45' 36.00" E

画像の中の文字(「売上グラフ(画像の文字)」)は出ず、位置情報(GPS)は出ました。 スマホで撮った写真を変換して共有すると、撮影場所も一緒に渡ることになります。以前の形式の .xls は [xls] で変換できましたが、.doc は対応しておらず、エラーになりました(エラーの節)。

LLM・RAGの前処理として使う(一括変換と区切り方)

この節では、フォルダーの中の文書をまとめて Markdown にし、RAG の索引に入れやすい単位に区切る方法と、かかった時間が分かります。

Markdown にすると、ファイルの大きさが大きく減り、見出しで区切れるようになります。 手元のファイルでは、docx が 45,184 バイトから 530 バイト、pptx が 49,343 バイトから 486 バイト、html が 697 バイトから 322 バイトになりました(画像と XML の枠を捨てるため)。

フォルダーをまとめて変換する

import sys, time
from pathlib import Path
from markitdown import MarkItDown

src, dst = Path(sys.argv[1]), Path(sys.argv[2])
dst.mkdir(parents=True, exist_ok=True)
md = MarkItDown()
start = time.perf_counter()
ok = ng = 0
for path in sorted(src.iterdir()):
    if path.suffix.lower() not in {".pdf", ".docx", ".pptx", ".xlsx", ".html"}:
        continue
    try:
        result = md.convert_local(path)
    except Exception as e:  # 1件の失敗で全体を止めない
        print(f"NG {path.name}: {type(e).__name__}")
        ng += 1
        continue
    out = dst / (path.stem + path.suffix.replace(".", "_") + ".md")
    out.write_text(result.markdown, encoding="utf-8")
    print(f"OK {path.name} -> {out.name} ({len(result.markdown)}字)")
    ok += 1
print(f"{ok}件成功・{ng}件失敗・{time.perf_counter() - start:.2f}秒")
$ python batch.py samples out
OK sample.docx -> sample_docx.md (312字)
OK sample.html -> sample_html.md (221字)
OK sample.pdf -> sample_pdf.md (208字)
OK sample.pptx -> sample_pptx.md (356字)
OK sample.xlsx -> sample_xlsx.md (275字)
OK scan.pdf -> scan_pdf.md (0字)
6件成功・0件失敗・1.49秒

出力のファイル名に元の拡張子を入れているのは、sample.pdf と sample.docx のように名前が同じファイルを上書きしないためです。scan.pdf の「0字」は、スキャンした PDF の目印です。

実測:コマンドを繰り返すより Python が速い

やり方 かかった時間 内訳
CLI を1回(docx) 2.5〜3.7秒 3回計測。ほとんどが起動と import
CLI を5回(docx・pptx・xlsx・pdf・html) 11.5秒 シェルの for で順に実行
Python で6ファイル(上のスクリプト) 3.8秒(変換は1.49秒) Python の起動と import を含む
import のあと1ファイルの変換 html 35ms・xlsx 63ms・pptx 71ms・pdf 71ms・docx 392ms 3回のうち最短

見出しごとに区切る(チャンク分割)

RAG では、文書を意味のまとまりで区切り、出典を付けて索引に入れます。Markdown の見出しで区切る最小の例です。

import re
from markitdown import MarkItDown

def chunks_by_heading(markdown: str, source: str):
    """## 見出しごとに区切り、出典と見出しを付けて返す"""
    for part in re.split(r"(?m)^(?=#{1,2} )", markdown):
        part = part.strip()
        if part:
            heading = part.splitlines()[0].lstrip("# ").strip()
            yield {"source": source, "heading": heading, "text": part}

result = MarkItDown().convert("samples/sample.docx")
for c in chunks_by_heading(result.markdown, "sample.docx"):
    print(c["source"], "|", c["heading"], "|", len(c["text"]), "字")
sample.docx | 社内勉強会の案内 | 73 字
sample.docx | 日程 | 37 字
sample.docx | 手順 | 29 字
sample.docx | 参加者 | 100 字
sample.docx | 図 | 65 字

PDF は見出しに # が付かないため、この方法では区切れません。PDF は文字数や空行で区切るか、レイアウトを解析するツールを使います。区切った文章をベクトルにする方法は関連記事「エンベディングとは?ベクトル検索とコサイン類似度を計算例で解説」で、RAG 全体の組み立ては関連記事「RAGの作り方|Pythonで動かす最小構成と精度の上げ方」で扱っています。

  • 1出力が空のファイルを数えるスキャンした PDF・画像だけの資料は0字になる。OCR に回すかを決める
  • 2表の列数を確かめるWord の結合セル・PDF の表は列がずれた。数字の多い表は元の資料と照らす
  • 3発表者ノートと位置情報を消すpptx の Notes と画像の GPS はそのまま出る。社外に出せない情報が混ざらないか見る
  • 4NaN と小数点を整えるExcel の空のセルは NaN、整数は 1200.0 になる。必要なら置き換える
  • 5出典(ファイル名・シート名・スライド番号)を残すAI の答えから元の資料に戻れるようにする

画像の説明・OCR・Azure Document Intelligence

この節では、画像やスキャンした PDF の中身を取るための3つの方法(LLM・OCR プラグイン・Azure)と、それぞれ外部に何が送られるかが分かります。

3つとも外部のサービスに画像や文書を送り、利用料がかかります。 この記事では外部に送らず、LLM は偽のクライアントで「何が渡されるか」だけを確かめ、ほかは README とソースコードで確かめました。

LLM で画像の説明を付ける

README によると、llm_client(OpenAI の形のクライアント)と llm_model を渡すと、pptx の画像と画像ファイルに説明文が付きます。llm_prompt で指示を変えられます。OpenAI と同じ形の偽のクライアントを渡して動かした結果です。

md = MarkItDown(llm_client=client, llm_model="gpt-4o",
                llm_prompt="画像の内容を日本語で1文で説明して")
print(md.convert("chart.png").markdown)
[送られるはずだった内容] model=gpt-4o prompt='画像の内容を日本語で1文で説明して' image=data:image/png;base64,iVBORw0K... (11318字)

# Description:
(ここにLLMの説明文が入る)
  • 画像は base64 の data URI にして、プロンプトと一緒に1回のリクエストで送られる形でした。
  • pptx では、画像の行が ![(説明文) chart.png](Picture1.jpg) のように、説明文が代わりの文字に入りました。
  • docx に貼った画像には、説明は付きませんでした(クライアントが呼ばれなかった)。README の説明どおり、対象は pptx と画像ファイルです。

OCR プラグイン(markitdown-ocr)

README によると、markitdown-ocr は PDF・DOCX・PPTX・XLSX に埋め込まれた画像の文字を LLM の画像認識で取り出すプラグインで、llm_client が無いときは OCR を飛ばして通常の変換になります。手元で依存を調べると、PyMuPDF(AGPL と商用のデュアルライセンス)が一緒に入りました。MarkItDown 本体の MIT とは条件が違うので、配布するソフトに組み込むときは確かめます。プラグインは既定で無効で、markitdown -p か MarkItDown(enable_plugins=True) で有効にします。入っているプラグインは markitdown --list-plugins で見られます。

$ markitdown --list-plugins
Installed MarkItDown 3rd-party Plugins:

  * No 3rd-party plugins installed.

Find plugins by searching for the hashtag #markitdown-plugin on GitHub.

Azure Document Intelligence・Content Understanding

  • Document Intelligence:markitdown 資料.pdf -d -e "接続先"(環境変数 MARKITDOWN_DOCINTEL_ENDPOINT でも指定可)。README によると、API キーが無ければ DefaultAzureCredential で認証し、--docintel-features で数式・高解像度 OCR などの追加の解析を選べ、その一部は追加の料金がかかります。
  • Content Understanding:--use-cu と --cu-endpoint。README は、動画の変換は Content Understanding だけが対応し、convert() のたびに課金される API を呼ぶので、--cu-file-types で送る形式を絞るよう注意しています。

MarkItDownのMCPサーバー(markitdown-mcp)

この節では、Claude などの AI アシスタントから MarkItDown を呼べるようにする MCP サーバーの動かし方と、実際のやり取りが分かります。

markitdown-mcp は、MarkItDown を MCP(AI とツールをつなぐ決まり)のサーバーとして公開するパッケージです。 PyPI の最新は 0.0.1a8(プレリリース)です。pip install markitdown-mcp で入れると、markitdown-mcp コマンドが使えます。

$ markitdown-mcp --help
usage: markitdown-mcp [-h] [--http] [--sse] [--host HOST] [--port PORT]
  --http       Run the server with Streamable HTTP and SSE transport rather
               than STDIO (default: False)
  --sse        (Deprecated) An alias for --http (default: False)
  --host HOST  Host to bind to (default: 127.0.0.1)
  --port PORT  Port to listen on (default: 3001)

標準入出力(STDIO)で JSON-RPC を送り、ツールの一覧と変換を試した応答です(長い行を省いています)。

→ {"jsonrpc":"2.0","id":2,"method":"tools/list"}
← {"jsonrpc":"2.0","id":2,"result":{"tools":[{"description":"Convert a resource described by an http:, https:, file: or data: URI to markdown",
    "inputSchema":{"properties":{"uri":{"title":"Uri","type":"string"}},"required":["uri"],...},"name":"convert_to_markdown",...}]}}

→ {"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"convert_to_markdown",
    "arguments":{"uri":"file:///…/samples/sample.pptx"}}}
← {"jsonrpc":"2.0","id":3,"result":{"content":[{"text":"<!-- Slide number: 1 -->\n# 四半期の振り返り\n売上は前期比 112%\n...","type":"text"}],"isError":false,...}}
  • ツールは convert_to_markdown(uri) の1つだけで、http:・https:・file:・data: の URI を受け付けます。 ローカルのファイルは file:/// から始まる絶対パスで渡します。
  • --http で起動すると 127.0.0.1 だけで待ち受け、/mcp に POST した initialize に 200 で応答しました。

Claude Desktop に登録するときは、設定ファイル(claude_desktop_config.json)の mcpServers に書きます。pip で入れたコマンドを使う形です(Docker のイメージを使う設定例は PyPI のページにあります)。

{
  "mcpServers": {
    "markitdown": {
      "command": "/path/to/.venv/bin/markitdown-mcp"
    }
  }
}

PyPI のページは、このサーバーには認証が無く、起動したユーザーの権限で読めるファイルとネットワークをすべて読めること、127.0.0.1 以外で待ち受けないことを警告しています。 MCP の仕組みは関連記事「MCPとは?サーバーとクライアントの仕組みと設定例を図解」で扱っています。

よくあるエラーとつまずき(原文つき)

この節では、MarkItDown でよく出るエラーの原文と、原因・直し方が分かります。

依存が足りない(MissingDependencyException)

docx を読む部品(mammoth)を外した状態で docx を変換したときの原文です。

markitdown._exceptions.FileConversionException: File conversion failed after 1 attempts:
 - DocxConverter threw MissingDependencyException with message: DocxConverter recognized the input as a potential .docx file, but the dependencies needed to read .docx files have not been installed. To resolve this error, include the optional dependency [docx] or [all] when installing MarkItDown. For example:

* pip install 'markitdown[docx]'
* pip install 'markitdown[all]'
* pip install 'markitdown[docx, ...]'
* etc.

対応していない形式(UnsupportedFormatException)

Word 97-2003 形式の .doc と、中身がでたらめなファイルで出ました。

markitdown._exceptions.UnsupportedFormatException: Could not convert stream to Markdown. No converter attempted a conversion, suggesting that the filetype is simply not supported.

.doc は、LibreOffice で soffice --headless --convert-to docx 資料.doc として docx にしてから変換します。.xls は [xls]([all] に含まれる)で変換できました。

起きたこと 原文・症状 直し方
docx・pdf が変換できない MissingDependencyException pip install 'markitdown[all]' か形式の extras
.doc・未知の形式 UnsupportedFormatException docx に変換してから。拡張子が無いなら -x
ファイルが無い FileNotFoundError: [Errno 2] No such file or directory パスとカレントディレクトリを確かめる
日本語の CSV が化ける エラーは出ず、ハングルのような文字になる -c cp932・StreamInfo(charset="cp932")
スキャンした PDF エラーは出ず、出力が空(終了コード 0) OCR プラグインか Azure を使う
Excel の合計が NaN 数式の列がすべて NaN Excel・LibreOffice で保存し直す
uv で版が 0.1.5 になる エラーは出ない。markitdown -v が 0.1.5 --prerelease=allow か形式を指定
Python 3.9 で入らない does not satisfy Python>=3.10,<3.15 Python 3.10〜3.14 を使う
  • CLI のエラーは Python のトレースバック(エラーの経路)のまま出ます。 最後の1行の例外の名前と文を読むと原因が分かります。
  • markitdown 資料.docx | head のように出力の途中で読むのをやめると、BrokenPipeError: [Errno 32] Broken pipe が出ました。変換の失敗ではありません。

判断表:MarkItDownか別のツールか

この節では、要素ごとの変換品質の比較と、MarkItDown を選ぶか別のツールを選ぶかの判断が分かります。

要素ごとの変換品質(手元の結果)

要素 Word PowerPoint Excel PDF
見出し ○ スタイルどおり ○ タイトルが # ○ シート名が ## × # が付かない
表 △ 空の見出し行・結合でずれる ○ そのまま △ NaN・小数になる △ 列がまとまる
リスト ○ 記号・番号が残る × 記号と階層が消える - △ 「・」の文字だけ
画像 △ data URI(省略) △ ファイル名だけ - × 出ない
その他 URL は文字のまま ノート・グラフの数値が出る 数式は保存済みの値だけ スキャンは空

どのツールを使うか

  1. 1いろいろな形式を AI に読ませたい → MarkItDownOffice・HTML・CSV・ZIP を1つの書き方で変換できる。MIT
  2. 2人が編集する文書として変換したい → pandoc手元では結合セルの列数が保たれた。Markdown から docx への逆向きもできる
  3. 3PDF の見出し・段組み・表をきちんと取りたい → レイアウト解析のツールDocling(MIT)・Marker(コードは Apache-2.0、モデルの重みは別の規約)・PyMuPDF4LLM(AGPL と商用)・MinerU(Apache 2.0 に条件を足した独自ライセンス)
  4. 4スキャンした書類が多い → OCR(Azure・LLM・OCR エンジン)費用と、外部に送ってよい文書かを先に決める
  5. 5Excel の数値を集計したい → pandas・openpyxl で直接読むMarkdown の表を経由しない
こんなとき おすすめ 理由
社内の資料を RAG に入れる MarkItDown+空・表のチェック 形式を問わず同じ処理で流せる
ChatGPT・Claude に資料を貼る MarkItDown(CLI か MCP) 画像や XML の枠を捨てて文字だけ渡せる
論文・数式の多い PDF レイアウト解析のツール MarkItDown は見出しと段組みを取らない
Java・Node.js・.NET から使う CLI を子プロセスで呼ぶか、MCP で呼ぶ 公式の実装は Python だけ
利用者が渡した URL を変換する Web サービス convert_stream+入力の検証 README が権限と接続先の制限を求めている
見た目どおりの文書を作り直す pandoc・Office の書き出し MarkItDown は書式を捨てる

1まず [all] で試す

形式ごとの extras を考えずに始められる。大きさが気になったら形式を絞って入れ直す。

2出力は必ず目で見る

表の列のずれ・NaN・空の出力は、エラーにならない。最初の数件は元の資料と並べて見る。

3外部に送る機能は分けて考える

LLM・Azure・音声の文字起こしは、文書や音声が外に出る。社外秘の資料はオフラインの変換だけにする。

よくある質問

Q. MarkItDown とは何ですか? A. PDF・Word・PowerPoint・Excel・HTML・CSV・画像などを Markdown に変換する、Microsoft が公開している Python のツールです。主に LLM や RAG に文書を渡す前の変換に使います。

Q. 無料で商用利用できますか? A. 本体は MIT ライセンスです。ただし markitdown-ocr が使う PyMuPDF は AGPL と商用のデュアルライセンスで、LLM や Azure を使う機能はそれぞれのサービスの料金がかかります。

Q. markitdown の使い方をいちばん短く言うと? A. pip install 'markitdown[all]' で入れ、markitdown 資料.pdf -o 資料.md で変換します。Python なら MarkItDown().convert("資料.pdf").markdown です。

Q. Windows で使えますか? A. Python 3.10〜3.14 があれば使えます。PowerShell では pip install "markitdown[all]" のように二重引用符で囲みます。Shift_JIS の CSV やテキストは -c cp932 を付けます。

Q. 画面(GUI)で使えますか? A. README で案内されているのは、コマンドライン・Python API・Docker・MCP サーバーです。画面から使いたいときは、MCP サーバーを Claude Desktop などに登録し、AI のチャットから変換を頼む方法があります。

Q. PDF の表がずれます。 A. 手元でも、罫線つきの4列の表が3列になりました。表の多い PDF は、元の Word や Excel があればそちらを変換するか、レイアウトを解析するツールを使います。

Q. スキャンした PDF の文字を取れますか? A. 何も足さないと出力は空です。markitdown-ocr(LLM の画像認識を使う)か、Azure Document Intelligence を使います。どちらも外部のサービスに画像を送ります。

Q. Markdown から Word や PDF に戻せますか? A. MarkItDown は Markdown にする向きだけです。Markdown から docx などに変換するときは pandoc などを使います。

Q. text_content と markdown の違いは? A. 0.1.9 では同じ文字列でした。text_content は以前の版から使われている名前で、README の例は markdown を使っています。

Q. 変換した結果が社外に送られることはありますか? A. PDF・Office・HTML などの通常の変換は手元だけで行います。LLM の画像説明・OCR プラグイン・Azure の機能・音声の文字起こし(Google の音声認識)を使ったときと、URL を変換するときは外部と通信します。

まとめ

  • MarkItDown は、PDF・Office・HTML などを Markdown に変換する Microsoft の Python ツール。pip install 'markitdown[all]'、markitdown 入力 -o 出力.md で使える。最新は 0.1.9(2026年10月29日時点)。
  • uv で [all] を入れると、エラー無しで 0.1.5 になった。--prerelease=allow か、形式を指定して入れる。
  • Word は見出し・リストがきれいに残るが、表の1行目が空の見出し行になり、結合セルで列がずれた。PowerPoint は箇条書きの記号と階層が消え、発表者ノートは全部出た。Excel は空のセルが NaN、未計算の数式も NaN になった。
  • PDF は文字は取れるが見出しの # は付かず、表の列がまとまった。スキャンした PDF は空の出力になり、エラーにはならない。
  • 大量の変換は Python API で行う(CLI 5回で11.5秒、Python で6ファイル3.8秒)。出力が空・表の列数・ノートと位置情報を確かめてから、AI や RAG に渡す。MCP サーバーは 127.0.0.1 だけで動かす。

次に読むとよい記事です。Markdown の書き方は関連記事「Markdown記法一覧|マークダウンの書き方早見表と表示されない原因」で、変換した文書を使った検索の仕組みは関連記事「RAGの作り方|Pythonで動かす最小構成と精度の上げ方」で扱っています。

参考・出典

確認日はいずれも 2026年10月29日です。

  • Microsoft「MarkItDown」(GitHub の README):https://github.com/microsoft/markitdown
  • PyPI「markitdown」(0.1.9・Requires-Python・ライセンス):https://pypi.org/project/markitdown/
  • PyPI「markitdown-mcp」(0.0.1a8・起動方法・セキュリティの注意):https://pypi.org/project/markitdown-mcp/
  • MarkItDown のソースコード「_transcribe_audio.py」(音声の文字起こし):https://github.com/microsoft/markitdown/tree/main/packages/markitdown/src/markitdown/converters
  • PyPI「docling」:https://pypi.org/project/docling/
  • PyPI「marker-pdf」:https://pypi.org/project/marker-pdf/
  • PyPI「mineru」:https://pypi.org/project/mineru/
  • uv「Resolution」(プレリリースの扱い):https://docs.astral.sh/uv/concepts/resolution/

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「MarkItDownとは?使い方とPDF・Word・Excelの変換結果を実物で比較」

株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。

WE ARE HIRING

RJCで一緒に開発しながら、
成長を楽しみませんか?

RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!

  • 127日年間休日
  • 12時間平均残業時間
  • 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!

ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。

ABOUT RJC RJCがどんな会社か知る 考え方、研修、働き方、福利厚生、社員の前職まで。RJCのことが丸わかり! RJC丸わかりページへ JOB DESCRIPTION 仕事内容・待遇を見てみる 仕事内容、給与・待遇、選考の流れ。経験者も未経験も!応募前に知りたいこと、まとめました! 募集要項を見る ENTRY エントリーする エントリーは1〜2分・履歴書不要です。まずは話を聞いてみたい、という方でも歓迎です! エントリーフォームへ

RJCで一緒に開発しながら、 成長を楽しみませんか?