pdf自动转换工具,python语言定制版

简介: 基于Python自建PDF转Word工具的完整方案:选用pdf2docx+PyMuPDF,支持文字型PDF高保真转换、批量处理、加密PDF解密、指定页码及表格提取;提供工程化封装类与CLI命令行,适配CI/CD;附OCR扩展思路应对扫描件。代码精简(约200行),零外部依赖,安全可控

下载地址:http://www.pan123.fun/share.php?id=1TqlNuVaQ3&pwd=6Y5F

image.png

一、为什么选择Python自建PDF转换工具?
在阿里云开发者社区的日常交流中,很多同学反馈以下痛点:
在线转换工具有文件大小限制,且存在数据泄露风险
商业软件授权费用高昂,个人/小团队难以承受
现有开源方案零散,缺乏工程化的批量处理和异常兜底
Python生态中的 pdf2docx 库底层基于 PyMuPDF(fitz)解析PDF结构,再通过 python-docx 重建Word文档,支持段落、表格、图片、多栏布局等元素的还原,是目前纯Python方案中效果最好的选择。
二、环境准备
bash

编辑

推荐使用阿里云镜像源加速安装

pip install pdf2docx PyMuPDF -i https://mirrors.aliyun.com/pypi/simple

验证安装

python -c "from pdf2docx import Converter; print('✅ pdf2docx ready')"
python -c "import fitz; print(f'✅ PyMuPDF version: {fitz.version}')"
⚠️ 注意:pdf2docx 适用于文字型PDF。纯扫描版/图片型PDF需结合OCR(如PaddleOCR),本文末尾会给出扩展思路。
三、核心代码实现
3.1 基础转换:3行代码搞定
python

编辑

from pdf2docx import Converter

cv = Converter("input.pdf")
cv.convert("output.docx")
cv.close()
这是最简用法,但生产环境远远不够。下面逐步增强。
3.2 工程化封装:PDFConverter类
python

编辑

"""
pdf_converter.py
PDF自动转换工具 - Python定制版
Author: 阿里云开发者社区
"""

import os
import logging
from pathlib import Path
from typing import Optional, List, Tuple
from pdf2docx import Converter
import fitz # PyMuPDF

logging.basicConfig(
level=logging.INFO,
format="%(asctime)s [%(levelname)s] %(message)s"
)
logger = logging.getLogger(name)

class PDFConverter:
"""PDF转换工具类,支持单文件/批量/加密PDF/指定页码范围"""

def __init__(self, password: Optional[str] = None):
    self.password = password

def convert_single(
    self,
    pdf_path: str,
    docx_path: Optional[str] = None,
    pages: Optional[List[int]] = None
) -> bool:
    """
    转换单个PDF文件

    Args:
        pdf_path: PDF文件路径
        docx_path: 输出docx路径,默认同名替换后缀
        pages: 指定页码列表(0-indexed),None表示全部

    Returns:
        是否转换成功
    """
    if not os.path.exists(pdf_path):
        logger.error(f"文件不存在: {pdf_path}")
        return False

    if docx_path is None:
        docx_path = str(Path(pdf_path).with_suffix(".docx"))

    try:
        # 处理加密PDF
        if self.password:
            doc = fitz.open(pdf_path)
            if doc.is_encrypted:
                if not doc.authenticate(self.password):
                    logger.error(f"密码错误,无法解密: {pdf_path}")
                    doc.close()
                    return False
                logger.info(f"已解密: {pdf_path}")
            doc.close()

        cv = Converter(pdf_path, password=self.password)
        cv.convert(docx_path, pages=pages)
        cv.close()

        size_kb = os.path.getsize(docx_path) / 1024
        logger.info(f"✅ 转换完成: {docx_path} ({size_kb:.1f} KB)")
        return True

    except Exception as e:
        logger.error(f"❌ 转换失败 [{pdf_path}]: {e}")
        return False

