pdf-to-docx

pdf-to-docx

热门

使用 pdf2docx 将 PDF 文件转换为可编辑的 Word 文档

310Star
68Fork
更新于 2026/1/31
SKILL.md
readonly只读
name
pdf-to-docx
description

使用 pdf2docx 将 PDF 文件转换为可编辑的 Word 文档

version
1.0

PDF 转 Word 技能

概述

本技能支持使用 pdf2docx 将 PDF 转换为可编辑的 Word 文档。pdf2docx 是一个 Python 库,能够保留布局、表格、图像和文本格式。与基于 OCR 的解决方案不同,pdf2docx 提取原生 PDF 内容以实现准确转换。

使用方法

  1. 提供要转换的 PDF 文件
  2. 可选地指定页面或转换选项
  3. 我将把它转换为可编辑的 Word 文档

示例提示:

  • "将此 PDF 报告转换为可编辑的 Word 文档"
  • "将此 PDF 的第 1-5 页转换为 Word 格式"
  • "提取此扫描文档为可编辑文本"
  • "将此 PDF 合同转换为 Word 以便编辑"

领域知识

pdf2docx 基础

from pdf2docx import Converter

# 基本转换
cv = Converter('input.pdf')
cv.convert('output.docx')
cv.close()

# 或使用上下文管理器
with Converter('input.pdf') as cv:
    cv.convert('output.docx')

转换选项

from pdf2docx import Converter

cv = Converter('input.pdf')

# 完整文档
cv.convert('output.docx')

# 指定页面(从 0 开始索引)
cv.convert('output.docx', start=0, end=5)

# 单页
cv.convert('output.docx', pages=[0])

# 多个指定页面
cv.convert('output.docx', pages=[0, 2, 4])

cv.close()

高级选项

from pdf2docx import Converter

cv = Converter('input.pdf')

cv.convert(
    'output.docx',
    start=0,                    # 起始页(从 0 开始索引)
    end=None,                   # 结束页(None 表示最后一页)
    pages=None,                 # 指定页面列表
    password=None,              # PDF 密码(如果加密)
    min_section_height=20.0,    # 章节最小高度
    connected_border_tolerance=0.5,  # 边框检测容差
    line_overlap_threshold=0.9, # 线条合并阈值
    line_break_width_ratio=0.5, # 换行检测
    line_break_free_space_ratio=0.1,
    line_separate_threshold=5,  # 垂直线分离
    new_paragraph_free_space_ratio=0.85,
    float_image_ignorable_gap=5,
    page_margin_factor_top=0.5,
    page_margin_factor_bottom=0.5,
)

cv.close()

处理不同类型的 PDF

原生 PDF(基于文本)
# 对原生 PDF 效果最佳
cv = Converter('native_pdf.pdf')
cv.convert('output.docx')
cv.close()
扫描 PDF(基于图像)
# 对于扫描 PDF,先使用 OCR
# pdf2docx 对原生文本 PDF 效果最好
# 考虑先使用 pytesseract 或 PaddleOCR

import pytesseract
from pdf2image import convert_from_path

# 将 PDF 页面转换为图像
images = convert_from_path('scanned.pdf')

# 对每页进行 OCR
text = ''
for img in images:
    text += pytesseract.image_to_string(img)

# 然后从文本创建 Word 文档

Python 集成

from pdf2docx import Converter
import os

def pdf_to_word(pdf_path, output_path=None, pages=None):
    """将 PDF 转换为 Word 文档。"""
    if output_path is None:
        output_path = pdf_path.replace('.pdf', '.docx')
    
    cv = Converter(pdf_path)
    
    if pages:
        cv.convert(output_path, pages=pages)
    else:
        cv.convert(output_path)
    
    cv.close()
    
    return output_path

# 使用示例
result = pdf_to_word('document.pdf')
print(f"已创建: {result}")

批量转换

from pdf2docx import Converter
from pathlib import Path
from concurrent.futures import ThreadPoolExecutor

def convert_single(pdf_path, output_dir):
    """将单个 PDF 转换为 Word。"""
    output_path = output_dir / pdf_path.with_suffix('.docx').name
    
    try:
        cv = Converter(str(pdf_path))
        cv.convert(str(output_path))
        cv.close()
        return f"成功: {pdf_path.name}"
    except Exception as e:
        return f"错误: {pdf_path.name} - {e}"

def batch_convert(input_dir, output_dir, max_workers=4):
    """转换目录中的所有 PDF。"""
    input_path = Path(input_dir)
    output_path = Path(output_dir)
    output_path.mkdir(exist_ok=True)
    
    pdf_files = list(input_path.glob('*.pdf'))
    
    with ThreadPoolExecutor(max_workers=max_workers) as executor:
        futures = [
            executor.submit(convert_single, pdf, output_path)
            for pdf in pdf_files
        ]
        
        for future in futures:
            print(future.result())

batch_convert('./pdfs', './word_docs')

解析 PDF 结构

from pdf2docx import Converter

def analyze_pdf(pdf_path):
    """在转换前分析 PDF 结构。"""
    cv = Converter(pdf_path)
    
    for i, page in enumerate(cv.pages):
        print(f"第 {i+1} 页:")
        print(f"  尺寸: {page.width} x {page.height}")
        print(f"  块数: {len(page.blocks)}")
        
        for block in page.blocks:
            if hasattr(block, 'text'):
                print(f"    文本块: {block.text[:50]}...")
            elif hasattr(block, 'image'):
                print(f"    图像块")
    
    cv.close()

analyze_pdf('document.pdf')

最佳实践

  1. 检查 PDF 类型:原生 PDF 转换效果优于扫描件
  2. 先预览:在完整转换前先用几页测试
  3. 处理表格:复杂表格可能需要手动调整
  4. 图像质量:图像以原始分辨率提取
  5. 字体处理:某些字体可能被替换为系统默认字体

