多個PDF批次轉Markdown,一次完成
作者 pdftomd.tools 團隊 · 更新於 · 約 6 分鐘閱讀
要一次把多個 PDF 轉成 Markdown,最省事的方法是在批次頁面一口氣選好所有檔案,例如我們的 批次PDF轉Markdown 工具,再下載一個 ZIP。檔案有好幾百個,或是要固定執行的工作,寫一段簡短的 Python 迴圈比較好;版面複雜的,可以用 marker 的資料夾指令。不管選哪一種,轉完都要檢查有沒有空白的結果。

依檔案數量挑方法
要用哪種方法,跟 PDF 本身關係不大,主要看有幾個檔案、多久要做一次。大致上:
- 幾個到幾十個、只做一次:用瀏覽器的批次頁面。什麼都不用裝,檔案也不會離開你的裝置。
- 好幾百個,或每週都要做:寫個 Python 迴圈跑整個資料夾。可以排程、留紀錄,也能保留資料夾結構。
- 掃描檔、表單、公式、特殊版面:用 marker 這類以模型為基礎的工具。在一般筆電上會慢很多。它的設計是用 OCR 讀取沒有文字層的頁面,但在我們的 CPU 測試裡,掃描頁還是空白;建議先拿幾個檔案試跑。

為了公平比較三種方法,我們準備了 20 個檔案、共 40 頁的測試組:十二個表格和版面範例、一份英文指南、一份 11 頁的中文報告、一份頁首重複的 4 頁報告、一張沒有文字層的掃描頁,還有分別放在兩個資料夾、檔名都叫 notes.pdf 的兩個不同檔案。全部都在我們的建置主機(Linux x86_64, 8 vCPU, 16 GB RAM, no GPU)上執行。
在瀏覽器裡批次把 PDF 轉成 Markdown
開始之前,先打開兩三個 PDF,試著反白一句話。可以反白,就代表檔案有文字層,下面每種方法都能用;反白不了,就是掃描檔或圖片,只有 OCR 工具才抓得出文字。先知道手上的檔案混了哪些,可以省掉重跑一次。
打開批次頁面,按「選擇檔案」(或把選好的檔案拖到放置區),一次選取全部 PDF。每個檔案會在分頁裡依序轉換,最後頁面會提供一個 ZIP,每個 PDF 各對應一個 .md。因為是在本機處理,速度取決於你的裝置,而不是上傳速度。如果檔案都在同一台電腦上,這就是批次 PDF 轉 Markdown 最快的方法。

在我們的測試中,從選檔案到 ZIP 產生,整組檔案在 Chrome 155.0.8059.84 裡大約花了 0.8 秒(跑三次,介於 0.8 到 1.0 秒)。ZIP 裡有 20 個 Markdown 檔。兩個 notes.pdf 分別輸出成 notes.md 和 notes-2.md,沒有互相覆蓋;掃描頁則會在清單裡被標示出來,不會默默失敗。
限制是:瀏覽器本身讀不了資料夾樹狀結構,來自不同資料夾的檔案會並排放在同一個 ZIP 裡;數量非常大時,也會受到分頁記憶體的限制。好幾百個檔案的話,就分幾批選,或改用腳本。
用 pymupdf4llm 寫 Python 迴圈
處理這件事的 Python 腳本只要幾行。下面這支會把整個資料夾的 PDF 轉成 Markdown:逐一走過資料夾,輸出時保留相同的結構(所以兩個 notes 檔會分開),某個檔案失敗也會繼續執行:
import pathlib, pymupdf4llm
src, out = pathlib.Path("pdfs"), pathlib.Path("markdown")
for pdf in sorted(src.rglob("*.pdf")):
dest = out / pdf.relative_to(src).with_suffix(".md")
dest.parent.mkdir(parents=True, exist_ok=True)
try:
dest.write_text(pymupdf4llm.to_markdown(str(pdf)), encoding="utf-8")
except Exception as e:
print(f"skipped {pdf}: {e}")同樣 20 個檔案,迴圈在 5.3 秒內跑完,包含 Python 啟動和匯入函式庫的時間。它寫出 20 個檔案,其中兩個是空的:一個是沒有可讀文字的掃描頁,另一個是表格轉了 90 度的頁面。如果有好幾千個檔案,由於每個檔案彼此獨立,可以把同一個迴圈丟進行程池,每個 CPU 核心一個工作者。表格和頁碼範圍的選項請看我們的 Python 教學;pymupdf4llm 跟另外兩個函式庫的比較,請看 函式庫比較文章。
marker 的資料夾指令
marker 有一個處理整個資料夾的指令:marker /path/to/pdfs --output_dir out。它只讀資料夾的第一層(腳本用 os.listdir 列出檔案),所以我們先把檔案複製到一個平面的資料夾。常用的選項有:平行處理用的 --workers、從中斷處接著跑的 --skip_existing,以及試跑用的 --max_files。
在我們沒有 GPU 的電腦上用預設設定,整個資料夾花了 5 分 51 秒(含載入模型),產出 20 個結果,大約是 Python 迴圈的 66 倍。轉了方向的表格它有救回來,但寫了兩次;掃描頁在這次執行中仍然是空白檔。在有支援 GPU 的電腦上情況會不一樣;用筆電的話,只把真的需要的檔案交給 marker。
檔名、重複名稱與資料夾結構

