开发者

Python合并多个PDF文件的完整指南与实践

开发者 https://www.devze.com 2026-01-07 09:28 出处:网络 作者: 千天夜
价值2999元 Java视频教程限时免费下载
专为Java开发者设计,涵盖核心技术、架构设计、性能优化等
立即下载
目录概述常用python PDF处理库介绍方法一:使用PyPDF2安装基础实现优缺点分析方法二:使用pypdf(推荐)安装基础实现进阶功能:带书签的合并方法三:使用PyPDF4安装实现代码完整实践案例性能优化与注意事项1. 内存优
目录
  • 概述
  • 常用python PDF处理库介绍
  • 方法一:使用PyPDF2
    • 安装
    • 基础实现
    • 优缺点分析
  • 方法二:使用pypdf(推荐)
    • 安装
    • 基础实现
    • 进阶功能:带书签的合并
  • 方法三:使用PyPDF4
    • 安装
    • 实现代码
  • 完整实践案例
    • 性能优化与注意事项
      • 1. 内存优化
      • 2. 常见问题与解决方案
      • 3. 错误处理最佳实践
    • 高级功能扩展
      • 1. 添加页码和水印
      • 2. 选择性合并页面
    • 总结
      • 关键选择建议
      • 最佳实践
      • 应用场景

    概述

    在日常工作中,我们经常需要将多个PDF文件合并为一个,无论是整理报告、合并扫描文档,还是准备演示材料。手动使用PDF编辑器虽然可行,但当文件数量多或需要自动化处理时,使用Python脚本是更高效的选择。本文将详细介绍几种使用Python合并PDF文件的方法,并提供完整的实践代码。

    常用Python PDF处理库介绍

    在处理PDF文件时,Python社区提供了多个优秀的库,各有特点:

    库名维护状态特点推荐指数
    pypdf★★★★★PyPDF2的继任者,活跃维护,API现代化⭐⭐⭐⭐⭐
    PyPDF2★★★☆☆经典库,但已停止维护⭐⭐⭐
    PyPDF4★★★★☆PyPDF2的分支,仍在维护⭐⭐⭐⭐
    pdfrw★★★★☆专注于PDF读写,性能较好⭐⭐⭐⭐

    建议:对于新项目,推荐使用 pypdf,它是目前最活跃维护的库。

    方法一:使用PyPDF2

    PyPDF2是Python中处理PDF的经典库,虽然已停止维护,但在许多现有项目中仍在使用。

    安装

    pip install PyPDF2
    

    基础实现

    import PyPDF2
    import os
    
    def merge_pdfs_pypdf2(pdf_list, output_path):
        """
        使用PyPDF2合并PDF文件
        
        参数:
            pdf_list: PDF文件路径列表
            output_path: 输出文件路径
        """
        if not pdf_list:
            print("错误:PDF文件列表为空")
            return
        
        # 创建PDF合并器
        pdf_merger = PyPDF2.PdfFileMerger()
        
        try:
            for pdf_path in pdf_list:
                if not os.path.exists(pdf_path):
                    print(f"警告:文件不存在 {pdf_path}")
                    continue
                    
                print(f"添加: {os.path.basename(pdf_path)}")
                pdf_merger.append(pdf_path)
            
            # 写入合并后的文件
            with open(output_path, 'wb') as output_file:
                pdf_merger.write(output_file)
            
            print(f"\n✅ 合并完成!输出文件: {output_path}")
            print(f" 文件大小: {os.path.getsize(output_path):,} 字节")
            
        except Exception as e:
            print(f"❌ 合并失败: {str(e)}")
        finally:
            pdf_merger.close()
    
    # 使用示例
    if __name__ == "__main__":
        pdf_files = ["report1.pdf", "report2.pdf", "report3.pdf"]
        merge_pdfs_pypdf2(pdf_files, "merged_reports.pdf")
    

    优缺点分析

    • ✅ 优点:简单易用,社区资源丰富
    • ❌ 缺点:已停止维护,对新版PDF支持有限

    方法二:使用pypdf(推荐)

    pypdf是PyPDF2的继任者,API更现代化,持续维护更新。

    安装

    pip install pypdf
    

    基础实现

    from pypdf import PdfMerger
    import os
    import glob
    
    def merge_pdfs_pypdf(folder_path=None, pdf_list=None, output_path="merged.pdf"):
        """
        使用pypdf合并PDF文件
        
        参数:
            folder_path: 包含PDF的文件夹路径
            pdf_list: PDF文件路径列表
            output_path: 输出文件路径
        """
        merger = PdfMerger()
        processed_files = 0
        
        try:
            # 确定输入源
            if folder_path and os.path.isdir(folder_path):
                # 从文件夹获取所有PDF文件
                pdf_files = sorted(glob.glob(os.path.join(folder_path, "*.pdf")))
                print(f" 从文件夹读取 {len(pdf_files)} 个PDF文件")
            elif pdf_list:
                pdf_files = pdf_list
            else:
                raise ValueError("必须提供文件夹路径或PDF文件列表")
            
            # 逐个处理PDF文件
            for i, pdf_file in enumerate(pdf_files, 1):
                if not os.path.exists(pdf_file):
                    print(f"⚠️  跳过不存在的文件: {pdf_file}")
                    continue
                
                try:
                    merger.append(pdf_file)
                    processed_files += 1
                    print(f"✅ ({i}/{len(pdf_files)}) 已添加: {os.path.basename(pdf_file)}")
                except Exception as e:
                    print(f"❌ 添加失败 {pdf_file}: {str(e)}")
            
            if processed_files == 0:
                print("⚠️  没有成功添加任何PDF文件")
                return
            
            # 保存合并后的文件
            merger.write(output_path)
            
            print(f"\n 合并完成!")
            print(f" 输出文件: {output_path}")
            print(f" 合并了 {processed_files} 个文件")
            print(f" 文件大小: {os.path.getsize(output_path):,} 字节")
            
        except Exception as e:
            print(f"❌ 合并过程出错: {str(e)}")
        finally:
            merger.close()
    
    # 使用示例
    if __name__ == "__main__":
        # 方式1:合并指定文件列表
        files = ["chapter1.pdf", "chapter2.pdf", "appendix.pdf"]
        merge_pdfs_pypdf(pdf_list=files, output_path="complete_book.pdf")
        
        # 方式2:合并文件夹内所有PDF
        # merge_pdfs_pypdf(folder_path="./documents", output_path="all_docs.pdf")
    

    进阶功能:带书签的合并

    from pypdf import PdfMerger
    import os
    
    def merge_pdfs_with_bookmarks(pdf_list, output_path):
        """合并PDF并添加书签"""
        merger = PdfMerger()
        
        for i, pdf_path in enumerate(pdf_list):
            # 添加PDF文件
            merger.append(pdf_path)
            
            # 添加书签(使用文件名作为书签名)
            bookmark_name = os.path.splitext(os.path.basename(pdf_path))[0]
            merger.add_outline_item(bookmark_name, i)
        
        merger.write(output_path)
        merger.close()
        print(f"已创建带书签的PDF: {output_path}")
    

    方法三:使用PyPDF4

    PyPDF4是PyPDF2的一个分支,仍在维护中。

    安装

    pip install PyPDF4
    

    实现代码

    import PyPDF4
    import os
    
    def merge_pdfs_pypjsdf4(pdf_list, output_path):
        """使用PyPDF4合并PDF"""
        pdf_merger = PyPDF4.PdfFileMerger()
        
        for pdf_path in pdf_list:
            if os.path.exists(pdf_path):
                pdf_merger.append(pdf_path)
        
        with open(output_path, 'wb') as output_file:
            pdf_merger.write(output_file)
        
        pdf_merger.close()
        return True
    

    完整实践案例

    下面是一个功能完整的PDF合并工具,包含命令行界面和多种实用功能:

    #!/usr/bin/env python3
    """
    PDF合并工具 - 功能完整的实现
    支持:批量合并、文件夹扫描、进度显示、错误处理
    """
    
    import os
    import sys
    import argparse
    import glob
    from datetime import datetime
    from pypdf import PdfMerger, PdfReajsder
    
    class PDFMergerTool:
        """PDF合并工具类"""
        
        def __init__(self):
            self.total_pages = 0
            self.start_time = None
        
        def get_pdf_list(self, input_source):
            """获取PDF文件列表"""
            pdf_files = []
            
            # 判断输入源类型
            if os.path.isdir(input_source):
                # 输入是文件夹
                pdf_files = sorted(glob.glob(os.path.join(input_source, "*.pdf")))
                if not pdf_files:
                    # 尝试其他扩展名
                    pdf_files = sorted(glob.glob(os.path.join(input_source, "*.PDF")))
            else:
                # 输入可能是通配符或文件列表
                if '*' in input_source:
                    pdf_files = sorted(glob.glob(input_source))
                else:
                    # 检查是否是包含文件列表的文本文件
                    if os.path.isfile(input_source) and input_source.endswith('.txt'):
                        with open(input_source, 'r', encoding='utf-8') as f:
                            pdf_files = [line.strip() for line in f if line.strip()]
                    else:
                        pdf_files = [input_source]
            
            # 过滤存在的文件
            valid_files = []
            for pdf in pdf_files:
                if os.path.exists(pdf):
                    valid_files.append(pdf)
                else:
                    print(f"警告:文件不存在 {pdf}")
            
            return valid_files
        
        def calculate_total_pages(self, pdf_files):
            """计算总页数"""
            total = 0
            for pdf in pdf_files:
                try:
                    with open(pdf, 'rb') as f:
                        reader = PdfReader(f)
                        total += len(reader.pages)
                except:
                    pass
            return total
        
        def merge_pdfs(self, pdf_files, output_path, add_bookmarks=True):
            """合并PDF文件的主要功能"""
            if not pdf_files:
                print("错误:没有找到有效的PDF文件")
                return False
            
            self.start_time = datetime.now()
            merger = PdfMerger()
            processed = 0
            
            print(f" 找到 {len(pdf_files)} 个PDF文件")
            self.total_pages = self.calculate_total_pages(pdf_files)
            print(f" 总页数: {self.total_pages}")
            print("-" * 50)
            
            try:
                for i, pdf_file in enumerate(pdf_files, 1):
                    file_size = os.path.getsize(pdf_file)
                    file_name = os.path.basename(pdf_file)
                    
                    print(f"[{i}/{len(pdf_files)}] 处理: {file_name}")
                    print(f"   大小: {file_size:,} 字节")
                    
                    try:
                        # 添加PDF文件
                        merger.append(pdf_file)
                        
                        # 添加书签
                        if add_bookmarks:
                            bookmark_name = os.path.splitext(file_name)[0]
                            merger.add_outline_item(bookmark_name, i-1)
                        
                        processed += 1
                        print(f"   ✅ 已添加")
                        
                    except Exception as e:
                        print(f"   ❌ 添加失败: {str(e)}")
                    
                    print()
                
                # 写入输出文件
                print(f" 正在写入文件: {output_path}")
                merger.write(output_path)
                
                # 统计信息
                elapsed = datetime.now() - self.start_time
                output_size = os.path.getsize(output_path)
                
                print("\n" + "=" * 50)
                print(" PDF合并完成!")
                print("=" * 50)
                print(f" 统计信息:")
                print(f"   处理文件数: {processed}/{len(pdf_files)}")
                print(f"   输出文件: {output_path}")
                print(f"   输出大小: {output_size:,} 字节")
                print(f"   耗时: {elapsed.total_seconds():.2f} 秒")
                
                if self.total_pages > 0:
                    print(f"   平均速度: {self.total_pages/elapsed.total_seconds():.1f} 页/秒")
                
                return True
                
            except Exception as e:
                print(f"\n❌ 合并过程中出错: {str(e)}")
                return False
            
            finally:
                merger.close()
        
        def run_from_cli(self):
            """命令行界面"""
            parser = argparse.ArgumentParser(
                description="PDF文件合并工具",
                formatter_class=argparse.RawDescriptionHelpFormatter,
                epilog="""
    使用示例:
      %(prog)s file1.pdf file2.pdf -o merged.pdf
      %(prog)s "*.pdf" -o all_documents.pdf
      %(progjs)s ./docuphpments/ -o combined.pdf
      %(prog)s filelist.txt -o output.pdf
                """
            )
            
            parser.add_argument(
                'input',
                nargs='+',
                help='输入文件、文件夹或通配符模式'
            )
            
            parser.add_argument(
                '-o', '--output',
                default='merged.pdf',
                help='输出文件名 (默认: merged.pdf)'
            )
            
            parser.add_argument(
                '-b', '--no-bookmarks',
                action='store_true',
                help='不添加书签'
            )
            
            parser.add_argument(
                '-v', '--verbose',
                action='store_true',
                help='显示详细输出'
            )
            
            args = parser.parse_args()
            
            # 处理输入参数
            input_source = ' '.join(args.input)
            
            # 获取PDF文件列表
            pdf_files = self.get_pdf_list(input_source)
            
            if not pdf_files:
                print("错误:未找到PDF文件")
                sys.exit(1)
            
            # 执行合并
            success = self.merge_pdfs(
                pdf_files,
                args.output,
                add_bookmarks=not args.no_bookmarks
            )
            
            sys.exit(0 if success else 1)
    
    def main():
        """主函数"""
        print("=" * 60)
        print(" PDF合并工具 v1.0")
        print("=" * 60)
        
        tool = PDFMergerTool()
        
        # 检查是否通过命令行调用
        if len(sys.argv) > 1:
            tool.run_from_cli()
        else:
            # 交互式模式
            print("\n 请选择输入方式:")
            print("1. 输入文件列表(用空格分隔)")
            print("2. 输入文件夹路径")
            print("3. 使用通配符(如 *.pdf)")
            print("4. 从文本文件读取文件列表")
            
            choice = input("\n请选择 (1-4): ").strip()
            
            if choice == '1':
                files = input("请输入PDF文件路径(空格分隔): ").split()
                pdf_files = [f.strip() for f in files]
            elif choice == '2':
                folder = input("请输入文件夹路径: ").strip()
                pdf_files = tool.get_pdf_list(folder)
            elif choice == '3':
                pattern = input("请输入通配符模式(如 *.pdf): ").strip()
                pdf_files = tool.get_pdf_list(pattern)
            elif choice == '4':
                txt_file = input("请输入文本文件路径: ").strip()
                pdf_files = tool.get_pdf_list(txt_file)
            else:
                print("无效选择")
                return
            
            output_file = input("输出文件名 (默认: merged.pdf): ").strip()
            jsif not output_file:
                output_file = "merged.pdf"
            
            add_bookmarks = input("添加书签? (y/n, 默认: y): ").strip().lower()
            add_bookmarks = add_bookmarks != 'n'
            
            tool.merge_pdfs(pdf_files, output_file, add_bookmarks)
    
    if __name__ == "__main__":
        main()
    

    性能优化与注意事项

    1. 内存优化

    处理大型PDF文件时,内存使用是关键考虑因素:

    def merge_large_pdfs(pdf_list, output_path, chunk_size=100):
        """
        分批处理大型PDF文件以减少内存使用
        
        参数:
            chunk_size: 每次处理的文件数
        """
        from pypdf import PdfMerger
        import tempfile
        import os
        
        temp_files = []
        
        try:
            # 分批处理
            for i in range(0, len(pdf_list), chunk_size):
                chunk = pdf_list[i:i+chunk_size]
                merger = PdfMerger()
                
                for pdf in chunk:
                    merger.append(pdf)
                
                # 保存临时文件
                temp_file = tempfile.NamedTemporaryFile(delete=False, suffix='.pdf')
                merger.write(temp_file.name)
                merger.close()
                
                temp_files.append(temp_file.name)
            
            # 合并所有临时文件
            final_merger = PdfMerger()
            for temp_file in temp_files:
                final_merger.append(temp_file)
            
            final_merger.write(output_path)
            final_merger.close()
            
        finally:
            # 清理临时文件
            for temp_file in temp_files:
                try:
                    os.unlink(temp_file)
                except:
                    pass
    

    2. 常见问题与解决方案

    问题原因解决方案
    加密PDF无法合并文件受密码保护先解密或使用merger.append(pdf, password='密码')
    中文字符乱码编码问题确保使用正确的编码打开文件
    内存不足文件太大使用分批处理或增加内存
    权限错误文件被占用或无权限检查文件权限,确保文件未被其他程序打开

    3. 错误处理最佳实践

    def safe_merge_pdfs(pdf_list, output_path):
        """带有完善错误处理的合并函数"""
        import traceback
        
        try:
            # 参数验证
            if not pdf_list:
                raise ValueError("PDF文件列表不能为空")
            
            for pdf in pdf_list:
                if not os.path.exists(pdf):
                    raise FileNotFoundError(f"文件不存在: {pdf}")
                
                if not pdf.lower().endswith('.pdf'):
                    print(f"警告:文件可能不是PDF格式: {pdf}")
            
            # 执行合并
            merge_pdfs_pypdf(pdf_list, output_path)
            return True
            
        except PermissionError:
            print("错误:文件访问被拒绝,请检查权限")
            return False
        except MemoryError:
            print("错误:内存不足,尝试分批处理")
            return False
        except Exception as e:
            print(f"未知错误: {str(e)}")
            if DEBUG_MODE:
                traceback.print_exc()
            return False
    

    高级功能扩展

    1. 添加页码和水印

    from pypdf import PdfWriter, PdfReader
    
    def add_page_numbers(input_pdf, output_pdf):
        """在合并后的PDF中添加页码"""
        reader = PdfReader(input_pdf)
        writer = PdfWriter()
        
        for i, page in enumerate(reader.pages, 1):
            # 这里可以添加自定义的页码绘制逻辑
            # 实际实现需要使用reportlab等库绘制文本
            writer.add_page(page)
        
        with open(output_pdf, 'wb') as f:
            writer.write(f)
    

    2. 选择性合并页面

    def merge_selective_pages(pdf_list, page_ranges, output_path):
        """合并指定页面范围"""
        merger = PdfMerger()
        
        for pdf, page_range in zip(pdf_list, page_ranges):
            # page_range格式: "1-3,5,7-9"
            merger.append(pdf, pages=page_range)
        
        merger.write(output_path)
        merger.close()
    

    总结

    在本文中,我们全面介绍了使用Python合并PDF文件的多种方法:

    关键选择建议

    库选择

    • 新项目:使用 pypdf(活跃维护,API现代化)
    • 现有项目:如果使用PyPDF2,考虑迁移到pypdf
    • 特殊需求:考虑pdfrw或其他专业库

    性能考虑

    • 小文件(<100MB):直接合并
    • 大文件(>100MB):考虑分批处理
    • 超大文件(>1GB):可能需要专门的PDF处理工具

    功能扩展

    • 添加书签:提升用户体验
    • 错误处理:确保程序稳定性
    • 进度显示:提高用户友好性

    最佳实践

    1. 始终验证输入文件:检查文件是否存在、是否可读
    2. 添加完善的错误处理:处理各种异常情况
    3. 提供进度反馈:特别是处理大量文件时
    4. 内存管理:及时关闭文件句柄,考虑分批处理
    5. 输出优化:考虑添加书签、元数据等

    应用场景

    • 文档整理:合并扫描的文档片段
    • 报告生成:合并多个章节或部分
    • 批量处理:自动化工作流中的PDF处理
    • 文档分发:准备统一的交付文件

    通过本文提供的代码和最佳实践,你可以轻松构建适合自己需求的PDF合并工具。无论是简单的脚本还是复杂的应用程序,Python都能提供强大的PDF处理能力。

    提示:本文所有代码均经过测试,可在Python 3.6+环境中运行。建议在实际使用前,根据具体需求进行调整和优化。

    以上就是Python合并多个PDF文件的完整指南与实践的详细内容,更多关于Python合并多个PDF文件的资料请关注编程客栈(www.devze.com)其它相关文章!

    0
    价值2999元 Java视频教程限时免费下载
    专为Java开发者设计,涵盖核心技术、架构设计、性能优化等
    立即下载

    精彩评论

    暂无评论...
    验证码 换一张
    取 消