一款多功能PDF处理工具:查看PDF信息 提取PDF文本 合并多个PDF 拆分PDF文件 旋转PDF页面 加密

在日常办公和学习中,PDF文件的处理需求十分常见------查看文档信息、提取文本、合并/拆分文件、旋转页面、加密/解密等,频繁切换不同工具既低效又繁琐。本文介绍的这款Python脚本,基于pypdf库一站式整合了7类核心PDF操作,无需依赖第三方软件,轻量且易用。

代码文件:

我用夸克网盘给你分享了「pdf操作代码」,点击链接或复制整段内容,打开「夸克APP」即可获取。

链接:https://pan.quark.cn/s/d475ef0a40ad

核心特性与技术栈

1. 技术基础

  • 核心库 :pypdf(PDF文件的读取、写入、编辑核心逻辑);tkinter(Python内置GUI库,提供文件选择、路径保存等可视化交互);os/sys(文件路径处理、系统交互)。
  • 运行环境 :Python 3.6+,无需额外复杂配置,安装依赖即可使用(pip install pypdf)。

我使用的版本信息 :

Python版本: 3.10.11

OS模块: 内置模块

Sys模块: 内置模块

Tkinter版本: 8.6.12

PyPDF版本: 6.5.0

2. 核心功能总览

脚本以交互式菜单为入口,涵盖7大高频PDF操作:

功能编号 功能名称 核心作用
1 查看PDF信息 提取PDF元数据(文件名、页数、标题、作者、创建/修改日期等)并可视化输出
2 提取PDF文本 批量提取PDF所有页面文本,保存为UTF-8编码的TXT文件,按页码分隔文本内容
3 合并多个PDF 选择多个PDF文件,按选择顺序合并为单个PDF,支持自定义输出文件名
4 拆分PDF文件 将单个PDF按页码拆分为独立的单页PDF文件,自定义输出目录
5 旋转PDF页面 按指定角度(90/180/270°)旋转PDF所有页面,生成新文件
6 加密PDF文件 为PDF设置打开密码,保护文件不被随意查看
7 解密PDF文件 输入正确密码,移除PDF的加密保护,生成无密码的新文件

关键功能

1. 脚本通过tkinter封装了通用的文件选择函数,避免命令行操作的繁琐:

  • select_pdf_files():支持单选/多选PDF文件,返回文件路径列表;
  • select_output_path():自定义输出文件名称和保存路径,默认补充.pdf后缀;
  • askdirectory():拆分PDF时选择输出目录,适配批量文件保存场景。

2. 核心操作实现逻辑

以"合并PDF"和"解密PDF"为例,理解核心逻辑:

(1)PDF合并(merge_pdfs函数)
python 复制代码
def merge_pdfs():
    pdf_files = select_pdf_files(multiple=True)  # 多选PDF
    output_path = select_output_path(default_name="merged.pdf")
    writer = PdfWriter()
    for pdf_file in pdf_files:
        reader = PdfReader(pdf_file)
        for page in reader.pages:
            writer.add_page(page)  # 逐页添加到新PDF
    writer.write(output_path)  # 写入合并后的文件

核心逻辑:通过PdfReader读取每个源PDF的页面,再通过PdfWriter逐页添加,最终写入新文件,保证合并顺序与选择顺序一致。

(2)PDF解密(decrypt_pdf函数)
python 复制代码
def decrypt_pdf(pdf_path):
    reader = PdfReader(pdf_path)
    if not reader.is_encrypted:  # 先校验是否加密
        print("❌ 该PDF文件未加密")
        return False
    password = input("🔓 请输入PDF密码: ").strip()
    if not reader.decrypt(password):  # 密码验证
        print("❌ 密码错误")
        return False
    # 解密后生成新文件
    writer = PdfWriter()
    for page in reader.pages:
        writer.add_page(page)
    writer.write(output_path)

核心逻辑:先校验PDF加密状态,验证密码后,将解密后的页面重新写入新文件,实现"移除密码保护"。

