MarkItDown มักถูกจับไปวางไว้ข้าง ๆ เครื่องมือเว็บสแครปเปอร์บ่อยมาก และการจัดหมวดแบบนั้นก็คลาดเคลื่อน เพราะมันไม่มีทั้ง crawler, ไม่มี JavaScript engine และไม่มีวิธีดึง URL แล้วค่อยล้างโครงสร้างขยะของหน้าเว็บให้เหลือแค่เนื้อหาหลัก สิ่งที่มันทำคือรับไฟล์ที่คุณมีอยู่แล้ว — ไม่ว่าจะเป็น PDF, เอกสาร Word, สเปรดชีต, หรือสไลด์ — แล้วแปลงทั้งหมดให้เป็น Markdown ที่โมเดลภาษาอ่านได้
ผมใช้เวลาหลายสัปดาห์ทดสอบ Microsoft MarkItDown กับเอกสารจริงจำนวนหนึ่งบน Mac เครื่องเดียว โดยให้คะแนนทุกตารางเทียบกับ manifest ที่เขียนไว้ก่อนเริ่ม และจับเวลาทุกการแปลง สรุปสั้น ๆ คือ: ถ้าเป็นอินพุตที่สะอาด มันเร็วและให้ผลตรงตามต้นฉบับ แต่แพ็กเกจของมันแอบพ่วง runtime ของ machine learning ขนาด 73 MB ที่คุณอาจไม่ได้ต้องการไว้ด้วย และตารางของมันมีวิธีพังแบบที่ผ่านด่านตรวจว่า “ข้อความยังอยู่ครบไหม?” แต่ไม่ผ่านด่านว่า “ข้อมูลยังอยู่คอลัมน์เดิมไหม?” นี่คือภาพรวมทั้งหมดพร้อมตัวเลข
MarkItDown คืออะไรกันแน่
MarkItDown คือยูทิลิตีภาษา Python จาก Microsoft สำหรับแปลงไฟล์และเอกสาร Office ให้เป็น Markdown ที่เหมาะกับการใช้งานกับ LLM แค่ชี้ไปที่ PDF, .docx, .xlsx, .pptx, รูปภาพ, ไฟล์ HTML หรือฟอร์แมตอื่น ๆ ที่รองรับ แล้วมันจะส่ง Markdown กลับมาให้ มี 3 วิธีเรียกใช้: ผ่าน CLI (markitdown file.pdf -o out.md หรือส่งจาก stdin), ผ่าน Python API (MarkItDown().convert(...)), และผ่าน MCP server แบบเสริมสำหรับ workflow ของเอเจนต์