常见模式

带进度转换

from pdf2docx import Converter

def convert_with_progress(pdf_path, output_path):
    """带进度跟踪的 PDF 转换。"""
    cv = Converter(pdf_path)
    
    total_pages = len(cv.pages)
    print(f"正在转换 {total_pages} 页...")
    
    for i in range(total_pages):
        cv.convert(output_path, start=i, end=i+1)
        progress = (i + 1) / total_pages * 100
        print(f"进度: {progress:.1f}%")
    
    cv.close()
    print("转换完成!")

仅提取表格

from pdf2docx import Converter
from docx import Document

def extract_tables_to_word(pdf_path, output_path):
    """仅从 PDF 提取表格到 Word。"""
    cv = Converter(pdf_path)
    
    # 先进行完整转换
    temp_path = 'temp_full.docx'
    cv.convert(temp_path)
    cv.close()
    
    # 打开并提取表格
    doc = Document(temp_path)
    new_doc = Document()
    
    for table in doc.tables:
        # 复制表格到新文档
        new_table = new_doc.add_table(rows=0, cols=len(table.columns))
        
        for row in table.rows:
            new_row = new_table.add_row()
            for i, cell in enumerate(row.cells):
                new_row.cells[i].text = cell.text
        
        new_doc.add_paragraph()  # 添加间距
    
    new_doc.save(output_path)
    os.remove(temp_path)

示例

示例 1:合同转换

from pdf2docx import Converter
import os

def convert_contract(pdf_path):
    """将合同 PDF 转换为可编辑的 Word 并保留元数据。"""
    
    # 定义输出路径
    base_name = os.path.splitext(pdf_path)[0]
    output_path = f"{base_name}_editable.docx"
    
    # 转换
    cv = Converter(pdf_path)
    
    # 检查页数
    page_count = len(cv.pages)
    print(f"正在处理 {page_count} 页...")
    
    # 转换所有页面
    cv.convert(output_path)
    cv.close()
    
    print(f"已创建: {output_path}")
    print(f"文件大小: {os.path.getsize(output_path) / 1024:.1f} KB")
    
    return output_path

# 使用示例
result = convert_contract('contract.pdf')

示例 2:选择性页面转换

from pdf2docx import Converter

def convert_selected_pages(pdf_path, page_ranges, output_path):
    """将指定页面范围转换为 Word。
    
    page_ranges: 元组列表,如 [(1, 3), (5, 7)] 表示第 1-3 页和第 5-7 页
    """
    cv = Converter(pdf_path)
    
    # 内部转换为从 0 开始索引
    all_pages = []
    for start, end in page_ranges:
        all_pages.extend(range(start - 1, end))
    
    cv.convert(output_path, pages=all_pages)
    cv.close()
    
    print(f"已转换页面: {page_ranges}")
    return output_path

# 转换第 1-5 页和第 10-15 页
convert_selected_pages(
    'long_document.pdf',
    [(1, 5), (10, 15)],
    'selected_pages.docx'
)

示例 3:PDF 报告转可编辑模板

from pdf2docx import Converter
from docx import Document

def pdf_to_template(pdf_path, output_path):
    """将 PDF 报告转换为带占位符的 Word 模板。"""
    
    # 将 PDF 转换为 Word
    cv = Converter(pdf_path)
    cv.convert(output_path)
    cv.close()
    
    # 打开并添加占位符字段
    doc = Document(output_path)
    
    # 将常见字段替换为占位符
    replacements = {
        'Company Name': '[COMPANY_NAME]',
        'Date:': 'Date: [DATE]',
        'Prepared by:': 'Prepared by: [AUTHOR]',
    }
    
    for para in doc.paragraphs:
        for old, new in replacements.items():
            if old in para.text:
                para.text = para.text.replace(old, new)
    
    # 同时检查表格
    for table in doc.tables:
        for row in table.rows:
            for cell in row.cells:
                for old, new in replacements.items():
                    if old in cell.text:
                        cell.text = cell.text.replace(old, new)
    
    doc.save(output_path)
    print(f"模板已创建: {output_path}")

pdf_to_template('annual_report.pdf', 'report_template.docx')

示例 4:批量发票处理

from pdf2docx import Converter
from pathlib import Path
import json

def process_invoices(input_folder, output_folder):
    """将 PDF 发票转换为可编辑的 Word 文档。"""
    
    input_path = Path(input_folder)
    output_path = Path(output_folder)
    output_path.mkdir(exist_ok=True)
    
    results = []
    
    for pdf_file in input_path.glob('*.pdf'):
        output_file = output_path / pdf_file.with_suffix('.docx').name
        
        try:
            cv = Converter(str(pdf_file))
            cv.convert(str(output_file))
            cv.close()
            
            results.append({
                'file': pdf_file.name,
                'status': 'success',
                'output': str(output_file)
            })
            
        except Exception as e:
            results.append({
                'file': pdf_file.name,
                'status': 'error',
                'error': str(e)
            })
    
    # 保存结果日志
    with open(output_path / 'conversion_log.json', 'w') as f:
        json.dump(results, f, indent=2)
    
    # 摘要
    success = sum(1 for r in results if r['status'] == 'success')
    print(f"已转换 {success}/{len(results)} 个文件")
    
    return results

results = process_invoices('./invoices_pdf', './invoices_word')

局限性

  • 扫描 PDF 需要 OCR 预处理
  • 复杂布局可能无法完美转换
  • 某些字体可能不可用
  • 水印会包含在转换中
  • 受保护/加密的 PDF 需要密码

安装

pip install pdf2docx

# 用于图像处理
pip install Pillow

资源