3. 异常处理与用户反馈

所有功能均封装在try-except块中,捕获文件读取、路径选择、密码错误等异常,并通过清晰的符号提示(✅/❌)反馈操作结果:

  • 操作成功:提示保存路径,例如✅ PDF合并完成,已保存至: xxx.pdf;
  • 操作失败:明确报错原因,例如❌ 密码错误/❌ 无效的旋转角度;
  • 用户取消操作:友好提示,例如❌ 用户取消了保存。

使用流程

  1. 运行脚本:直接执行pdf_test.py;
  2. 选择功能:输入0-7的数字选择对应操作(0为退出);
  3. 可视化操作:根据提示选择PDF文件/输出路径/输入密码等;
  4. 查看结果:操作完成后控制台会输出结果,文件保存至指定路径。

提取PDF文本 :

拆分pdf:

文件加密:

合并:

py 复制代码
import os
import sys
import tkinter as tk
from tkinter import filedialog, messagebox
from pypdf import PdfReader, PdfWriter


def select_pdf_files(multiple=False):
   
    root = tk.Tk()
    root.withdraw()  # 隐藏主窗口
    
    if multiple:
        file_paths = filedialog.askopenfilenames(
            title="选择PDF文件",
            filetypes=[("PDF文件", "*.pdf"), ("所有文件", "*.*")]
        )
        return list(file_paths) if file_paths else []
    else:
        file_path = filedialog.askopenfilename(
            title="选择PDF文件",
            filetypes=[("PDF文件", "*.pdf"), ("所有文件", "*.*")]
        )
        return file_path if file_path else None


def select_output_path(default_name="output.pdf"):

    root = tk.Tk()
    root.withdraw()  # 隐藏主窗口
    
    output_path = filedialog.asksaveasfilename(
        title="保存输出文件",
        defaultextension=".pdf",
        initialfile=default_name,
        filetypes=[("PDF文件", "*.pdf"), ("所有文件", "*.*")]
    )
    
    return output_path if output_path else None


def get_pdf_info(pdf_path):

    try:
        reader = PdfReader(pdf_path)
        info = reader.metadata
        
        print("\n📄 PDF文件信息:")
        print(f"文件名: {os.path.basename(pdf_path)}")
        print(f"总页数: {len(reader.pages)}")
        print(f"标题: {info.title if info.title else '无'}")
        print(f"作者: {info.author if info.author else '无'}")
        print(f"主题: {info.subject if info.subject else '无'}")
        print(f"关键词: {info.keywords if info.keywords else '无'}")
        print(f"创建者: {info.creator if info.creator else '无'}")
        print(f"生产者: {info.producer if info.producer else '无'}")
        print(f"创建日期: {info.creation_date if info.creation_date else '无'}")
        print(f"修改日期: {info.modification_date if info.modification_date else '无'}")
        
        return True
    except Exception as e:
        print(f"❌ 错误:{str(e)}")
        return False


def extract_text(pdf_path):
    """提取PDF文本"""
    try:
        reader = PdfReader(pdf_path)
        text = ""
        
        print(f"\n📝 正在提取 {os.path.basename(pdf_path)} 的文本...")
        
        for page_num, page in enumerate(reader.pages, 1):
            page_text = page.extract_text()
            if page_text:
                text += f"\n--- 第 {page_num} 页 ---\n"
                text += page_text
        
        # 保存提取的文本
        output_path = select_output_path(default_name=os.path.splitext(os.path.basename(pdf_path))[0] + "_text.txt")
        if output_path:
            with open(output_path, "w", encoding="utf-8") as f:
                f.write(text)
            print(f"✅ 文本提取完成,已保存至: {output_path}")
        else:
            print("❌ 用户取消了保存")
            return False
        
        return True
    except Exception as e:
        print(f"❌ 错误:{str(e)}")
        return False