จุดสำคัญที่สุดไม่ใช่สิ่งที่มันทำ แต่คือสิ่งที่มัน ไม่ทำ เพราะ README ก็ไม่ได้อ้างว่าเป็นแบบนั้น และผมยืนยันจากการทดสอบแล้ว: ไม่มีการ crawl, ไม่มีการ render JavaScript, ไม่มีการไล่ลิงก์, ไม่มี pagination และไม่มีการดึงเฉพาะเนื้อหาหลักแบบเครื่องมือสาย readability มันเป็นตัวแปลงทั้งเอกสาร คุณเอา bytes มาให้ แล้วมันแปลงให้เป็นมาตรฐาน ความต่างเพียงข้อนี้แหละที่ตัดสินเลยว่าเครื่องมือนี้เหมาะจะอยู่ในสแตกของคุณหรือไม่ ซึ่งผมจะย้ำประเด็นนี้กลับมาอีกหลายครั้ง
ตัว repo เองก็เป็นของหนักตามสถิติยอดนิยมของ GitHub — 165,282 stars และ 11,790 forks ณ กลางเดือนกรกฎาคม 2026 ใช้สัญญาอนุญาต MIT และรีลีสล่าสุด (v0.1.6) ออกเมื่อ 2026-05-26 แต่จำนวนดาวนั้นสะท้อนกระแสความสนใจต่อเครื่องมือ LLM ขององค์กร Microsoft มากกว่าเป็นสัญญาณเรื่องความสุกงอมของแกน conversion จริง ๆ อีกทั้งยังมี 833 issues ที่เปิดอยู่ และบางอันก็เป็นเรื่องที่คุณควรรู้ก่อนติดตั้ง (จะพูดต่อด้านล่าง)
HTML เป็น Markdown: เร็วและครบ แต่พ่วง boilerplate มาด้วย
เพราะชุดรีวิวเว็บสแครปเปอร์ของผมใช้ฟิกซ์เจอร์เว็บสี่ชุดเดิม ผมจึงป้อน MarkItDown ด้วยไฟล์ HTML แบบ local ชุดเดียวกัน — ไม่ใช่เพื่อให้คะแนนในฐานะสแครปเปอร์ แต่เพื่อดูว่า conversion จาก HTML เป็น Markdown ทำได้ดีแค่ไหน และบนหน้าที่ tag มาดี มันทำได้ดีจริง
ทั้ง 4 หน้าแปลงได้ด้วย install หลักโดยไม่ต้องลงอะไรเพิ่ม และ probe เนื้อหาหลักทุกจุดยังอยู่ครบ บทความ Wikipedia เรื่อง "Web scraping" (226 KB) ออกมาพร้อมโครงสร้างหัวข้อที่สะท้อนต้นฉบับ — h1 หนึ่งอัน, h2 เจ็ดอัน, h3 สิบสองอัน ตรงกับโครงสร้างจริงของบทความ — และเก็บลิงก์ไว้ครบ 418 ลิงก์ในรูป [text](url) ที่ถูกต้อง ตารางสถิติฮอกกี้ขนาด 25×9 บนหน้า Scrape This Site forms page กลายเป็นตาราง pipe ของ GFM ที่เรียบร้อย 27 แถว (header + separator + 26 แถวข้อมูล) รวมถึงช่องว่างทั้งหมด ความเร็วก็ไม่ใช่ปัญหาบนชุดนี้: ค่ามัธยฐาน 48 ms สำหรับหน้าคำคมขนาดเล็ก ไปจนถึง 352 ms สำหรับหน้า Wikipedia ขนาด 226 KB
แต่มีข้อแม้อยู่หนึ่งอย่าง และนี่เป็นการออกแบบ ไม่ใช่บั๊ก MarkItDown ไม่ได้ลบ boilerplate มันแปลงทั้ง <body> ดังนั้นส่วน chrome ของเว็บก็ถูกพ่วงมาด้วย — และเศษซากนั้นยิ่งมากตามปริมาณ chrome ที่หน้าเว็บมี
| Page | Output chars | Headings (h1/h2/h3) | Links | Site-chrome lines |
|---|---|---|---|---|
| Books to Scrape | 10,478 | 1 / 0 / 0 | 94 | 0.6% (1/159) |
| Quotes to Scrape | 2,973 | 1 / 1 / 0 | 55 | 1.2% (1/86) |
| ScrapeThisSite forms | 3,385 | 1 / 0 / 0 | 31 | 6.7% (5/75) |
| Wikipedia Web scraping | 60,159 | 1 / 7 / 12 | 418 | 12.4% (42/338) |
บนหน้า Books ที่แทบไม่มี chrome เลย 0.6% ของบรรทัดที่ออกมาคือ chrome ส่วน Wikipedia สูงถึง 12.4% — 42 จาก 338 บรรทัดที่ไม่ว่างคือพวก “jump to content,” “toggle the table of contents,” “22 languages,” “retrieved from,” รวมถึง footer เรื่องคุกกี้และลิขสิทธิ์ แบนเนอร์ดูแลบทความของ Wikipedia อย่าง “This article needs additional citations” ยังถูกแปลงออกมาเป็นตาราง pipe แบบสองคอลัมน์อย่างซื่อสัตย์ ซึ่งนี่แหละที่ทำให้หน้าที่ไม่มีตารางข้อมูลจริงกลับได้ตาราง 9 แถว
ทั้งหมดนี้ไม่ใช่ MarkItDown ทำผิดทาง แต่มันคือ converter ทั้งเอกสาร ไม่ใช่เครื่องมือดึงเฉพาะเนื้อหาหลัก: การแปลง HTML เป็น Markdown แบบตรงไปตรงมาเป็นคนละงานกับการสกัดบทความให้สะอาด Trafilatura และเครื่องมือแนว Firecrawl พยายามคืนกลับมาเฉพาะเนื้อหาหลัก ขณะที่ MarkItDown คืนทั้งหน้า ภายใน _html_converter.py ของมันจะลบ <script> และ <style> ออก แล้วส่ง body ทั้งหมดให้ไลบรารี markdownify โดยไม่มี heuristic สำหรับหา main content อยู่ในเส้นทางเลย ถ้าคุณต้องการแค่บทความ นี่คือชั้นที่ผิด
สนามถนัด: PDF, DOCX, XLSX, PPTX
เอกสารคือสิ่งที่ MarkItDown ถูกสร้างมาเพื่อจัดการ ผมทดสอบกับไฟล์สาธารณะจริง — กระดาษ arXiv ที่มี text layer, whitepaper ของ Bitcoin, PDF ที่สแกนเป็นรูปภาพอย่างเดียวซึ่งผมเรนเดอร์ให้ไม่มีข้อความเลย และไฟล์ DOCX/XLSX/PPTX จากชุดทดสอบของ MarkItDown เอง (ใส่ UUID เป็นตัวตรวจจับเพื่อหาการสูญหายของเนื้อหาแบบเงียบ ๆ)
| Document | Input | Output chars | Probes | Median time | Notes |
|---|---|---|---|---|---|
| arXiv 1706.03762 (text-layer PDF) | 2.2 MB | 40,174 | 7/7 | 3.7 s (warm) | title, "Transformer", "BLEU", "References" all present |
| Bitcoin whitepaper (9 pp PDF) | 184 KB | 22,485 | 6/6 | 1.4 s | "Satoshi Nakamoto", "proof-of-work", "Conclusion" present |
| Scanned PDF (no text layer) | 89 KB | 0 | 0/4 | 15 ms | empty output, no error, no OCR |
| DOCX (test.docx) | 136 KB | 4,651 | — | 70 ms | headings + GFM table; embedded UUIDs survive |
| DOCX with equations | 15 KB | 240 | — | 101 ms | Office Math preserved as LaTeX |
| XLSX (test.xlsx) | 12 KB | 808 | — | 57 ms | each sheet → ## SheetName + GFM table |
| PPTX (test.pptx) | 278 KB | 2,047 | — | 52 ms | slide-number markers, tables, chart → table |
การดึงข้อความจาก PDF ที่มี text layer ทำได้ดีมาก — probe ที่กำหนดไว้ล่วงหน้า 7 จาก 7 จุดบน paper arXiv “Attention Is All You Need” และ 6 จาก 6 จุดบน Bitcoin whitepaper ผ่านทั้งหมด และไฟล์ Office ก็ไม่สูญเสีย UUID sentinel เลยสักตัว จึงไม่มีการหายของเนื้อหาแบบเงียบ ๆ ใน fixture ทดสอบของผู้ดูแลโครงการเอง ชัยชนะเฉพาะทางอีกข้อที่น่าสนใจ: เส้นทาง DOCX (ผ่าน mammoth) รักษาสมการ Office Math เป็น LaTeX ได้ แปลง equations.docx ออกมาเป็น math แบบ $$...$$ จริง ๆ ถ้าคุณป้อนเอกสาร Word ที่มีสมการจำนวนมากให้ LLM นี่เป็นจุดแข็งที่มีประโยชน์มาก แม้จะเฉพาะทาง
มีสองผลการทดสอบบนสนามนี้ที่ควรพูดแยก เพราะเป็นจุดที่มีโอกาสทำให้คุณสะดุดมากที่สุด
PDF ที่เป็นสแกนแล้วหายไปเฉย ๆ
ถ้าป้อน PDF ที่เป็นรูปภาพล้วนและไม่มี text layer ให้ MarkItDown มันจะคืนค่าว่างกลับมา ศูนย์อักขระ ไม่มี exception ไม่มีคำเตือน — แปลงเสร็จในราว 15 ms เพราะไม่มีอะไรให้ดึงออกมา path สำหรับ PDF ของ MarkItDown รองรับเฉพาะการดึงข้อความ (ภายใต้ใช้ pdfminer และ pdfplumber) และไม่มี OCR แถมมาใน install หลักหรือ extra ตัวใดตัวหนึ่งของ pip
เรื่องนี้สำคัญมากเมื่อรันเป็น batch ถ้านักพัฒนาป้อนโฟลเดอร์ PDF ที่มีทั้งไฟล์สแกนและไฟล์ปกติ ระบบจะได้ผลลัพธ์ว่างแบบเงียบ ๆ สำหรับไฟล์ที่สแกน โดยไม่มีสัญญาณเตือนว่ามีบางไฟล์ถูกข้าม ผมเช็กว่า fixture ไม่เสียด้วยการเรียก extract_text ของ pdfminer ตรง ๆ — ก็ได้ศูนย์อักขระเหมือนกัน ไม่มี text layer ยืนยันแล้ว ดังนั้น output ที่ว่างจึงเป็นพฤติกรรมจริงของ MarkItDown กับสแกนจริง นี่เป็นการสะท้อนช่องโหว่ OCR fallback ที่ค้างมานาน #1268 ซึ่ง upstream ติดตามมาพักใหญ่แล้ว เส้นทางที่มีเอกสารรองรับคือ Azure Document Intelligence backend แบบเลือกใช้ หรือ plugin ซึ่งไม่ได้มากับ install เริ่มต้น
PDF ออกมาเป็นข้อความแบน ๆ ไม่ใช่โครงสร้าง
กับ PDF ทั้งสองที่มี text layer MarkItDown ไม่ได้สร้างสัญลักษณ์หัวข้อ Markdown เลยแม้แต่ตัวเดียว PDF ไม่มีแท็ก semantic สำหรับหัวข้อ และ MarkItDown ก็ไม่ได้เดาโครงสร้างจากขนาดฟอนต์ ดังนั้นทุกบรรทัดจึงลงมาอยู่ระดับ body ทั้งหมด การเรียกข้อความกลับมาทำได้ดี แต่โครงสร้างแบน
ไม่ใช่แค่ผลของผมเท่านั้น เบนช์มาร์กสาธารณะจากภายนอกให้คะแนน MarkItDown ในด้านลำดับชั้นหัวข้อของ PDF ใกล้ 0.0 และความถูกต้องของตารางราว 0.27 ซึ่งต่ำกว่า Docling ที่อิง TableFormer ซึ่งได้ราว 0.88 มาก (ดู การเปรียบเทียบ MarkItDown vs Docling vs Marker และ READoc benchmark) ฟิกซ์เจอร์ของผมให้ผลสอดคล้องกับของเขา ซึ่งเป็นจุดแข็งของหลักฐาน เพราะตัวเลขของผมตรงกับแหล่งข้อมูลภายนอก สิ่งที่เบนช์มาร์กเดียวกันชี้ให้เห็นอีกด้านคือ MarkItDown เร็วกว่าประมาณ 100 เท่าเมื่อเทียบกับ Docling ซึ่งสอดคล้องกับเวลาที่ผมวัดได้เป็นวินาที ไม่ใช่เป็นนาทีบนเอกสารที่เครื่องมือแบบ layout model ใช้เวลาหลายนาที ข้อสรุปคือ: MarkItDown ให้คุณได้ PDF ที่เป็น ข้อความ แบบสะอาดและเร็ว แต่ไม่ได้ให้ โครงสร้าง ของ PDF ถ้าหัวข้อและตารางต้องอยู่ครบ เครื่องมือแบบ layout model อย่าง Docling หรือ Marker คือชั้นที่เหมาะกว่า
ตาราง: ข้อความไม่เคยหาย แต่โครงสร้างอาจพัง
ตารางคือจุดที่คำถาม “ข้อความยังอยู่ครบไหม?” กับ “ข้อมูลยังใช้ได้ไหม?” แยกออกจากกัน ผมจึงสร้างเมทริกซ์ 13 กรณี — หนึ่ง <table> ต่อหนึ่งกรณี ให้คะแนนเทียบกับ manifest ที่เขียนไว้ก่อนเริ่ม — เพื่อดูให้ชัดว่า shape แบบไหนผ่านและแบบไหนพัง

