DocSlicer


Lightning-fast (31 pages/sec), deterministic document parser and chunker for business documents. No LLM calls or heavy ML models.
DocSlicer turns PDFs, Word documents, HTML pages, and PowerPoint files into clean chunks, structured blocks, tables, charts, markdown and a navigable heading hierarchy.
Top score on BizDocBench (0.88 overall vs 0.70 for the next-best tool). 0.80 table accuracy, 0.98 content faithfulness, 0.85 heading recognition and hierarchy preservation, and 0.76 RAG retrieval performance.
Two ways to use it:
- As a Python library β classic RAG. The layout-aware chunker gives you clean, non-overlapping chunks, each carrying its full heading breadcrumb, ready to embed. Jump to the API β
- As an MCP server β vectorless RAG. For when you want an answer out of a document right now. Claude, Cursor, or VS Code pulls the outline, picks the section it needs, and reads only that β no embedding, and no 200-page document in the context window. Jump to setup β
Quick start
import docslicer
def main():
result = docslicer.parse_document("annual_report.pdf")
# Inspect the outline first
result.hierarchy.to_outline()
# - PART I β FINANCIAL INFORMATION
# - Item 1. Financial Statements
# - Notes to Condensed Consolidated Financial Statements
# - Note 4 β Financial Instruments
# - Derivative Instruments and Hedging
# - Foreign Exchange Rate Risk
# - Interest Rate Risk
# - Accounts Receivable
# - Trade Receivables
# - Item 2. Management's Discussion and Analysis
# - Liquidity and Capital Resources
# - PART II β OTHER INFORMATION
# ...
# Pull only the chunks you need
risk_section = result.find_heading("Risk Factors")[0]
chunks = result.chunks_under(risk_section)
# Tables come back structured, not as flat text
for table in result.tables_under(risk_section):
print(table.markdown)
if __name__ == "__main__":
main()
Features
- No LLM, VLM, or ML models β fully deterministic; no model weights to download, no GPU required, no cold-start delay
- Lightweight β ~630 KB wheel with no heavy ML dependencies
- Agentic-friendly β reduces token spend on long documents: have the agent inspect the outline first, then pull only the relevant chunks into context instead of feeding a 500-page document verbatim; well-suited for legal texts, technical SOPs, financial filings, and compliance documents
- Deep hierarchy extraction β works for both numbered (
1., 1.2., 1.2.3) and free-form headings; uses font size, bold weight, and document structure β not inference; handles re-entry after exhibit breaks and repeated navigation headings across pages
- Structure-aware chunking β splits at heading and paragraph boundaries, preserving semantic coherence
- Zero character overlap β chunks are non-overlapping by default; no duplicated tokens in your context window
- Unified result object β
chunks, blocks, tables, charts, metadata, and hierarchy in one place
- Structured tables β tables come back as cells, not flat text; export as Markdown, JSONL, or melted format
- Multiple export formats β CSV, Markdown, JSONL, Parquet, JSON, plain text, and DataFrames
- Reading order preserved β including multi-column PDF layouts
- Supports
pdf, docx, pptx, and html β including JS-rendered pages via Playwright
- Robust URL fetching β always renders pages in a real browser, handling cookie banners and bot protection out of the box; also preserves styling signals like boldness that raw HTML omits, producing sharper heading detection and chunk quality
- OCR fallback β auto-detects scanned pages and falls back to Tesseract when the extra is installed
Benchmarks
Measured with BizDocBench β an open benchmark for multi-format business document parsing. All scores are 0β1 (higher is better); pages_per_sec_aggregate is throughput across the full corpus.
| Tool | Score | Coverage | Speed | Hierarchy | Faithfulness | Tables | Retrieval | Pages/sec |
|---|
| docslicer | 0.8796 | 1.0000 | 0.8836 | 0.8466 | 0.9824 | 0.8047 | 0.7601 | 31.27 |
| docling | 0.7036 | 1.0000 | 0.3805 | 0.4905 | 0.8927 | 0.7467 | 0.7111 | 3.46 |
| markitdown | 0.5838 | 1.0000 | 0.8513 | 0.0604 | 0.7972 | 0.2584 | 0.5357 | 27.42 |
| unstructured | 0.5798 | 0.9091 | 0.1073 | 0.4327 | 0.9057 | 0.4812 | 0.6430 | 0.52 |
| opendataloader | 0.5359 | 0.5844 | 1.0000 | 0.3853 | 0.6484 | 0.2655 | 0.3317 | 117.26 |
| pymupdf4llm | 0.4519 | 0.5974 | 0.6492 | 0.1089 | 0.6456 | 0.3551 | 0.3552 | 11.84 |
| mineru | 0.4107 | 0.5974 | 0.1353 | 0.4220 | 0.6176 | 0.3012 | 0.3910 | 0.70 |
| marker | 0.3735 | 0.5974 | 0.1598 | 0.1926 | 0.6121 | 0.3012 | 0.3778 | 0.87 |
Install
The core install is dependency-light. Optional features are available as extras:
pip install 'docslicer[html]' # HTML / URL parsing via Playwright
playwright install chromium # one-time browser install (Chromium only)
pip install 'docslicer[ocr]' # scanned PDF support via Tesseract + OpenCV
# The tesserocr wheel bundles libtesseract but NOT the language models,
# so install the Tesseract engine to provide them (docslicer auto-detects the path):
# Linux: apt install tesseract-ocr
# macOS: brew install tesseract
pip install 'docslicer[mcp]' # MCP server for LLM clients (Claude, Cursor, β¦)
pip install 'docslicer[llm]' # exact token counts via tiktoken (exact_tokens=True)
pip install 'docslicer[crypto]' # password-protected Office files (msoffcrypto-tool)
pip install 'docslicer[parquet]' # Parquet export support
Extras can be combined: pip install 'docslicer[html,ocr,llm]'.
Requires Python 3.10+
What you get back (ParseResult)
parse_document returns a ParseResult:
result.chunks # list[Chunk] β heading-aware text chunks, ready for embedding
result.blocks # list[Block] β paragraph/heading/table blocks before chunking
result.tables # list[Table] β structured tables with cells, spans, and markdown
result.charts # list[Chart] β charts as extracted data points (docx/pptx)
result.metadata # DocumentMetadata β title, author, language, page count, OCR flag
result.hierarchy # HierarchyTree β navigable tree of all headings
Each Chunk carries:
chunk.text # str β chunk text
chunk.path # list β full heading breadcrumb from root to nearest heading
chunk.heading # str β nearest heading above this chunk
chunk.section # str β body | toc | exhibit | header | footer | coverpage | β¦
chunk.page_number # int β 1-based physical page
chunk.page_label # str β "A-6", "iv", "F-3" β as printed on the page
chunk.table_ids # list β IDs of tables referenced in this chunk
chunk.chart_ids # list β IDs of charts referenced in this chunk (docx/pptx)
chunk.link_url # list β URLs found in this chunk
chunk.bbox # BBox β bounding box (PDF only)
Every chunk carries its full heading breadcrumb, no matter how deeply nested. For example, a paragraph six levels deep in a financial filing:
chunk.path == [
"# PART I β FINANCIAL INFORMATION",
"## Item 1. Financial Statements",
"### Notes to Condensed Consolidated Financial Statements (Unaudited)",
"#### Note 4 β Financial Instruments",
"##### Accounts Receivable",
"###### Trade Receivables",
]
This lets downstream code filter or group chunks by any level of the hierarchy without re-parsing the document.
Supported formats
| Format | Extension | Notes |
|---|
| PDF | .pdf | Text-based and scanned (OCR extra required for scanned) |
| Word | .docx | Full style and outline hierarchy |
| HTML | .html, URLs | Static files and JS-rendered pages (html extra required for URLs) |
| PowerPoint | .pptx | Slides, speaker notes, charts |
Not supported: .doc, .ppt (legacy Office formats), .xlsx.
Parsing
parse_document auto-detects the format from the file extension or magic bytes. Pass a file path, URL, raw bytes, or a file-like object:
result = docslicer.parse_document("contract.docx")
result = docslicer.parse_document("report.pdf")
result = docslicer.parse_document("https://www.sec.gov/Archives/edgar/data/.../10-K.htm")
result = docslicer.parse_document(file_bytes)
Parsing & content options