Skip to main content

多格式文档智能文本提取工具

Project description

Power-Doc

多格式文档智能文本提取工具

Power-Doc 是一个 Python 工具包与命令行工具,专注于从多种常见文档格式(图片、PDF、Word、HTML)中提取纯文本内容。它采用模块化架构设计,每个格式对应独立的提取引擎,支持按需安装依赖,并针对每种格式选择了业界最优的底层库,实现高精度的内容提取。


目录


功能特性

格式 扩展名 底层引擎 特点
图片 OCR .png, .jpg, .jpeg, .bmp, .tiff RapidOCR 轻量级 ONNX 推理,支持中英混合识别
PDF .pdf pymupdf4llm + PyMuPDF 保留 Markdown 格式,支持按页提取
Word 2007+ .docx docx2txt 直接读取 XML 内容,无格式残留
Word 97-2003 .doc doc2txt 兼容旧版二进制格式
HTML .html, .htm trafilatura + BeautifulSoup 智能正文提取 + 降级去噪方案
  • 模块化懒加载:未安装的依赖不会阻塞其他功能
  • 混合降级策略:HTML 模块优先用 trafilatura,失败时自动 fallback 到 BeautifulSoup
  • 链接保留:HTML 提取支持将超链接保留为 [文字](URL) 格式
  • 统一错误处理:所有模块使用一致的 FileNotFoundErrorImportError 语义

快速开始

安装

基础安装(仅 CLI 框架,无提取能力):

pip install power-doc

按需安装特定功能:

# 图片 OCR
pip install "power-doc[ocr]"

# PDF 提取
pip install "power-doc[pdf]"

# Word 文档
pip install "power-doc[doc]"

# HTML 解析
pip install "power-doc[html]"

一次性安装全部功能(开发推荐):

pip install "power-doc[all]"

命令行使用

安装后获得 power-doc 命令:

# 查看帮助
power-doc --help

# 图片 OCR 转文本
power-doc image2txt ./photo.png -o output.txt

# PDF 转文本
power-doc pdf2txt ./document.pdf -v

# DOCX 转文本
power-doc docx2txt ./report.docx -o report.txt

# 旧版 DOC 转文本
power-doc doc2txt ./legacy.doc -o legacy.txt

# HTML 智能提取(保留链接)
power-doc html2txt ./page.html -o page.txt --verbose

# HTML 提取(不保留链接)
power-doc html2txt ./page.html --no-links

Python API 使用

from power_doc import ImageOCR, PDFExtractor, DocxExtractor, DocExtractor, HtmlExtractor

# 图片 OCR
ocr = ImageOCR()
text = ocr.extract_text("./image.png")
results = ocr.extract_text_with_confidence("./image.png")  # [(text, confidence), ...]

# PDF 提取
text = PDFExtractor.extract_text("./document.pdf")
pages = PDFExtractor.extract_text_with_pages("./document.pdf")  # 按页列表

# DOCX / DOC
text = DocxExtractor.extract_text("./report.docx")
text = DocExtractor.extract_text("./legacy.doc")

# HTML 提取
text = HtmlExtractor.extract_text_from_file("./page.html", fallback=True, include_links=True)
text = HtmlExtractor.extract_text_from_string("<html>...</html>", include_links=False)

完整使用示例

场景一:批量图片 OCR 并过滤低置信度结果

from pathlib import Path
from power_doc import ImageOCR

ocr = ImageOCR()
image_dir = Path("./scanned_documents")

for img_path in image_dir.glob("*.png"):
    results = ocr.extract_text_with_confidence(img_path)
    # 过滤置信度低于 0.85 的识别结果
    high_confidence_lines = [
        text for text, conf in results if conf >= 0.85
    ]
    print(f"[{img_path.name}] 高置信度文本 ({len(high_confidence_lines)} 行):")
    print("\n".join(high_confidence_lines))
    print("-" * 40)

场景二:PDF 按页提取并生成页码索引