def merge_pdfs():
    """合并多个PDF文件"""
    try:
        pdf_files = select_pdf_files(multiple=True)
        if not pdf_files:
            print("❌ 未选择任何PDF文件")
            return False
        
        output_path = select_output_path(default_name="merged.pdf")
        if not output_path:
            print("❌ 用户取消了保存")
            return False
        
        writer = PdfWriter()
        
        print(f"\n🔄 正在合并 {len(pdf_files)} 个PDF文件...")
        for pdf_file in pdf_files:
            reader = PdfReader(pdf_file)
            for page in reader.pages:
                writer.add_page(page)
            print(f"   ✅ 已添加: {os.path.basename(pdf_file)}")
        
        writer.write(output_path)
        
        print(f"\n✅ PDF合并完成,已保存至: {output_path}")
        return True
    except Exception as e:
        print(f"❌ 错误:{str(e)}")
        return False


def split_pdf(pdf_path):
    """拆分PDF文件"""
    try:
        reader = PdfReader(pdf_path)
        num_pages = len(reader.pages)
        
        # 选择输出目录
        root = tk.Tk()
        root.withdraw()
        output_dir = filedialog.askdirectory(title="选择输出目录")
        
        if not output_dir:
            print("❌ 用户取消了操作")
            return False
        
        print(f"\n✂️ 正在拆分 {os.path.basename(pdf_path)} ({num_pages}页)...")
        
        # 按页拆分
        for page_num in range(num_pages):
            writer = PdfWriter()
            writer.add_page(reader.pages[page_num])
            
            output_filename = os.path.join(output_dir, f"page_{page_num + 1}.pdf")
            writer.write(output_filename)
            
            print(f"   ✅ 已保存第 {page_num + 1} 页")
        
        print(f"\n✅ PDF拆分完成,所有页面已保存至: {output_dir}")
        return True
    except Exception as e:
        print(f"❌ 错误:{str(e)}")
        return False


def rotate_pages(pdf_path):
    """旋转PDF页面"""
    try:
        reader = PdfReader(pdf_path)
        writer = PdfWriter()
        
        # 获取旋转角度
        rotation = input("\n🔄 请输入旋转角度 (90/180/270): ").strip()
        if rotation not in ["90", "180", "270"]:
            print("❌ 无效的旋转角度,请输入90、180或270")
            return False
        rotation = int(rotation)
        
        output_path = select_output_path(default_name=os.path.splitext(os.path.basename(pdf_path))[0] + "_rotated.pdf")
        if not output_path:
            print("❌ 用户取消了保存")
            return False
        
        print(f"\n🔄 正在旋转 {os.path.basename(pdf_path)} 的所有页面...")
        
        for page in reader.pages:
            page.rotate(rotation)
            writer.add_page(page)
        
        writer.write(output_path)
        
        print(f"✅ PDF旋转完成,已保存至: {output_path}")
        return True
    except Exception as e:
        print(f"❌ 错误:{str(e)}")
        return False


def encrypt_pdf(pdf_path):

    try:
        reader = PdfReader(pdf_path)
        writer = PdfWriter()
        
        # 获取密码
        password = input("\n🔒 请输入PDF密码: ").strip()
        if not password:
            print("❌ 密码不能为空")
            return False
        
        output_path = select_output_path(default_name=os.path.splitext(os.path.basename(pdf_path))[0] + "_encrypted.pdf")
        if not output_path:
            print("❌ 用户取消了保存")
            return False
        
        print(f"\n🔒 正在加密 {os.path.basename(pdf_path)}...")
        
        # 添加所有页面
        for page in reader.pages:
            writer.add_page(page)
        
        # 加密PDF
        writer.encrypt(password)
        writer.write(output_path)
        
        print(f"✅ PDF加密完成,已保存至: {output_path}")
        return True
    except Exception as e:
        print(f"❌ 错误:{str(e)}")
        return False


