Extractous:重新定义文档内容提取的速度与效率

在现代数据处理流程中,从各种格式的文档中高效提取文本和元数据已成为许多企业和开发者的核心需求。无论是处理法律文档、财务报告,还是分析网络内容,快速且准确地获取信息至关重要。尽管市场上有一些工具可供选择,但大多数方案存在性能瓶颈、依赖复杂或需要调用外部服务等问题。

今天,我们将深入介绍一款名为 Extractous 的开源工具,它以其卓越的性能、简洁的接口和强大的格式兼容性,为文档内容提取提供了全新的解决方案。

什么是 Extractous?

Extractous 是一款专为提取文档内容和元数据而设计的高性能工具。它支持多种常见格式,包括 PDF、Word、HTML 等,并凭借其底层 Rust 实现及与 Apache Tika 的深度集成,在速度和资源效率方面表现出众。

与许多依赖外部 API 或本地服务的工具不同,Extractous 被设计为在本地运行,无需网络调用,也无需启动额外的服务进程。这意味着更低的延迟、更少的依赖以及更好的隐私控制。

为什么需要 Extractous?

你可能听说过或者其他一些用于解析非结构化数据的工具,比如 unstructured-io。这类工具通常封装了多个庞大的 Python 库,导致运行缓慢且内存占用高。此外,由于 Python 全局解释器锁(GIL)的限制,它们往往无法充分利用多核 CPU 的处理能力。

更值得注意的是,随着这类工具的发展,它们逐渐变得更加复杂,甚至演变为需要独立部署的服务框架。这不仅增加了系统架构的复杂度,也为很多应用场景带来了不必要的负担。

Extractous 则坚持“简单且高效”的设计原则:

  • 核心基于 Rust 构建:利用 Rust 的高性能、内存安全性和并发处理能力。
  • 原生格式支持 + Apache Tika 扩展:对常见格式提供原生解析,同时通过 GraalVM 将 Apache Tika 编译为本地库,以支持更多文件类型,无需虚拟机或垃圾收集过程。
  • 多语言绑定:目前提供 Python 绑定,未来将支持更多语言,帮助开发者轻松集成到现有技术栈中。
  • 真正的多核利用:从根本上避免 GIL 问题,充分发挥多核CPU的优势。

主要特性一览

  • 高性能:为速度和低内存使用而优化。
  • 简洁的 API:提供清晰易用的文本和元数据提取接口。
  • 自动文档类型识别:自动判断文件类型并选用合适的解析方式。
  • 广泛的格式支持:覆盖绝大多数由 Apache Tika 支持的格式。
  • OCR 文字识别:通过集成 Tesseract,支持从图片和扫描文档中提取文字。
  • 多语言支持:核心使用 Rust,提供 Python 绑定,并计划支持 JavaScript/TypeScript。
  • 详细文档与示例:提供丰富的说明和代码示例,降低上手门槛。
  • 商业友好:采用 Apache 2.0 许可证,可免费用于商业项目。

如何开始使用?

Extractous 的安装和使用都非常简单。以下是一些基础示例,帮助你快速了解其用法。

Python 示例

首先,你需要安装 Extractous 的 Python 包:

pip install extractous

示例 1:将文件内容提取到字符串

from extractous import Extractor

# 初始化提取器
extractor = Extractor()
extractor = extractor.set_extract_string_max_length(1000)
# 如果需要输出为 XML 格式,可以取消下一行的注释
# extractor = extractor.set_xml_output(True)

# 从文件中提取文本和元数据
result, metadata = extractor.extract_file_to_string("README.md")
print(result)
print(metadata)

示例 2:流式提取文件内容

对于大文件,流式处理可以节省内存。

from extractous import Extractor

extractor = Extractor()
# 提取文件(也支持 URL 或字节数组)
reader, metadata = extractor.extract_file("tests/quarkus.pdf")
# 提取 URL
# reader, metadata = extractor.extract_url("https://www.google.com")
# 提取字节数组
# with open("tests/quarkus.pdf", "rb") as file:
#     buffer = bytearray(file.read())
# reader, metadata = extractor.extract_bytes(buffer)

result = ""
buffer = reader.read(4096)
while len(buffer) > 0:
    result += buffer.decode("utf-8")
    buffer = reader.read(4096)

print(result)
print(metadata)

示例 3:使用 OCR 提取PDF内容

需要先安装 Tesseract 及相应的语言包(以 Debian 为例):

sudo apt install tesseract-ocr tesseract-ocr-deu
from extractous import Extractor, TesseractOcrConfig

extractor = Extractor().set_ocr_config(TesseractOcrConfig().set_language("deu"))
result, metadata = extractor.extract_file_to_string("../../test_files/documents/eng-ocr.pdf")

print(result)
print(metadata)

Rust 示例

如果你更喜欢直接使用 Rust,可以在 Cargo.toml 中添加依赖:

[dependencies]
extractous = "0.1"

示例 1:将文件内容提取到字符串

use extractous::Extractor;