from pathlib import Path
from power_doc import PDFExtractor

pdf_path = Path("./research_paper.pdf")
pages = PDFExtractor.extract_text_with_pages(pdf_path)

# 生成带页码的索引文件
with open("paper_index.txt", "w", encoding="utf-8") as f:
    for page_num, page_text in enumerate(pages, start=1):
        word_count = len(page_text.split())
        f.write(f"\n=== 第 {page_num} 页 (约 {word_count} 词) ===\n")
        f.write(page_text[:500])  # 只写入前 500 字符作为预览
        f.write("\n")

print(f"共提取 {len(pages)} 页,索引已保存到 paper_index.txt")

场景三:HTML 网页正文提取并保留超链接

from pathlib import Path
from power_doc import HtmlExtractor

html_path = Path("./saved_page.html")

# 启用 fallback 和链接保留
result = HtmlExtractor.robust_html_to_txt(
    html_path.read_text(encoding="utf-8"),
    fallback=True,
    include_links=True,
)

text = result["text"]
links = result["links"]      # [(text, url), ...]
method = result["method"]    # "trafilatura" 或 "beautifulsoup"

print(f"提取方法: {method}")
print(f"正文长度: {len(text)} 字符")
print(f"发现链接: {len(links)} 个")
for link_text, url in links[:5]:
    print(f"  - [{link_text}]({url})")

# 保存纯文本
Path("article.txt").write_text(text, encoding="utf-8")

场景四:批量转换 Word 文档到文本

from pathlib import Path
from power_doc import DocxExtractor, DocExtractor

source_dir = Path("./word_files")
output_dir = Path("./text_output")
output_dir.mkdir(exist_ok=True)

for docx_path in source_dir.glob("*.docx"):
    text = DocxExtractor.extract_text(docx_path)
    out_path = output_dir / f"{docx_path.stem}.txt"
    out_path.write_text(text, encoding="utf-8")
    print(f"[DOCX] {docx_path.name} -> {out_path.name}")

for doc_path in source_dir.glob("*.doc"):
    text = DocExtractor.extract_text(doc_path)
    out_path = output_dir / f"{doc_path.stem}.txt"
    out_path.write_text(text, encoding="utf-8")
    print(f"[DOC]  {doc_path.name} -> {out_path.name}")

场景五:通用文档提取器(根据扩展名自动分发)

from pathlib import Path
from power_doc import (
    ImageOCR, PDFExtractor, DocxExtractor,
    DocExtractor, HtmlExtractor,
)

class UniversalExtractor:
    """根据文件扩展名自动选择对应提取器的通用封装."""

    _ocr = None

    @classmethod
    def _get_ocr(cls):
        if cls._ocr is None:
            cls._ocr = ImageOCR()
        return cls._ocr

    @classmethod
    def extract(cls, file_path: str | Path) -> str:
        path = Path(file_path)
        if not path.exists():
            raise FileNotFoundError(f"文件不存在: {path}")

        ext = path.suffix.lower()

        if ext in {".png", ".jpg", ".jpeg", ".bmp", ".tiff"}:
            return cls._get_ocr().extract_text(path)
        elif ext == ".pdf":
            return PDFExtractor.extract_text(path)
        elif ext == ".docx":
            return DocxExtractor.extract_text(path)
        elif ext == ".doc":
            return DocExtractor.extract_text(path)
        elif ext in {".html", ".htm"}:
            return HtmlExtractor.extract_text_from_file(path)
        else:
            raise ValueError(f"不支持的文件格式: {ext}")


# 使用示例
if __name__ == "__main__":
    files = ["report.pdf", "scan.jpg", "notes.docx", "article.html"]
    for f in files:
        try:
            text = UniversalExtractor.extract(f)
            print(f"[{f}] 提取成功,共 {len(text)} 字符")
        except Exception as e:
            print(f"[{f}] 提取失败: {e}")

项目架构

目录结构

