You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用PyPDF2批量处理多目录PDF时遭遇UnicodeError问题求助

问题分析与解决方案

报错根本原因

从堆栈信息看,PyPDF2在验证文件头时触发Unicode解码失败,核心原因是递归遍历过程中脚本尝试读取了非PDF格式文件(比如临时文件、隐藏文件或其他格式文件)。这类文件的开头不是标准PDF的%PDF标识,导致utf-8解码失败。单独处理文件夹时,这类非PDF文件可能不存在或未被遍历到,因此能正常运行。

同时你的代码存在多处逻辑缺陷,加剧了问题:

  • 重复使用files变量(外层os.walk的files与内层循环变量重名),导致遍历逻辑混乱
  • 路径拼接错误:手动拼接字符串容易出现路径层级错误
  • 页面循环中反复打开输出文件,会导致内容被多次覆盖
  • 手动调用in_f.close()属于冗余操作,with open会自动管理文件关闭

修复后的代码

from PyPDF2 import PdfFileReader, PdfFileWriter
import os

source_folder = r'L:\py_test'

# 递归遍历目标目录下所有文件
for root, dirs, files in os.walk(source_folder):
    for file_name in files:
        # 仅处理PDF文件,过滤非目标格式
        if not file_name.lower().endswith('.pdf'):
            continue
            
        file_path = os.path.join(root, file_name)
        try:
            with open(file_path, 'rb') as in_f:
                # 前置检查:验证是否为标准PDF文件
                header = in_f.read(4)
                if header != b'%PDF':
                    print(f"跳过非PDF文件: {file_path}")
                    continue
                # 重置文件指针至开头
                in_f.seek(0)
                
                input_pdf = PdfFileReader(in_f)
                output_pdf = PdfFileWriter()
                total_pages = input_pdf.getNumPages()
                print(f"处理文件: {file_path}, 共 {total_pages} 页")
                
                need_crop = False
                for page_idx in range(total_pages):
                    page = input_pdf.getPage(page_idx)
                    page_height = page.mediaBox.getUpperRight_y()
                    print(f"第{page_idx+1}页高度: {page_height} pts")
                    
                    if page_height > 1300:
                        need_crop = True
                        # 修正裁剪坐标:保留底部1220pts区域(如需保留顶部可调换坐标)
                        page.cropBox.upperRight = (page.mediaBox.getUpperRight_x(), page_height)
                        page.cropBox.lowerLeft = (0, page_height - 1220)
                    output_pdf.addPage(page)
                
                if need_crop:
                    # 生成新文件路径,避免覆盖原文件
                    new_file_path = os.path.splitext(file_path)[0] + "_new.pdf"
                    with open(new_file_path, 'wb') as out_f:
                        output_pdf.write(out_f)
                    print(f"已生成裁剪文件: {new_file_path}")
                else:
                    print(f"{file_path} 所有页面高度≤1300pts,无需裁剪")
                    
        except Exception as e:
            print(f"处理文件 {file_path} 出错: {str(e)}")
            continue

核心修复点

  • 严格过滤PDF文件:通过后缀+文件头双重校验,彻底避免读取非PDF文件
  • 变量名规范:将内层循环变量改为file_name,避免与外层files冲突
  • 路径拼接优化:使用os.path.join正确生成递归路径,杜绝手动拼接的层级错误
  • 裁剪逻辑修正:修复原代码中反向的裁剪坐标,确保裁剪区域正确
  • 输出逻辑优化:处理完所有页面后一次性写入输出文件,避免内容覆盖
  • 异常隔离:添加try-except捕获单个文件的处理错误,保证递归流程不中断

内容的提问来源于stack exchange,提问作者Camerak

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 17:40:30