ข้อสรุปหลัก: MarkItDown ไม่เคยทำให้เนื้อหาในตารางหาย ทุก 13 กรณียังเก็บ token ที่ลงทะเบียนไว้ก่อนทดสอบได้ 100% แต่ความถูกต้องของโครงสร้างแบ่งออกเป็น 3 แบบ เจ็ดจากสิบสามเคสได้ GFM grid ที่เรียบร้อย (plain, header-colspan, กว้าง 24 คอลัมน์, ไม่มีหัวตาราง, ช่องว่าง, block-in-cell, และภาษาอาหรับแบบ right-to-left) อีกสี่เคสออกมาไม่เรียบ เพราะ Markdown ไม่มีแนวคิดเรื่อง cell ที่ span จึงทำให้ rowspan, colspan และแหล่งต้นทางที่มีปัญหาออกมาเป็นแถวสั้น ๆ และอีกสองเคสพังชัดเจน
สองเคสที่พังควรระบุชื่อไว้ ตารางซ้อนตาราง (มี <table> อยู่ใน <td>) จะถูกทำให้แบนเป็นบรรทัดเดียว ทำให้ pipe และ separator row ของตารางด้านในไหลเข้าไปในเซลล์แม่ และสร้างแถวขยะที่ดูเหมือนมี 14 “คอลัมน์” ส่วนตัวอักษร | ที่อยู่ในเซลล์จะไม่ถูก escape — ข้อความ a | b กลายเป็นสองคอลัมน์ และ x || y กลายเป็นสามคอลัมน์ — ดังนั้นตารางสองคอลัมน์จึงอาจกลายเป็นแถวที่มี 2, 3 หรือ 4 คอลัมน์ และ Markdown parser ปลายทางก็จะอ่านขอบเขตผิดไปอีก เรื่องน่าสังเกตคือเครื่องหมายดอกจันและ backtick ภายในเซลล์ถูก escape อย่างถูกต้อง แต่ pipe ไม่ได้ถูก escape ต้นตอคือเส้นทาง HTML ของ MarkItDown ใช้การจัดการตารางแบบ default ของ markdownify และ subclass ที่เขียนเองนั้น override แค่ลิงก์ รูปภาพ และหัวข้อ ไม่ได้แตะเซลล์ตาราง ปัญหา escape pipe แบบเดียวกันยังอยู่ใน issue เปิดของ CSV converter (#2019) แม้จะแก้ bug นั้นก็ไม่ได้แตะเส้นทาง HTML ที่ผมทดสอบ
ประเด็นละเอียดที่ผมอยากให้ data engineer เห็นที่สุดคือ rowspan เคส t03 ไม่ได้แค่แถวไม่เรียบ แต่มันทำให้ข้อมูลเหลื่อมกันแบบเงียบ ๆ ป้าย rowspan=2 (“Fruit”) ถูกแสดงเพียงครั้งเดียว และแถวด้านล่างจะกลายเป็นแถวสั้นสองคอลัมน์ (| Banana | 8 |) ทำให้ “Banana” ไปอยู่ใต้คอลัมน์ Group แทน Item ทุก token ยังอยู่ครบ ถ้าคนใช้งานอ่านแค่ “คอลัมน์ที่สอง” แบบง่าย ๆ ก็จะได้ค่าผิด นี่คือบั๊กที่ผ่านการตรวจว่า text ยังอยู่ครบ แต่แอบทำให้ชุดข้อมูลเสีย
ข้อจำกัดเรื่อง span เองก็เป็นข้อกำหนดด้านการออกแบบที่รู้กันและติดตามอยู่แล้ว (#1211, #1248) — ตาราง pipe แบบ GFM ที่แบนราบจริง ๆ ไม่สามารถแทน spans หรือ nesting ได้ จึงเป็นการแลกโครงสร้างกับความครบถ้วนของเนื้อหา ยังมีพฤติกรรมที่ดีอยู่ด้วย: ตารางที่ไม่มีหัวจะได้แถวหัวว่างถูกสร้างขึ้นมาแทน (ดังนั้นข้อมูลจะไม่ถูกยกขึ้นไปเป็นหัวโดยไม่ตั้งใจ), ช่องว่างในตารางถูกคงไว้ และ <caption> จะยังอยู่เป็นบรรทัดข้อความเหนือโต๊ะ
การติดตั้งและการเริ่มต้น: ภาษีที่ยูทิลิตี “เบา ๆ” ไม่ได้เตือนคุณไว้
ไม่มีเรื่องไหนในงานทดสอบนี้ที่ทำให้ผมแปลกใจมากไปกว่านี้ และนี่คือจุดที่ภาพลักษณ์ “Python utility ขนาดเล็ก” ให้คำสัญญาเกินจริงแบบเงียบ ๆ

อย่างแรก อย่าใช้ pip install 'markitdown[all]' บน Python 3.14 เพราะมันจะถอยกลับไปติดตั้ง markitdown 0.0.2 แบบเงียบ ๆ ซึ่งเป็นรีลีสเก่าเมื่อสองปีก่อน และผมทดสอบยืนยันสดใน venv ที่สะอาดแล้ว เหตุผลชัดขึ้นเมื่อ pin เวอร์ชัน: pip install 'markitdown[all]==0.1.6' จะ error เพราะ extra [all] ไป pin youtube-transcript-api~=1.0.0 ไว้ และบน PyPI ปัจจุบัน build ในช่วงนั้นทั้งหมดถูกจำกัดให้ใช้ Python <3.14 ส่วน build ที่ใช้กับ 3.14 ได้จริงกลับอยู่นอกช่วง pin ดังนั้นตัว resolver จึงถอยกลับไปหา release ล่าสุดที่ยังพอ satisfy dependency ได้ เรื่องนี้ตรงกับ issue เปิด #2179 วิธีแก้ตรงไปตรงมา คือ pin เวอร์ชันแล้วติดตั้ง extras แยกกัน: pip install 'markitdown==0.1.6' จากนั้น pip install 'markitdown[pdf,docx,pptx,xlsx,xls]==0.1.6' แต่ละคำสั่งติดตั้งได้ปกติ มีเพียง bundle [all] ตัวเดียวที่พ่วง pin พิษนี้มา (กับดักนี้ขึ้นอยู่กับเวอร์ชัน Python — ถ้าเป็น Python 3.13 หรือต่ำกว่า เงื่อนไขอาจไม่ชน และ [all] อาจ resolve ต่างออกไป)
อย่างที่สอง คือ footprint ตัว install core ใช้พื้นที่ 161 MB (venv ว่าง 13 MB บวกของที่ติดตั้ง 148 MB) โดยในนั้น onnxruntime (73 MB) และ numpy (34 MB) รวมกันเป็น 107 MB หรือ 66% ของ footprint core ทั้งหมด และทั้งคู่ถูกดึงเข้ามาเพราะ hard dependency เพียงตัวเดียว: magika ตัวตรวจจับชนิดไฟล์แบบ machine learning ของ Google ดังนั้นตัวแปลงข้อความจึงต้องขน runtime สำหรับ inference ของ ONNX ขนาด 73 MB มาด้วยตั้งแต่ install พื้นฐาน ก่อนที่คุณจะเพิ่ม document extra ตัวใดเลย ถ้าเพิ่ม extras สำหรับเอกสารเข้าไป venv จะขยายเป็น 310 MB ซึ่งเบากว่าสแตก headless browser มาก แต่ถ้าคุณคาดหวังยูทิลิตีแบบ pip install แล้วจบ ก็ควรรู้ว่า ONNX runtime จะตามมาด้วย
อย่างที่สาม — และนี่คือผลการทดสอบเพียงหนึ่งเดียวในชุดนี้ที่ผ่านทุก novelty check ที่ผมลอง — แม้ติดตั้งสะอาดแล้ว import markitdown ก็ยังใช้เวลาประมาณ 3.35 วินาที บนเครื่องนี้ ต้นทุนส่วนใหญ่เกิดตอน import นั่นเอง: markitdown._markitdown import registry ของ converter ทั้งหมดแบบ eager (รวม 2.56 s หรือ 76% ของทั้งหมด) ซึ่งลาก pandas (1.21 s ผ่าน XLSX converter), python-pptx (427 ms), magika (354 ms), และ requests (270 ms) เข้ามาด้วย ไม่ว่าคุณจะใช้ฟอร์แมตเหล่านั้นจริงหรือไม่ก็ตาม ถ้าเป็น service ที่รันยาว ต้นทุนนี้ก็ถูกเฉลี่ยทิ้งไปและไม่สำคัญ แต่ถ้าเป็น CLI invocation หรือ serverless cold start มันคือภาษีต่อ process ที่หนักพอสมควร และคำว่า “lightweight utility” ไม่ได้บอกคุณล่วงหน้าเลย (ข้อแม้ที่ยุติธรรม: นี่เป็นการ profile รันเดียว ถูกนับเป็นหนึ่ง observation ไม่ใช่การกระจายจากหลายรัน)

สเกลการทำงาน: ไม่ล่ม แต่ต้องเผื่องาน CPU สำหรับ PDF และ RAM สำหรับสเปรดชีต
ผมโยนงานขนาดใหญ่ 4 ชุดผ่านมัน โดยแยกแต่ละชุดออกคนละ process เพื่อไม่ให้ peak memory ของรอบก่อนมาปน ไม่พบการ crash แต่ต้นทุนของมันไม่สมดุล

| Subject | Input | Output chars | Median time | Peak RSS Δ | |---|---:|---:|:--:|---:|---| | NIST SP 800-53r5 (492-page PDF) | 6.07 MB | 1,625,365 | 192.5 s | +40 MB | | XLSX 50,000 rows × 8 cols | 2.1 MB | 3,722,955 | 62.1 s | +374 MB | | arXiv 1706.03762 (~15-page PDF) | 2.2 MB | 40,174 | 12.6 s | +25 MB | | XLSX 200 rows × 64 cols | 46 KB | 120,129 | 2.9 s | +22 MB |
PDF NIST 492 หน้า ใช้เวลามัธยฐาน 192.5 วินาที — ประมาณ 3.2 นาที หรือ 0.39 วินาทีต่อหน้า — เพราะ pdfplumber ทำการตรวจจับฟอร์มตามตำแหน่งคำในทุกหน้า Peak RSS อยู่ที่ +40 MB จึงชัดว่าเป็นงานที่ติด CPU ไม่ใช่ติด memory แม้แต่ PDF arXiv 15 หน้า ก็ยังใช้เวลา 12.6 วินาทีเมื่อรันใน process ที่แยกเดี่ยว ซึ่งช้ากว่าตอนที่ไฟล์เดียวกันรันแบบ warm ในชุดเอกสารของผมถึงราว 3.4 เท่า ช่องว่างนั้นคือค่าใช้จ่ายของ cold process และยืนยันว่าตัวขับหลักคือการทำงานต่อหน้า ไม่ใช่ขนาดไบต์ดิบ ถ้าจะใช้ตัวเลขเดียวที่พกไปอ้างต่อได้ ให้ใช้ 12.6 วินาทีของการรันแบบ isolated นี้
เส้นทางของสเปรดชีตสลับคอขวดไปอีกแบบ XLSX ขนาด 2.1 MB จำนวน 50,000 แถว พุ่งเป็น +374 MB peak RSS (และได้ข้อความ Markdown ยาว 3.7 ล้านอักขระ) เพราะตัวแปลงโหลดทั้งชีตเข้าไปและสร้างสตริง Markdown ก้อนใหญ่ในหน่วยความจำ ดังนั้นคำแนะนำเชิงปฏิบัติจึงตรงไปตรงมา: ถ้าเป็น PDF ใหญ่ เตรียม CPU หลาย ๆ นาที; ถ้าเป็นสเปรดชีตใหญ่ เตรียม RAM หลายร้อย MB ตัวเลขเหล่านี้มาจากเครื่องเดียวบน macOS arm64 และ Python 3.14 และค่าคงที่ต่อหน้า/ต่อแถวก็ขึ้นกับแพลตฟอร์ม แต่รูปทรงของมัน — PDF ช้าและติด CPU, XLSX หนักที่ memory, และไม่มีอะไรล่ม — คือส่วนที่ถอดย้ายไปใช้ได้
ตำแหน่งของ Thunderbit — และจุดที่มันไม่ใช่
ลองใช้ Thunderbit สำหรับดึงข้อมูลเว็บ
นี่คือการเปรียบเทียบที่เผลอขยายความเกินจริงได้ง่ายที่สุด ผมจึงขีดเส้นให้ชัด MarkItDown กับ Thunderbit แก้ปัญหาใกล้เคียงกัน แต่ไม่ใช่ปัญหาเดียวกัน
MarkItDown แปลงไฟล์ที่คุณมีอยู่แล้ว Thunderbit ดึง หน้าเว็บมาก่อน endpoint /distill ของ Thunderbit เปลี่ยนหน้าเว็บที่ยังมีชีวิตให้กลายเป็น Markdown ที่สะอาดและพร้อมใช้กับ LLM — จัดการทั้งการ render JavaScript, anti-bot และเนื้อหาแบบ dynamic ที่ MarkItDown ไม่มีเครื่องมือรับมือ — ส่วน endpoint /extract จะคืน JSON ที่ตรงตาม schema ไม่ใช่แค่ Markdown ดิบ สำหรับนักพัฒนา สิ่งนี้มีให้ผ่าน API (POST /distill / POST /extract), MCP server, และ CLI (npx @thunderbit/thunderbit-cli) บน AI engine เดียวกัน ซึ่งเป็นตัวเดียวกับที่อยู่เบื้องหลังส่วนขยายที่มีผู้ใช้ 100,000+ คน
ดังนั้นสิ่งที่ทับซ้อนกันมีเพียงอย่างเดียว — ทั้งคู่สามารถให้ “LLM-ready Markdown” ได้ — แต่ domain ของอินพุตต่างกัน: distill ของ Thunderbit รับ URL บนเว็บสาธารณะ ขณะที่ MarkItDown รับ ไฟล์ในเครื่อง ทั้งสองไม่ใช่ตัวแทนกันแบบเสียบแทนได้ และผมจะไม่ทำเป็นว่าใช่ สแตกที่ใช้งานจริงมักใช้ทั้งคู่: ใช้ Thunderbit (หรือบริการแนว Firecrawl) เพื่อดึงและ crawl เว็บ จากนั้นใช้ MarkItDown เพื่อทำให้เอกสาร local แบบผสมที่คุณมีอยู่ — PDF, deck, spreadsheet — กลายเป็นมาตรฐาน อันหนึ่งจัดการเครือข่าย อีกอันจัดการตู้เก็บไฟล์
ข้อดีและข้อเสีย
จุดแข็ง
- ดึงเนื้อหาหลักจาก HTML ที่สะอาดได้ครบถ้วน (4/4 หน้า) พร้อมเก็บโครงสร้างหัวข้อและลิงก์ไว้อย่างซื่อสัตย์
- ดึงข้อความจาก PDF/DOCX ได้แม่นยำมาก (arXiv 7/7 probes, Bitcoin 6/6) และไม่มีการสูญหายของเนื้อหาแบบเงียบ ๆ บน fixture Office ของผู้ดูแลเอง
- รักษาสมการ Office Math ให้เป็น LaTeX ได้ — เป็นชัยชนะเฉพาะทางที่มีค่าจริง
- ไม่ล่มแม้กับงานขนาดใหญ่ ทั้ง PDF 492 หน้า และ XLSX 50k แถว
- เรียกใช้ได้ง่ายมาก: CLI,
convert(), ส่งผ่าน stdin และ MCP server แบบเลือกใช้ - ใช้สัญญา MIT, Microsoft ดูแลต่อเนื่อง, issue tracker ตอบสนองดี
จุดอ่อน
- พ่วง boilerplate มาด้วย — บน Wikipedia มี chrome lines สูงสุดถึง 12.4% ; ไม่ใช่เครื่องมือสกัดบทความ
- ตารางพังเมื่อมี span, nesting และ pipe ภายในเซลล์ (พัง 2/13, ร่อนเร่ 4/13) และ rowspan ทำให้ข้อมูลเลื่อนคอลัมน์แบบเงียบ ๆ
- PDF ที่สแกนเป็นรูปภาพล้วนจะได้ output ว่าง ไม่มี OCR และไม่มี error
- PDF output ไม่มีโครงสร้างหัวข้อเลย (สอดคล้องกับเบนช์มาร์กสาธารณะ)
- core install 161 MB พร้อม ONNX runtime 73 MB; cold import ~3.35 วินาที
- extra
[all]สามารถถอยกลับไปเป็นเวอร์ชัน 0.0.2 ที่เก่ากว่าสองปีบน Python 3.14 แบบเงียบ ๆ
ใครควรใช้ และใครไม่ควรใช้
ควรเลือก MarkItDown ถ้าคุณกำลังทำให้เอกสาร local หลายแบบ — Word, Excel, PowerPoint, PDF ที่มี text layer — กลายเป็น Markdown สำหรับ pipeline ของ LLM และคุณแคร์ความครบของข้อความมากกว่าการคงโครงสร้างเดิม ในงาน batch แบบเป็นขั้นตอนสุดท้ายที่ส่งข้อความสะอาดให้โมเดล มันเร็ว ซื่อสัตย์ และฟรี
แต่ควรข้าม หรือใช้ควบคู่กับเครื่องมืออื่น ถ้างานของคุณเข้าข่ายเหล่านี้: ต้องการแค่บทความหลักจากเว็บเพจเดียว (ใช้เครื่องมือสาย readability หรือแนว Firecrawl); ต้องการให้หัวข้อและตารางใน PDF อยู่ครบ (นั่นคือพื้นที่ของ Docling หรือ Marker); หรืออินพุตของคุณมีเอกสารสแกนที่ต้องใช้ OCR (คุณจะต้องใช้ Azure backend หรือเครื่องมืออื่นไปเลย) และถ้าคุณคิดว่ากำลังซื้อสแครปเปอร์ — เครื่องมือที่ดึงและ crawl ได้ — นี่ไม่ใช่แบบนั้นเลย
คะแนนชั่วคราวที่ผมลองให้บนรูบริกแบบสแครปเปอร์ออกมาเป็น 60/100 และคะแนนต่ำนี้เป็นผลจากการเอา converter ไปสอบแบบ crawler เมื่อมองในบ้านของมันเอง คะแนนด้าน text fidelity สูงมาก จุดอ่อนหลักเป็นเรื่องโครงสร้าง (ตาราง, PDF heading) และการบรรจุภัณฑ์ (footprint, import, กับดัก [all]) ไม่ใช่คุณภาพข้อความ ให้ตัดสินมันตามสิ่งที่มันเป็น — file-to-Markdown converter — แล้วมันคือเครื่องมือที่ดี ดูแลต่อเนื่อง และมีมุมคมไม่กี่จุดที่คุณควรรู้ก่อนเอาเข้าระบบ production
คำถามที่พบบ่อย
MarkItDown เป็นเว็บสแครปเปอร์ไหม?
ไม่ใช่ มันไม่มี crawler ไม่มีการ render JavaScript ไม่มีการไล่ลิงก์ และไม่มี pagination มันแปลงไฟล์และเอกสารที่คุณมีอยู่แล้ว — PDF, DOCX, XLSX, PPTX, รูปภาพ, HTML — ให้เป็น Markdown ถ้าคุณต้องการดึงและ crawl หน้าเว็บสด ๆ คุณควรใช้เครื่องมือสแครปปิงอย่าง Thunderbit หรือ Firecrawl; ส่วน MarkItDown คือขั้นตอนถัดมา สำหรับแปลงไฟล์ที่ดึงมาแล้วหรือไฟล์ local ให้เป็น Markdown ที่สะอาด
ทำไม pip install markitdown[all] ถึงติดตั้งเวอร์ชันเก่า?
บน Python 3.14 extra [all] จะ pin youtube-transcript-api~=1.0.0 และ build ทุกตัวในช่วงนั้นถูกจำกัดให้ใช้ Python ที่ต่ำกว่า 3.14 ตัว resolver ไม่สามารถ satisfy pin นี้ได้ จึงถอยกลับไปติดตั้ง markitdown 0.0.2 แบบเงียบ ๆ ซึ่งเป็นรีลีสอายุกว่าสองปี วิธีแก้คือ pin เวอร์ชันแล้วติดตั้ง extras แยกกัน: pip install 'markitdown==0.1.6' จากนั้นเพิ่ม 'markitdown[pdf,docx,pptx,xlsx,xls]==0.1.6' ปัญหานี้ถูกติดตามใน issue #2179
MarkItDown ทำ OCR กับ PDF ที่สแกนไหม?
ไม่ทำใน install เริ่มต้น path ของ PDF เป็นการดึงข้อความอย่างเดียว ดังนั้น PDF ที่เป็นรูปภาพล้วนและไม่มี text layer จะคืนค่าว่างกลับมา — ไม่มี error ไม่มีคำเตือน OCR ต้องใช้ Azure Document Intelligence backend แบบเลือกใช้ หรือ plugin ซึ่งไม่มีติดมาด้วยในค่าเริ่มต้น ช่องว่างนี้ถูกติดตามมานานแล้ว (issue #1268)
MarkItDown จัดการตารางได้ดีแค่ไหน?
ในมุมเนื้อหา ทำได้ดีมาก — ในการทดสอบ 13 กรณี มันเก็บเนื้อหาตารางครบ 100% ทุกเคส แต่ถ้ามองด้านโครงสร้างก็ขึ้นกับรูปทรง: ตารางง่าย ๆ, ตารางกว้าง, ไม่มีหัว, และมีช่องว่าง จะออกมาเป็น GFM grid ที่เรียบร้อย แต่ rowspan และ colspan จะทำให้แถวไม่เรียบ (และ rowspan อาจทำให้ข้อมูลไปอยู่คอลัมน์ผิดแบบเงียบ ๆ), ตารางซ้อนจะถูกแบนจนกลายเป็นแถวขยะ, และเครื่องหมาย pipe ที่อยู่ในเซลล์จะไม่ถูก escape Markdown ตารางแบบแบน ๆ ไม่สามารถแทน span หรือ nesting ได้อยู่แล้ว
MarkItDown เร็วพอสำหรับเอกสารขนาดใหญ่ไหม?
มันไม่ล่มกับไฟล์ใหญ่ แต่ควรเผื่อทรัพยากรแยกตามประเภท PDF 492 หน้าใช้เวลาประมาณ 3.2 นาที (ราว 0.39 วินาทีต่อหน้า) เพราะมันตรวจจับ form ตามหน้า และเป็นงานที่ติด CPU สเปรดชีต 50,000 แถวใช้เวลาราวหนึ่งนาที แต่กิน RAM เพิ่ม +374 MB เพราะมันสร้าง Markdown ก้อนใหญ่ไว้ในหน่วยความจำ สำหรับ PDF ใหญ่ควรเผื่อ CPU หลายนาที; สำหรับสเปรดชีตใหญ่ควรเผื่อ RAM หลายร้อย MB
ลองใช้ Thunderbit สำหรับดึงข้อมูลเว็บ Get Started Free