- 重複名稱:一次轉很多 PDF 時,要先決定兩個資料夾裡的同名檔案怎麼處理。我們的批次頁面會加上編號;上面的迴圈會保留子資料夾;寫得太陽春的腳本會在沒有警告的情況下蓋掉第一個檔案。
- 結構:如果資料夾結構有意義(每位客戶或每一年一個資料夾),就把它留住:可以像上面一樣用
relative_to,或每個資料夾各用一次批次頁面。 - 命名:
.md沿用 PDF 的主檔名,之後就一定找得到原始檔。想要比較好讀的名字,之後再到筆記 App 裡改。 - 把 Markdown 檔打包成 ZIP 最方便交給別人;如果輸出還要給另一支腳本處理,用資料夾比較好。
品質檢查:找出掃描檔和空白結果
一次把多個 PDF 批次轉 Markdown,很容易漏看單一檔案時一眼就看得出的問題。我們測的每一個工具,都至少產出一個空白或幾乎空白的檔案,而且沒有 OCR 的話,誰都沒辦法把讀不到的頁面變成文字。所以每次大量轉換後,都要找出那些短得不太對勁的檔案:
# Markdown files under 100 bytes are usually scans or image-only pages
find markdown -name '*.md' -size -100c
接著隨機打開幾個結果,跟 PDF 對照:標題、一個表格、最後一段。如果這些檔案要丟給聊天模型,我們的 最適合 ChatGPT 的檔案格式 一文有說明,為什麼這一步檢查值得做,才能換到乾淨的 Markdown。
20 個檔案的實測時間
| 方法 | 時間 | 輸出數 | 空白輸出 | 重複名稱 |
|---|---|---|---|---|
| 我們的批次頁面(瀏覽器) | 0.8 秒 | 20 | scanned-sample.md | 加上編號(notes、notes-2) |
| Python 迴圈,pymupdf4llm 1.28.2 | 5.3 秒 | 20 | rotated.md, scanned-sample.md | 保留在子資料夾 |
| marker 2.0.0 資料夾指令 | 5 分 51 秒 | 20 | scanned-sample.md | 只支援平面資料夾(由我們改名) |
對多數人來說,結論很簡單:多個 PDF 批次轉 Markdown,先從瀏覽器開始;工作會一再重複,就寫成腳本;其他工具讀不出來的頁面,再交給以模型為基礎的工具。
資料來源
- PyMuPDF4LLM (README and licence) — Artifex, GitHub
- marker (README, licence and model licence) — Datalab, GitHub
- pathlib: Path.rglob — Python documentation
- find(1) — GNU findutils manual
常見問題
要怎麼一次把多個 PDF 轉成 Markdown?
在我們這類批次頁面選取所有檔案並下載 ZIP,或寫一段簡短的 Python 迴圈跑整個資料夾。轉完記得檢查有沒有空白的輸出。
批次頁面一次可以選幾個檔案?
沒有固定上限,限制在於瀏覽器的記憶體。我們測試 20 個檔案、40 頁大約花了一秒。好幾百個大型檔案的話,請分批處理或改用腳本。
同名的檔案會怎樣?
我們的批次頁面會替第二個檔案加上編號(notes.md、notes-2.md)。用腳本的話就由你決定:保留子資料夾、加上後綴,或直接略過。
掃描的 PDF 可以批次轉換嗎?
只讀文字層的工具沒辦法:掃描檔會是空白,我們的工具會把它標示出來。你需要先做 OCR。marker 就是為此設計的,但在我們沒有 GPU 的測試中,掃描頁的結果仍是空白;大量轉換前請先抽樣測試。
可以排程批次把 PDF 轉成 MD 嗎?
可以,用腳本就行。把 Python 迴圈放進 cron 或工作排程器,再加上類似 --skip_existing 的邏輯,只轉換新的檔案。
批次頁面會上傳我的檔案嗎?
不會。轉換是在瀏覽器分頁裡完成的,ZIP 也是在你的裝置上產生。