fn main() {
    // 初始化提取器(使用消费型建造器模式)
    let mut extractor = Extractor::new().set_extract_string_max_length(1000);
    // 如果需要输出为 XML 格式,可以取消下一行的注释
    // extractor = extractor.set_xml_output(true);

    // 提取文件内容
    let (text, metadata) = extractor.extract_file_to_string("README.md").unwrap();
    println!("{}", text);
    println!("{:?}", metadata);
}

示例 2:流式提取内容

use std::io::{BufReader, Read};
// use std::fs::File;  // 用于读取字节时使用
use extractous::Extractor;

fn main() {
    let args: Vec<String> = std::env::args().collect();
    let file_path = &args[1];

    let extractor = Extractor::new();
    let (stream, metadata) = extractor.extract_file(file_path).unwrap();
    // 提取 URL
    // let (stream, metadata) = extractor.extract_url("https://www.google.com/").unwrap();
    // 提取字节
    // let mut file = File::open(file_path)?;
    // let mut buffer = Vec::new();
    // file.read_to_end(&mut buffer)?;
    // let (stream, metadata) = extractor.extract_bytes(&file_bytes);

    // 由于 stream 实现了 std::io::Read,我们可以进行缓冲读取
    let mut reader = BufReader::new(stream);
    let mut buffer = Vec::new();
    reader.read_to_end(&mut buffer).unwrap();

    println!("{}", String::from_utf8(buffer).unwrap());
    println!("{:?}", metadata);
}

示例 3:使用 OCR 提取PDF内容

use extractous::Extractor;

fn main() {
  let file_path = "../test_files/documents/deu-ocr.pdf";

    let extractor = Extractor::new()
          .set_ocr_config(TesseractOcrConfig::new().set_language("deu"))
          .set_pdf_config(PdfParserConfig::new().set_ocr_strategy(PdfOcrStrategy::OCR_ONLY));
    // 使用配置提取文件
  let (content, metadata) = extractor.extract_file_to_string(file_path).unwrap();
  println!("{}", content);
  println!("{:?}", metadata);
}

性能表现:数字背后的真相

Extractous 在设计之初就将性能作为核心目标。那么,它的实际表现究竟如何?

通过针对 SEC10 filings PDF 文档集的测试,Extractous 展现出了显著优势:

  • 速度提升:平均比 unstructured-io 快 18 倍。这意味着原来需要一小时处理的任务,现在只需短短几分钟。
提取速度对比图
  • 内存效率:内存分配量比 unstructured-io 少 11 倍。大幅降低的内存需求使得 Extractous 能够在资源受限的环境中流畅运行,同时处理更多任务。
内存效率对比图
  • 输出质量:除了速度和效率,提取内容的准确性也同样重要。测试表明,Extractous 在内容提取质量方面也略有优势。
输出质量对比图

这些数据清楚地表明,Extractous 不仅在速度上占优,在资源利用率和输出质量方面同样表现出色。

支持的文件格式

Extractous 支持多种常见文档格式,以下是部分列表:

类别 支持格式 说明
Microsoft Office DOC, DOCX, PPT, PPTX, XLS, XLSX, RTF 包括旧版和现代 Office 格式
OpenOffice ODT, ODS, ODP OpenDocument 格式
PDF PDF 可提取嵌入内容并支持 OCR
电子表格 CSV, TSV 纯文本电子表格格式
网页文档 HTML, XML 解析并提取网页内容
电子书 EPUB 电子书格式
文本文件 TXT, Markdown 纯文本格式
图像 PNG, JPEG, TIFF, BMP, GIF, ICO, PSD, SVG 通过 OCR 提取嵌入文本
电子邮件 EML, MSG, MBOX, PST 提取内容、标题和附件

常见问题解答

问:Extractous 是如何实现高性能的?

答:Extractous 的核心采用 Rust 编写,充分利用了 Rust 的零成本抽象和内存安全特性。同时,它通过 GraalVM 将 Apache Tika 编译为本地库,避免了虚拟机开销,实现了真正的高效执行。

问:是否需要安装 Java 运行时环境(JRE)?

答:不需要。Extractous 通过 GraalVM 将 Apache Tika 编译为本地库,因此无需安装 Java 虚拟机或任何运行时环境。

问:Extractous 支持中文 OCR 吗?

答:支持。只要系统安装了相应语言(如中文)的 Tesseract 语言包,并通过 set_language 方法正确配置,Extractous 就可以处理中文OCR任务。

问:是否可以处理加密的 PDF 文件?

答:当前版本的 Extractous 主要专注于内容提取功能,对于加密PDF的支持可能需要根据具体情况进行测试或查阅最新文档。

问:如何参与贡献?

答:Extractous 是一个开源项目,欢迎社区贡献。你可以通过提交 Issue 或 Pull Request 的方式提出改进建议或新功能。

总结

Extractous 的出现为文档内容提取领域带来了新的选择。它通过创新的架构设计,实现了卓越的性能和效率,同时保持了简单易用的特性。无论是处理大量企业文档,还是集成到复杂的数据处理流程中,Extractous 都能提供可靠且高效的解决方案。

其开源特性意味着它可以被自由使用和修改,而详细的文档和示例则大大降低了学习和使用的门槛。如果你正在寻找一个能够快速、准确且高效提取文档内容的工具,Extractous 无疑值得你的关注和尝试。

项目源码和更多详细信息可以在 GitHub 上找到。