def decrypt_pdf(pdf_path):
    """解密PDF文件"""
    try:
        reader = PdfReader(pdf_path)
        
        # 检查是否加密
        if not reader.is_encrypted:
            print("❌ 该PDF文件未加密")
            return False
        
        # 获取密码
        password = input("\n🔓 请输入PDF密码: ").strip()
        
        # 尝试解密
        if not reader.decrypt(password):
            print("❌ 密码错误")
            return False
        
        output_path = select_output_path(default_name=os.path.splitext(os.path.basename(pdf_path))[0] + "_decrypted.pdf")
        if not output_path:
            print("❌ 用户取消了保存")
            return False
        
        writer = PdfWriter()
        print(f"\n🔓 正在解密 {os.path.basename(pdf_path)}...")
        
        # 添加所有页面
        for page in reader.pages:
            writer.add_page(page)
        
        writer.write(output_path)
        
        print(f"✅ PDF解密完成,已保存至: {output_path}")
        return True
    except Exception as e:
        print(f"❌ 错误:{str(e)}")
        return False


def show_menu():
    """显示主菜单"""
    while True:
        print("\n" + "="*50)
        print("          PDF 操作工具")
        print("="*50)
        print("1. 📄 查看PDF信息")
        print("2. 📝 提取PDF文本")
        print("3. 🔄 合并多个PDF")
        print("4. ✂️  拆分PDF文件")
        print("5. 🔄 旋转PDF页面")
        print("6. 🔒 加密PDF文件")
        print("7. 🔓 解密PDF文件")
        print("0. 🚪 退出程序")
        print("="*50)
        
        choice = input("请选择操作 (0-7): ").strip()
        
        if choice == "0":
            print("\n👋 感谢使用,再见!")
            break
        
        elif choice in ["1", "2", "4", "5", "6", "7"]:
            # 需要选择单个PDF文件的操作
            pdf_path = select_pdf_files(multiple=False)
            if not pdf_path:
                print("❌ 未选择任何PDF文件")
                continue
            
            if choice == "1":
                get_pdf_info(pdf_path)
            elif choice == "2":
                extract_text(pdf_path)
            elif choice == "4":
                split_pdf(pdf_path)
            elif choice == "5":
                rotate_pages(pdf_path)
            elif choice == "6":
                encrypt_pdf(pdf_path)
            elif choice == "7":
                decrypt_pdf(pdf_path)
        
        elif choice == "3":
            # 合并PDF操作
            merge_pdfs()
        
        else:
            print("❌ 无效的选择,请重新输入")
        
        input("\n按回车键继续...")


if __name__ == "__main__":
    show_menu()
相关推荐
reasonsummer11 分钟前
【办公类-53-12】20261016(预测)Python模仿制作2026学年第二学期校历(excel+pdf,上下学期都包含)
pdf·excel
开开心心就好4 小时前
多份文档怎么批量打印?支持多种格式
java·服务器·开发语言·pdf·ocr·散列表·启发式算法
开开心心就好6 小时前
文件被占用删不掉?解锁工具强制删除
java·运维·服务器·开发语言·前端·pdf·ocr
BD_Marathon9 小时前
PyPDFLoader和MinerU加载pdf文件
pdf
ydjs678899-bot1 天前
如何在Java中打印pdf静默打印和打印对话框选择
java·python·pdf
SamChan901 天前
PDF 翻译后 1,250 变成 1.250,是错了吗?用 Python 核对数字格式
python·pdf·ocr·数据校验·文档翻译
开开心心就好2 天前
打印机卡住打不了?一键清理卡死打印队列
服务器·开发语言·算法·pdf·ocr·idea·visual studio code
打工仔折腾 AI2 天前
在线PDF工具隐私焦虑?把BentoPDF部署到极空间NAS本地处理
人工智能·后端·python·pdf·ai agent 实战
霸道流氓气质2 天前
AI 简历制作平台:结构化输出解析、多模板渲染与 PDF 导出的 Vue3 + Spring AI 全栈实战
人工智能·spring·pdf
开开心心_Every2 天前
黄金价格软件国内外价格实时监控超方便
运维·服务器·游戏·智能手机·pdf·lua·perl