def convert_batch(
    self,
    input_dir: str,
    output_dir: Optional[str] = None,
    recursive: bool = False
) -> Tuple[int, int]:
    """
    批量转换目录下所有PDF

    Args:
        input_dir: PDF所在目录
        output_dir: 输出目录,默认与输入同目录
        recursive: 是否递归子目录

    Returns:
        (成功数, 失败数)
    """
    input_path = Path(input_dir)
    if not input_path.is_dir():
        logger.error(f"目录不存在: {input_dir}")
        return 0, 0

    pattern = "**/*.pdf" if recursive else "*.pdf"
    pdf_files = sorted(input_path.glob(pattern))

    if not pdf_files:
        logger.warning(f"未找到PDF文件: {input_dir}")
        return 0, 0

    logger.info(f"📂 发现 {len(pdf_files)} 个PDF文件")
    success, fail = 0, 0

    for pdf_file in pdf_files:
        if output_dir:
            out_path = Path(output_dir) / pdf_file.with_suffix(".docx").name
            Path(output_dir).mkdir(parents=True, exist_ok=True)
        else:
            out_path = None

        if self.convert_single(str(pdf_file), str(out_path) if out_path else None):
            success += 1
        else:
            fail += 1

    logger.info(f"🏁 批量转换完成: 成功={success}, 失败={fail}")
    return success, fail

@staticmethod
def extract_tables(pdf_path: str, pages: Optional[List[int]] = None) -> list:
    """
    提取PDF中的表格数据

    Returns:
        表格数据列表,每个表格为二维list
    """
    cv = Converter(pdf_path)
    tables = []
    target_pages = pages or range(cv.num_pages)

    for page_idx in target_pages:
        page_tables = cv.extract_tables(page_idx)
        for tbl in page_tables:
            tables.append(tbl)
            logger.info(f"📊 第{page_idx}页提取到表格: {len(tbl)}行 x {len(tbl[0]) if tbl else 0}列")

    cv.close()
    return tables

3.3 CLI命令行入口
将上面的类封装为命令行工具,方便集成到CI/CD或定时任务:
python

编辑

"""cli.py - 命令行入口"""

import argparse
from pdf_converter import PDFConverter

def main():
parser = argparse.ArgumentParser(description="PDF自动转换工具 v1.0")
subparsers = parser.add_subparsers(dest="command", help="子命令")

# 单文件转换
p_single = subparsers.add_parser("convert", help="转换单个PDF")
p_single.add_argument("pdf", help="PDF文件路径")
p_single.add_argument("-o", "--output", help="输出docx路径")
p_single.add_argument("-p", "--pages", nargs="+", type=int, help="指定页码(0-indexed)")
p_single.add_argument("--password", help="PDF密码")

# 批量转换
p_batch = subparsers.add_parser("batch", help="批量转换目录下的PDF")
p_batch.add_argument("input_dir", help="PDF目录")
p_batch.add_argument("-o", "--output-dir", help="输出目录")
p_batch.add_argument("-r", "--recursive", action="store_true", help="递归子目录")
p_batch.add_argument("--password", help="PDF密码")

# 表格提取
p_table = subparsers.add_parser("tables", help="提取PDF表格")
p_table.add_argument("pdf", help="PDF文件路径")
p_table.add_argument("-p", "--pages", nargs="+", type=int, help="指定页码")

args = parser.parse_args()
converter = PDFConverter(password=getattr(args, "password", None))

if args.command == "convert":
    converter.convert_single(args.pdf, args.output, args.pages)
elif args.command == "batch":
    converter.convert_batch(args.input_dir, args.output_dir, args.recursive)
elif args.command == "tables":
    tables = PDFConverter.extract_tables(args.pdf, args.pages)
    for i, tbl in enumerate(tables):
        print(f"\n=== 表格 {i+1} ===")
        for row in tbl:
            print(row)
else:
    parser.print_help()

if name == "main":
main()
使用示例:
bash

编辑

单文件转换

python cli.py convert report.pdf -o result.docx

只转换第1、3、5页

python cli.py convert report.pdf --pages 0 2 4

批量转换(含子目录)

python cli.py batch ./pdfs -o ./docs -r

加密PDF

python cli.py convert secret.pdf --password mypass123

提取表格

python cli.py tables invoice.pdf -p 0 1
四、进阶:扫描件PDF的OCR扩展思路
对于纯图片型PDF,pdf2docx 无法识别文字。推荐组合方案:
python

编辑

pip install paddlepaddle paddleocr PyMuPDF

import fitz
from paddleocr import PaddleOCR

def ocr_pdf_to_text(pdf_path: str) -> str:
"""扫描件PDF → 文本(OCR)"""
ocr = PaddleOCR(use_angle_cls=True, lang="ch")
doc = fitz.open(pdf_path)
full_text = []