power_doc/
├── __init__.py              # 包入口:导出所有提取器类与版本号
├── cli.py                   # Typer 命令行接口:5 个子命令 + 统一错误处理
└── core/                    # 核心提取引擎(每个格式独立模块)
    ├── __init__.py          # core 子包入口
    ├── image_ocr.py         # 图片 OCR(RapidOCR)
    ├── pdf_extractor.py     # PDF 提取(pymupdf4llm / fitz)
    ├── docx_extractor.py    # DOCX 提取(docx2txt)
    ├── doc_extractor.py     # DOC 提取(doc2txt)
    └── html_extractor.py    # HTML 提取(trafilatura + BeautifulSoup 混合方案)

tests/                       # pytest 测试套件(覆盖率 > 85%)
    ├── test_cli.py
    ├── test_image_ocr.py
    ├── test_pdf_extractor.py
    ├── test_docx_extractor.py
    ├── test_doc_extractor.py
    └── test_html_extractor.py

pyproject.toml               # 项目配置、依赖、构建脚本、pytest-cov 配置

核心模块详解

image_ocr.py — 图片 OCR 引擎

  • 底层库:RapidOCR(基于 ONNX Runtime)
  • 设计:实例化时加载模型,支持 extract_text(纯文本)与 extract_text_with_confidence(带置信度)
  • 懒加载:模块顶部 try/except 导入,未安装时在 __init__ 抛出明确 ImportError

pdf_extractor.py — PDF 提取引擎

  • 底层库pymupdf4llm(全文转 Markdown)、fitz(PyMuPDF,按页提取)
  • 设计:全静态方法类,无需实例化
  • 双模式
    • extract_text:返回完整 Markdown 格式文本
    • extract_text_with_pages:返回 List[str],每页一个元素

docx_extractor.py / doc_extractor.py — Word 文档引擎

  • 底层库docx2txt(DOCX)、doc2txt(DOC)
  • 设计:极简静态方法,直接调用第三方库的 process() 函数
  • 兼容性:DOCX 对应 Word 2007+(Office Open XML),DOC 对应 Word 97-2003(二进制)

html_extractor.py — HTML 智能提取引擎

  • 底层库trafilatura(正文提取)+ BeautifulSoup(降级去噪)
  • 混合策略
    1. 先用 trafilatura.extract() 提取正文;结果长度超过 100 字符则直接采用
    2. 若结果过短或失败,fallback 到 BeautifulSoup:移除 script/style/nav/footer/header/aside/noscript 黑名单标签,按 class 关键词过滤广告容器
    3. 完全失败时返回空字符串
  • 链接处理include_links=True 时将 <a> 标签替换为 [文字](URL),并收集到返回字典的 links 字段
  • 空白规范化:内部 _normalize_whitespace 方法通过多步正则压缩多余空格与换行

数据流向

用户输入(文件路径)
    │
    ▼
┌─────────────────┐     ┌─────────────────────────────┐
│   CLI (Typer)   │────▶│  命令分发到对应提取器模块   │
│   参数校验       │     │  image_ocr / pdf_extractor  │
│   -o / -v 处理   │     │  docx_extractor / ...       │
└─────────────────┘     └─────────────────────────────┘
    │                              │
    │                              ▼
    │                    ┌─────────────────┐
    │                    │  核心提取引擎    │
    │                    │  懒加载依赖检查  │
    │                    │  调用第三方库    │
    │                    └─────────────────┘
    │                              │
    ▼                              ▼
┌─────────────────┐     ┌─────────────────┐
│  结果输出到终端  │◀────│   纯文本结果     │
│  或写入文件      │     │  (可选链接列表)│
└─────────────────┘     └─────────────────┘

依赖与可选功能

功能组 依赖 extras 标识
图片 OCR rapidocr, onnxruntime [ocr]
PDF pymupdf4llm [pdf]
Word docx2txt, doc2txt [doc]
HTML trafilatura, beautifulsoup4, lxml [html]
开发 pytest, pytest-cov [dev]

