firecrawl/pdf-inspector

GitHub: firecrawl/pdf-inspector

一个用 Rust 实现的快速 PDF 分类与文本提取库,通过智能识别扫描件与文本内容,避免不必要的 OCR,提升大规模文档处理的速度与成本效率。

Stars: 440 | Forks: 43

# pdf-inspector 用于 PDF 分类和文本提取的快速 Rust 库。支持检测 PDF 是基于文本的还是扫描件,提取带位置信息的文本,并转换为干净的 Markdown —— 全程无需 OCR。提供 [Python](docs/python.md) 和 [Node.js](napi/README.md) 绑定。 由 [Firecrawl](https://firecrawl.dev) 构建,可在 200 毫秒内本地处理基于文本的 PDF,跳过约 54% 不需要 OCR 的 PDF 的高昂开销。 ## 功能 - **智能分类** — 通过采样内容流,在约 10-50 毫秒内检测 TextBased、Scanned、ImageBased 或 Mixed PDF。返回置信度(0.0-1.0)以及每页的 OCR 路由建议。 - **文本提取** — 带字体信息、X/Y 坐标的位置感知提取,支持自动多列阅读顺序。 - **Markdown 转换** — 基于字体大小比例的标题(H1-H4)、项目符号/编号/字母列表、等宽字体检测的代码块、基于矩形的表格与启发式表格、粗体/斜体格式、URL 链接和分页。 - **表格检测** — 双模式:基于 PDF 绘制操作的矩形检测,以及基于文本对齐的启发式检测。支持财务表格、脚注和跨页延续表格。 - **CID 字体支持** — ToUnicode CMap 解码 Type0/Identity-H 字体,支持 UTF-16BE、UTF-8 和 Latin-1 编码。 - **多列布局** — 自动检测报纸风格的列,支持顺序阅读和 RTL 文本。 - **编码问题检测** — 自动标记损坏的字体编码,以便调用方回退到 OCR。 - **单文档加载** — 文档仅解析一次,并在检测与提取阶段共享,避免重复 I/O。 - **轻量级** — 纯 Rust 实现,不含 ML 模型,不依赖外部服务,仅依赖 `lopdf` 进行 PDF 解析。 ## 基准测试 在 [opendataloader-bench](https://github.com/opendataloader-project/opendataloader-bench) 数据集(200 个 PDF)上进行评估。仅展示直接文本提取引擎 —— 不使用 OCR 或 ML 模型。评分范围为 0-1,数值越高越好。 | 引擎 | Overall | Reading Order (NID) | Tables (TEDS) | Headings (MHS) | Speed (200 docs) | |---|---|---|---|---|---| | pdf-inspector | 0.78 | 0.87 | 0.59 | 0.57 | 4s | | opendataloader | 0.84 | 0.91 | 0.49 | 0.74 | 11s | | pymupdf4llm | 0.73 | 0.89 | 0.40 | 0.41 | 18s | | markitdown | 0.58 | 0.88 | 0.00 | 0.00 | 8s | 相比之下,使用 OCR/ML 的引擎(docling、marker、mineru)在整体评分上为 0.83-0.88,但处理同一数据集需要 2 到 180 分钟。 **我们的优势:** 速度(所有引擎中最快)、阅读顺序、相较于其他直接文本工具的表格检测。 **待改进之处:** 标题检测落后于 opendataloader —— 许多 PDF 使用正文字体大小的粗体文本作为标题,或标题仅比正文稍大;表格检测落后于基于 OCR 的引擎,因为后者能直接看到视觉表格结构。 ## 快速开始 ### Python ``` pip install maturin maturin develop --release ``` ``` import pdf_inspector result = pdf_inspector.process_pdf("document.pdf") print(result.pdf_type) # "text_based", "scanned", "image_based", "mixed" print(result.markdown) # Markdown string or None ``` ### Node.js ``` npm install firecrawl-pdf-inspector ``` ``` import { readFileSync } from 'fs'; import { processPdf, classifyPdf } from 'firecrawl-pdf-inspector'; const result = processPdf(readFileSync('document.pdf')); console.log(result.pdfType); // "TextBased", "Scanned", "ImageBased", "Mixed" console.log(result.markdown); // Markdown string or null ``` ### Rust ``` [dependencies] pdf-inspector = { git = "https://github.com/firecrawl/pdf-inspector" } ``` ``` use pdf_inspector::process_pdf; let result = process_pdf("document.pdf")?; println!("Type: {:?}", result.pdf_type); if let Some(markdown) = &result.markdown { println!("{}", markdown); } ``` ### CLI ``` # 将 PDF 转换为 Markdown cargo run --bin pdf2md -- document.pdf # JSON 输出(用于管道传输) cargo run --bin pdf2md -- document.pdf --json # 仅原始 Markdown(无标题) cargo run --bin pdf2md -- document.pdf --raw # 插入分页标记() cargo run --bin pdf2md -- document.pdf --pages # 仅处理特定页面 cargo run --bin pdf2md -- document.pdf --select-pages 1,3,5-10 # 仅检测(不提取) cargo run --bin detect-pdf -- document.pdf cargo run --bin detect-pdf -- document.pdf --json # 检测 + 布局分析(表格、列) cargo run --bin detect-pdf -- document.pdf --analyze --json ``` ## 架构 ``` PDF bytes │ ├─► detector → PdfType (TextBased / Scanned / ImageBased / Mixed) │ └─► extractor ├─ fonts → font widths, encodings ├─ content_stream → walk PDF operators → TextItems + PdfRects ├─ xobjects → Form XObject text, image placeholders ├─ links → hyperlinks, AcroForm fields └─ layout → column detection → line grouping → reading order │ ├─► tables │ ├─ detect_rects → rectangle-based tables (union-find) │ ├─ detect_heuristic → alignment-based tables │ ├─ grid → column/row assignment → cells │ └─ format → cells → Markdown table │ └─► markdown ├─ analysis → font stats, heading tiers ├─ preprocess → merge headings, drop caps ├─ convert → line loop + table/image insertion ├─ classify → captions, lists, code └─ postprocess → cleanup → final Markdown ``` 文档通过 `load_document_from_path` / `load_document_from_mem` **加载一次**,并在检测与提取阶段共享,避免重复解析。 ### 项目结构 ``` src/ lib.rs — Public API, PdfOptions builder, convenience functions python.rs — PyO3 Python bindings types.rs — Shared types: TextItem, TextLine, PdfRect, ItemType text_utils.rs — Character/text helpers (CJK, RTL, ligatures, bold/italic) process_mode.rs — ProcessMode enum (DetectOnly, Analyze, Full) detector.rs — Fast PDF type detection without full document load glyph_names.rs — Adobe Glyph List → Unicode mapping tounicode.rs — ToUnicode CMap parsing for CID-encoded text extractor/ — Text extraction pipeline tables/ — Table detection and formatting markdown/ — Markdown conversion and structure detection bin/ — CLI tools (pdf2md, detect_pdf) napi/ — Node.js/Bun bindings (napi-rs) ``` ## 分类工作原理 1. 解析 xref 表和页面树(不加载完整对象) 2. 根据 `ScanStrategy` 选择页面(默认:扫描所有页面,支持提前退出) 3. 在内容流中查找 `Tj`/`TJ`(文本操作符)和 `Do`(图像操作符) 4. 基于文本操作符在采样页面中的存在情况进行分类 这可在毫秒级检测 300+ 页的 PDF。结果包含 `pages_needing_ocr` —— 缺少文本的特定页号列表,支持按页 OCR 路由而非全有或全无。 ### 扫描策略 | 策略 | 行为 | 适用场景 | |---|---|---| | `EarlyExit`(默认) | 扫描所有页面,遇到首个非文本页即停止 | 将文本类 PDF 路由至快速提取 | | `Full` | 扫描所有页面,不提前退出 | 准确区分 Mixed 与 Scanned | | `Sample(n)` | 采样 `n` 个均匀分布的页面(首、末、中部) | 超大 PDF 且更看重速度 | | `Pages(vec)` | 仅扫描指定的 1-indexed 页号 | 调用方已知需要检查的页面 | ## Markdown 输出 转换器支持处理: | 元素 | 检测方式 | |---|---| | 标题(H1-H4) | 基于与正文字体大小的比例层级,0.5pt 聚类 | | 粗体/斜体 | 字体名称模式(Bold、Italic、Oblique) | | 项目符号列表 | `*`、`-`、`•`、`○`、`●`、`◦` 前缀 | | 编号列表 | `1.`、`1)`、`(1)` 模式 | | 字母列表 | `a.`、`a)`、`(a)` 模式 | | 代码块 | 等宽字体(Courier、Consolas、Monaco、Menlo、Fira Code、JetBrains Mono)与关键字检测 | | 表格 | 基于 PDF 绘制操作的矩形检测 + 基于文本对齐的启发式检测 | | 财务表格 | 令牌拆分以整合聚合数值 | | 标注 | “Figure”、“Table”、“Source:” 前缀检测 | | 上标/下标 | 字体大小与相对于基线的 Y 偏移 | | URL | 转换为 Markdown 链接 | | 断词 | 跨行连接的单词重新合并 | | 页码 | 从输出中过滤 | | 首字下沉 | 大号首字与后续文本合并 | | 浮点省略号 | TOC 风格省略号折叠为 “ ... ” | ## 使用场景:智能 PDF 路由 pdf-inspector 为大规模 PDF 处理流水线设计。无需将每个 PDF 都送入 OCR: ``` PDF arrives → pdf-inspector classifies it (~20ms) → TextBased + high confidence? YES → extract locally (~150ms), done NO → send to OCR service (2-10s) ``` 这可为大多数已是文本类的 PDF(报告、论文、发票、法律文档)节省成本与延迟。 ## 调试 请参考 [docs/debugging.md](docs/debugging.md) 了解 `RUST_LOG` 环境变量的使用方法。 ## 许可证 MIT
标签:200ms响应, CID字体, CMap解码, Firecrawl, Latin-1编码, Markdown转换, MITM代理, Node.js绑定, OCR规避, OCR路由建议, OpenDataLoader, PDF分类, PDF文本提取, PDF检查, PDF解析, Python绑定, RTL支持, Rust库, UTF-16, X/Y坐标, 位置感知提取, 内容流采样, 单依赖lopdf, 可视化界面, 多列布局, 字体信息提取, 扫描件检测, 文本提取基准, 文本版PDF, 无ML模型, 智能路由, 本地处理, 混合PDF, 纯Rust, 编码问题检测, 置信度评分, 表格检测, 逆向工具, 通知系统, 阅读顺序, 高性能PDF