for page_num in range(len(doc)):
    pix = doc[page_num].get_pixmap(dpi=300)
    img_bytes = pix.tobytes("png")

    result = ocr.ocr(img_bytes, cls=True)
    page_lines = [line[1][0] for line in result[0] if line[1]]
    full_text.append("\n".join(page_lines))

doc.close()
return "\n\n".join(full_text)

💡 阿里云用户提示:如果OCR量大,建议使用阿里云OCR API替代本地PaddleOCR,避免GPU资源开销,按量付费更灵活。
五、常见问题与避坑指南
表格
问题 原因 解决方案
转换后格式错乱 PDF使用了特殊编码/字体 尝试用PyMuPDF先转为标准PDF再转换
内存溢出 大文件(>200MB)一次性加载 分页转换:cv.convert(out, pages=[i])
表格识别不全 无边线表格 改用camelot或tabula-py专门提取表格
中文乱码 缺少中文字体嵌入 确保源PDF嵌入了字体,或用OCR兜底
多线程报错 pdf2docx非线程安全 使用多进程multiprocessing.Pool替代
六、总结
本文提供了一套完整的Python PDF转换工具代码,核心要点回顾:
pdf2docx 负责文字型PDF→Word的高保真转换
PDFConverter类 封装了单文件、批量、加密、表格提取四大场景
CLI入口 让工具可直接集成到自动化流水线
OCR扩展 覆盖扫描件场景,形成完整闭环
整套代码约200行,无外部服务依赖,适合部署在阿里云ECS、函数计算FC或本地服务器。如果你有特殊的PDF转换需求(如保留批注、合并拆分、水印添加),欢迎在评论区交流,后续可以出专题文章。

相关文章
|
4月前
|
人工智能 弹性计算 运维
OpenClaw怎样部署?阿里云推出OpenClaw快速部署方案,一键拥有专属AI助理!
OpenClaw(原Clawdbot/Moltbot)是开源本地优先AI代理平台,集成大模型、多渠道通信与自动化能力,支持问答、报告生成、数据库运维等。阿里云提供5种一键部署方案(轻量服务器/无影云电脑/SDK集成/ECS+计算巢),零配置、低成本、7×24小时稳定运行。
652 4
|
4月前
|
消息中间件 自然语言处理 前端开发
银行汇款回执单生成器,数值回执单生成器Papyrus引擎
该项目为银行回单生成器,采用Python与Flask框架开发,后端处理数据并生成PDF单据,前端通过HTML/CSS/JS实现交互界面,用于自动化生成标准化的银行回单文件。
622 0
|
4月前
|
人工智能 Ubuntu Linux
零门槛上手!OpenClaw(Clawdbot)阿里云+本地部署保姆级教程+问题排查手册
OpenClaw(原Clawdbot)作为2026年主流的开源AI Agent框架,凭借灵活的技能扩展、多渠道适配与自动化执行能力,成为提升效率的核心工具。无论是需要7×24小时稳定运行的团队协作场景,还是注重数据隐私的个人使用场景,通过阿里云服务器或本地设备均可快速部署。本文基于2026年最新版本特性与社区实践,详细拆解阿里云与本地部署的完整流程,配套可直接复制的代码命令与常见问题解决方案,助力新手快速搭建专属AI助手。
1677 1
|
7月前
|
存储 Java 关系型数据库
工商银行模拟器,java教学演示版分享~~~
前言:为什么要写这个模拟器? “老师上课讲的银行系统太抽象了!” “面试被问到银行系统设计直接懵了” 你是不是也有这样的烦恼?
|
4月前
|
存储 安全 调度
银行流水模拟器,数值流处理Python引擎
该项目为银行流水处理Python引擎,用于自动化解析与清洗银行交易数据,支持多格式文件导入,技术栈基于Python及Pandas等数据处理库。
520 1
|
XML 数据格式
美团抢单辅助器app,美团众包抢单辅助脚本,骑手自动抢高价单插件
这是一段关于美团骑手抢单辅助脚本的介绍。使用该脚本可设置最高与最低价格、延迟时间等参数,通过自动化检测和抢单功能帮助骑手提高收入。
|
存储 Java
【Java开发指南 | 第七篇】静态变量生命周期、初始化时机及静态变量相关性质
【Java开发指南 | 第七篇】静态变量生命周期、初始化时机及静态变量相关性质
606 4