基础依赖(必装):typer, rich


开发与测试

# 安装开发依赖
pip install -e ".[dev]"

# 运行测试
pytest

# 运行测试并查看覆盖率报告
pytest --cov=power_doc --cov-report=term-missing

# 构建并发布
python -m build
twine check dist/*
twine upload dist/*

扩展指南

新增提取器

以新增 Markdown 提取器为例:

  1. 新建模块:在 power_doc/core/ 下创建 markdown_extractor.py
  2. 编写类:实现静态方法 extract_text(md_path),遵循懒加载模式:
try:
    import markdown  # 或你的底层库
except ImportError:
    markdown = None  # type: ignore

class MarkdownExtractor:
    @staticmethod
    def extract_text(md_path):
        if markdown is None:
            raise ImportError("markdown 未安装...")
        # 提取逻辑...
  1. 导出类:在 power_doc/core/__init__.pypower_doc/__init__.py 中导入并加入 __all__
  2. 新增测试:在 tests/ 下创建 test_markdown_extractor.py

CLI 命令注册

power_doc/cli.py 中新增命令:

@app.command()
def md2txt(
    md_path: Path = typer.Argument(..., help="输入 Markdown 路径", exists=True),
    output: Optional[Path] = typer.Option(None, "--output", "-o", help="保存结果到文件"),
    verbose: bool = typer.Option(False, "--verbose", "-v", help="显示处理详情"),
) -> None:
    """Markdown 转纯文本."""
    try:
        if verbose:
            console.print(f"[blue]正在提取 Markdown: {md_path}[/blue]")
        text = MarkdownExtractor.extract_text(md_path)
        _print_result(text, output, verbose)
    except Exception as exc:
        _handle_error(str(exc))

无需额外注册,@app.command() 装饰器会自动将命令注册到 Typer 应用。


许可证

MIT License


免责声明

  1. 按原样提供:本软件按「原样」(AS IS)提供,不附带任何明示或暗示的担保,包括但不限于对适销性、特定用途适用性及非侵权性的担保。

  2. 责任限制:在任何情况下,作者或版权持有人均不对因使用本软件或无法使用本软件而导致的任何直接、间接、附带、特殊、惩戒性或后果性损害(包括但不限于数据丢失、业务中断或利润损失)承担责任,无论该等损害基于合同、侵权(包括过失)或其他任何责任理论,即使已被告知存在该等损害的可能性。

  3. 用户责任:用户在使用本软件前应自行评估相关风险,并确保其使用行为符合所在地的法律法规。对于因用户违反当地法律或不当使用本软件而产生的任何后果,由用户自行承担全部责任。

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

power_doc-0.1.0.tar.gz (20.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

power_doc-0.1.0-py3-none-any.whl (14.7 kB view details)

Uploaded Python 3

File details

Details for the file power_doc-0.1.0.tar.gz.

File metadata

  • Download URL: power_doc-0.1.0.tar.gz
  • Upload date:
  • Size: 20.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.3

File hashes

Hashes for power_doc-0.1.0.tar.gz
Algorithm Hash digest
SHA256 992e5d8362873e6a09e2d993db28eaae5d4885babc884b598bf11f2721b638f9
MD5 8659bdc7b8409ef74255187a8598a779
BLAKE2b-256 bce3ab5fd7fce0b6c0143cfe2f5b1f2aa3b621add39e870bebb0b9461881e31b

See more details on using hashes here.

File details

Details for the file power_doc-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: power_doc-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 14.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.3

File hashes

Hashes for power_doc-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 7d29841b77d126933e5697916b2cc409ba7b10aaaff3252491835a47b9d9edec
MD5 73e8a81c73a5bde4875ad9b13ffbb3c8
BLAKE2b-256 bf05b4b7e2c1d43f95e43b4d2e74edc3a4df20de20aeb4ae070ef250683fe2a8

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page