资讯详情

资讯详情

PDF批量压缩实战:Ghostscript与Python脚本详解

在日常办公、资料归档、邮件附件上传以及网盘同步这些场景里PDF 体积过大是很多人都会遇到的一个痛点。一份文件动辄几十兆不仅占空间上传下载也慢如果手里积压了成百上千个 PDF一个一个用编辑器另存去压缩工作量会非常可怕。本文以“批量压缩 PDF”为目标从压缩原理讲起给出命令行方案和 Python 脚本方案并提供完整可复制的代码、运行步骤、常见报错排查和工程建议适合有一定办公自动化需求的学生、HR、财务、档案管理员和开发者阅读。先提醒一点批量压缩和“批量降低图片画质”不是一回事。如果你只是粗暴地把 PDF 的每一页转成低分辨率图片再重新生成 PDF页面上原本可选的文本会丢失打印效果也会明显变差。正确的做法应该是有选择地去重采样图片、清理无用对象、压缩内容流并保留文字层和基本结构。下面我们围绕这套思路逐步展开。1. 背景与核心概念1.1 PDF 体积为什么越来越大PDF 并不是一种“越存越小”的格式。很多 PDF 在生成时为了兼容性会嵌入整套字体通过 Word、WPS 或设计软件导出的 PDF 往往还保留了大量编辑信息扫描仪生成的 PDF 更是直接把每一页保存为高分辨率图片。这些因素叠加在一起文件体积就会快速膨胀。从根本上说PDF 是一个容器它内部至少包含四类东西文本内容和字体文本本身不大但嵌入的完整字体文件可能有好几兆。图片对象扫描件、截图、商品图、流程图这些是 PDF 体积的大头。内容流描述页面布局、绘制指令的代码通常是可压缩的。元数据和辅助对象书签、缩略图、属性信息、冗余对象。如果你的 PDF 是从 CAD、PS 或高分辨率扫描设备导出的图片部分占比通常超过 90%。这时候压缩 PDF 的核心问题就变成了在“视觉可接受”和“文件体积”之间做平衡。1.2 批量压缩的典型应用场景批量压缩绝不是“把单个文件多处理几次”那么简单。常见的应用场景包括电子档案归档大批量扫描件转存的 PDF 需要长期保存体积过大会浪费存储空间。邮件附件发送多数邮箱附件限制在 20MB 到 50MB 之间超大 PDF 需要降体积后才能发送。网盘同步与知识库搭建压缩后能显著减少上传时间也便于检索和分享。电子书整理从网上下载或自行排版的 PDF 书刊压缩后可存入阅读器节省设备空间。业务流程处理比如人力资源部门批量处理简历、合同财务部门批量归档电子发票。这些场景里如果只靠人工打开软件另存为效率极低且容易漏处理。批量压缩的价值在于一次写脚本永久复用。1.3 压缩不是简单降低分辨率很多新手会对“压缩 PDF”产生一个误解把每页导出成图片缩小后再拼回 PDF。这种思路只适合打印质量要求极高且不需要文本层的场景。绝大多数办公场景下我们要的是尽量保留文字和矢量信息的可编辑性尽量保留页面的排版效果对内嵌图片做适度重采样只删除冗余对象和无效元数据。所以批量压缩应该理解为“基于 PDF 内部结构优化”而不是“把 PDF 当图片重绘”。2. 环境准备与版本说明PDF 压缩可以用不同技术栈实现Java 、Python、命令行工具都可以。本文选择“Python Ghostscript”的组合原因是它跨平台、安装简单、脚本适合批量化且 Ghostscript 的 PDF 优化引擎足够成熟压缩效果明显。2.1 推荐技术路线推荐路线如下操作系统Windows 10/11、macOS、Linux 均可本文示例以通用命令说明为主。脚本语言Python 3.8 及以上版本低版本请留意pathlib和subprocess的兼容性。压缩引擎Ghostscript这是开源的 PostScript 和 PDF 解释器内置pdfwrite输出设备专门用于 PDF 重建和优化。Python 库pikepdf和PyMuPDF作为备选方案用于兼容加密 PDF、清理无用对象等场景。版本需要根据你的实际环境调整本文重点是配置和代码思路。比如你使用的是 Python 3.12 或 3.13依赖安装方式不变但个别库的底层版本可能影响运行结果建议先用小样本测试。2.2 安装 GhostscriptGhostscript 的安装方式按系统区分Windows从官方渠道下载安装包如 Ghostscript 的 Windows 安装程序安装时可以选择“添加到系统 PATH”。如果没勾选安装后在命令行中找不到gswin64c脚本就需要写绝对路径。macOS执行brew install ghostscript安装后命令名一般是gs。LinuxDebian/Ubuntu执行sudo apt-get install ghostscriptCentOS/RHEL 上可以使用sudo yum install ghostscript。安装完成后在终端执行gs --version如果能输出版本号说明安装成功。Windows 用户如果遇到“不是内部或外部命令”说明 Ghostscript 没有加入 PATH后面会单独说解决方法。2.3 安装 Python 依赖Python 侧建议新建一个虚拟环境避免依赖冲突python -m venv pdf_compress_env激活环境后安装依赖# Windows pdf_compress_env\Scripts\activate # macOS / Linux source pdf_compress_env/bin/activate然后安装库pip install pikepdf pymupdf如果网络较慢可以加国内镜像源pip install pikepdf pymupdf -i https://pypi.tuna.tsinghua.edu.cn/simple安装完成后可以进入 Python 交互环境做一个导入验证import pikepdf import fitz print(pikepdf.__version__) print(fitz.__doc__)能正常打印版本信息说明环境就绪。3. 批量压缩的核心原理3.1 PDF 里的体积来源分析要写出真正有效的压缩脚本首先要大概知道 PDF 的体积来源。文本 PDF 和扫描件 PDF 的压缩策略完全不同文本型 PDFWord 导出、LaTeX 生成的论文、公众号排版导出的文档体积主要来自嵌入字体和内容流压缩重点在于字体子集化和流压缩Ghostscript 能很好处理。图片型 PDF扫描仪生成、PS 导出、产品图册体积主要来自内嵌图片压缩重点在于图片重采样。如果图片是 300 DPI 的彩色扫描件改成 150 DPI 往往体积能减少一半以上。混合型 PDF既有大量文字又有插图、照片、封面图需要综合处理。如果你不确定 PDF 的体积类型可以先开 Python 看一眼页面里的图片数量、颜色空间和分辨率再决定压缩参数。3.2 三种主流压缩手段常见的批量压缩手段可以归纳为三类第一类内容流压缩。PDF 内部的页面内容流可以使用 Flate 等算法压缩compress_streams就属于这类。它适合对已经解压过的 PDF、或是由某些工具生成时未开启压缩的 PDF。这类方法不改变画面无损程度最高但压缩率有限。第二类图片重采样。把高分辨率的位图降到合理分辨率比如从 300 DPI 降到 150 DPI并统一图片颜色空间。这是大幅减小体积的最有效手段但会造成一定的细节损失。第三类移除冗余对象。PDF 重新生成时可以丢弃未引用的对象、过时的元数据、重复字体。garbage、clean参数就是做这一类清理。一份成熟的压缩方案通常三管齐下。Ghostscript 就是通过组合这些策略把原始 PDF 重建为一个更精简的新 PDF。3.3 主流工具横向对比下面这个表格能帮你理解三种常用工具各自的定位工具/库定位优点局限Ghostscript命令行压缩引擎压缩层度深支持 DPI 重采样批量处理稳定需要额外安装参数较多不同版本参数细节有差异pikepdfPython PDF 库无损清理、压缩流适合加密 PDFAPI 清晰不做图片重采样时体积下降有限PyMuPDFPython PDF 库可清理无用对象支持渲染和图片操作轻量级清理为主复杂图像压缩需配合其他手段在实际工程中推荐把 Ghostscript 作为主压缩引擎把 pikepdf 作为“打不过 Ghostscript 时”的兜底工具比如遇到损坏 PDF 或加密 PDF可以先用 pikepdf 尝试修复和重建。4. 完整实战命令行批量压缩 PDF命令行方案适合临时处理、服务器环境或不需要写完整 Python 程序的场景。它的核心是 Ghostscript。4.1 使用 Ghostscript 压缩单个 PDF先看单个文件的压缩命令。假设输入文件是input.pdf输出文件是output.pdfgs \ -sDEVICEpdfwrite \ -dCompatibilityLevel1.7 \ -dPDFSETTINGS/ebook \ -dNOPAUSE \ -dQUIET \ -dBATCH \ -sOutputFileoutput.pdf \ input.pdf参数含义如下-sDEVICEpdfwrite告诉 Ghostscript 使用 PDF 输出设备目标是生成一个新的 PDF 文件。-dCompatibilityLevel1.7输出的 PDF 兼容 1.7 版本绝大多数阅读器都支持。-dPDFSETTINGS/ebook选用“电子书”优化级别适合普通办公文档。-dNOPAUSE、-dBATCH不暂停、不交互适合批量处理。-dQUIET减少不必要的输出日志更干净。执行完成后对比input.pdf和output.pdf的大小就能看出压缩效果。4.2 用批处理脚本压缩文件夹如果只有几十个 PDF可以用终端循环。Windows CMD 里可以写echo off set INPUT_DIRD:\pdf_input set OUTPUT_DIRD:\pdf_output mkdir %OUTPUT_DIR% 2nul for %%f in (%INPUT_DIR%\*.pdf) do ( gswin64c -sDEVICEpdfwrite -dPDFSETTINGS/ebook -dNOPAUSE -dBATCH -dQUIET -sOutputFile%OUTPUT_DIR%\%%~nf.pdf %%f ) echo batch compress donemacOS 或 Linux 的 Bash 脚本可以写#!/bin/bash input_dirpdf_input output_dirpdf_output mkdir -p $output_dir for pdf in $input_dir/*.pdf; do name$(basename $pdf) gs -sDEVICEpdfwrite -dPDFSETTINGS/ebook -dNOPAUSE -dBATCH -dQUIET \ -sOutputFile$output_dir/$name $pdf done echo batch compress done命令行方案的优点是简单直接缺点是无法自动跳过已经压缩过的文件无法自动记录每个文件的压缩率无法处理文件名带空格或者路径特殊符号时产生的小问题用户对整个流程的透明度不高。所以当你打算把压缩归档变成一个稳健的生产工具时应该转用 Python 脚本。5. 完整实战Python 批量压缩脚本这一章是文章的核心。我会给出一个可以直接复制运行的 Python 脚本它不仅能批量压缩 PDF还会输出压缩日志跳过不需要处理的文件并在压缩失败时自动降级处理。5.1 项目结构建议按照下面的结构组织文件pdf_batch_compress/ ├── pdf_input/ # 放原始 PDF ├── pdf_output/ # 放压缩后的 PDF ├── logs/ # 保存运行日志 └── batch_pdf_compress.py提前把pdf_input、pdf_output、logs三个目录创建好。脚本会自动创建目录但手动创建便于你理解文件路径关系。5.2 核心代码调用 Ghostscript 批量压缩下面是一个完整的 Python 脚本文件路径为pdf_batch_compress/batch_pdf_compress.py 批量压缩 PDF 脚本 依赖: Python 3.8, Ghostscript 用法: python batch_pdf_compress.py \ --input pdf_input \ --output pdf_output \ --settings ebook \ --min-size-kb 100 \ --skip-existing import argparse import logging import shutil import subprocess import time from pathlib import Path logger logging.getLogger(pdf_compress) # Ghostscript 四档预设 SETTINGS_MAP { screen: /screen, # 屏幕预览体积最小 ebook: /ebook, # 电子阅读与办公文档 printer: /printer, # 打印机分辨率 prepress: /prepress, # 印刷输出级体积较大 } def find_ghostscript(): 查找系统中的 Ghostscript 可执行文件。 candidates [gs, gswin64c, gswin32c] for name in candidates: path shutil.which(name) if path: return path raise FileNotFoundError( 未找到 Ghostscript请先安装并配置 PATH 或者修改脚本中 candidates 为绝对路径。 ) def compress_pdf( gs_path: str, input_pdf: Path, output_pdf: Path, settings: str /ebook, ) - bool: 使用 Ghostscript 压缩单个 PDF。 output_pdf.parent.mkdir(parentsTrue, exist_okTrue) cmd [ gs_path, -sDEVICEpdfwrite, -dCompatibilityLevel1.7, f-dPDFSETTINGS{settings}, -dNOPAUSE, -dBATCH, -dQUIET, -sOutputFile, str(output_pdf), str(input_pdf), ] # 捕获标准输出和标准错误便于排查问题 result subprocess.run(cmd, capture_outputTrue, textTrue) if result.returncode ! 0: logger.error(压缩失败: %s, input_pdf.name) logger.error(result.stderr[-1500:] if result.stderr else 无错误信息) return False return output_pdf.exists() and output_pdf.stat().st_size 0 def batch_compress( input_dir: Path, output_dir: Path, settings: str, min_size_kb: int, skip_existing: bool, use_pikepdf_fallback: bool, ) - None: 批量遍历输入目录下的 PDF 并压缩。 gs_path find_ghostscript() # 只处理 PDF 文件 pdf_files list(input_dir.rglob(*.pdf)) if not pdf_files: logger.warning(输入目录下没有找到 PDF 文件。) return logger.info(共发现 %d 个 PDF 文件, len(pdf_files)) success_count 0 skip_count 0 fail_count 0 total_size_before 0 total_size_after 0 for index, input_pdf in enumerate(pdf_files, start1): size_before input_pdf.stat().st_size # 跳过过小文件 if size_before min_size_kb * 1024: logger.info([%d/%d] 跳过过小文件: %s (%.1f KB), index, len(pdf_files), input_pdf.name, size_before / 1024) skip_count 1 continue # 输出路径保持相对目录结构是更稳妥的选择 relative_path input_pdf.relative_to(input_dir) output_pdf output_dir / relative_path if skip_existing and output_pdf.exists(): logger.info([%d/%d] 跳过已存在文件: %s, index, len(pdf_files), output_pdf.name) skip_count 1 continue logger.info([%d/%d] 正在压缩: %s (%.1f MB), index, len(pdf_files), input_pdf.name, size_before / 1024 / 1024) ok compress_pdf(gs_path, input_pdf, output_pdf, settings) if not ok and use_pikepdf_fallback: # 如果是 Ghostscript 无法处理则尝试用 pikepdf 兜底 ok compress_with_pikepdf(input_pdf, output_pdf) if ok: size_after output_pdf.stat().st_size ratio (1 - size_after / size_before) * 100 if size_before else 0 total_size_before size_before total_size_after size_after success_count 1 logger.info( 压缩后: %.1f MB压缩率 %.1f%%, size_after / 1024 / 1024, ratio) else: fail_count 1 logger.info(处理完成: 成功 %d 个跳过 %d 个失败 %d 个, success_count, skip_count, fail_count) if total_size_before: logger.info(总体积从 %.1f MB 降至 %.1f MB减少 %.1f%%, total_size_before / 1024 / 1024, total_size_after / 1024 / 1024, (1 - total_size_after / total_size_before) * 100) def compress_with_pikepdf(input_pdf: Path, output_pdf: Path) - bool: 如果 Ghostscript 失败使用 pikepdf 进行无损清理压缩。 try: import pikepdf with pikepdf.open(input_pdf) as pdf: pdf.save( output_pdf, compress_streamsTrue, object_stream_modepikepdf.ObjectStreamMode.generate, ) return output_pdf.exists() and output_pdf.stat().st_size 0 except Exception as exc: logger.error(pikepdf 兜底失败: %s, exc) return False def main(): parser argparse.ArgumentParser(description批量压缩 PDF 文件) parser.add_argument(--input, typePath, defaultPath(pdf_input), help输入 PDF 目录) parser.add_argument(--output, typePath, defaultPath(pdf_output), help输出 PDF 目录) parser.add_argument(--settings, typestr, defaultebook, choiceslist(SETTINGS_MAP.keys()), help压缩预设等级) parser.add_argument(--min-size-kb, typeint, default100, help小于该体积的文件跳过单位 KB) parser.add_argument(--skip-existing, actionstore_true, help输出目录已有同名文件时跳过) parser.add_argument(--fallback, actionstore_true, helpGhostscript 失败时使用 pikepdf 兜底) args parser.parse_args() # 日志配置同时输出到控制台和文件 log_dir Path(logs) log_dir.mkdir(exist_okTrue) log_file log_dir / fcompress_{time.strftime(%Y%m%d_%H%M%S)}.log logging.basicConfig( levellogging.INFO, format%(asctime)s [%(levelname)s] %(message)s, handlers[ logging.StreamHandler(), logging.FileHandler(log_file, encodingutf-8), ], ) settings_value SETTINGS_MAP[args.settings] batch_compress( input_dirargs.input, output_dirargs.output, settingssettings_value, min_size_kbargs.min_size_kb, skip_existingargs.skip_existing, use_pikepdf_fallbackargs.fallback, ) if __name__ __main__: main()这段代码中以下几个设计点值得注意find_ghostscript()自动识别不同系统上的 Ghostscript 命令名称避免 Windows 和 macOS/Linux 命令名不一致的问题。利用subprocess.run(capture_outputTrue, textTrue)捕获 Ghostscript 的标准输出和错误方便后续排错。输出路径使用input_pdf.relative_to(input_dir)保留原有目录层级适合多级文件夹批量处理。增加--min-size-kb参数避免对体积很小的文件做无意义压缩。增加--skip-existing参数重复运行脚本时不会重复处理已经生成的同名文件。日志写入logs目录文件名带时间戳方便审计。5.3 备选方案PyMuPDF 压缩如果某些 PDF 不需要 Ghostscript 那样激进的重采样可以单独写一个基于 PyMuPDF 的版本 另一个轻量方案使用 PyMuPDF 清理无用对象并重新压缩内容流。 文件路径pdf_batch_compress/compress_pymupdf.py from pathlib import Path import fitz def compress_with_pymupdf(input_pdf: Path, output_pdf: Path): doc fitz.open(input_pdf) # garbage4: 清除未引用的对象、去除重复对象 # deflateTrue: 重新压缩内容流 # cleanTrue: 清理并规范化 PDF 结构 doc.save(output_pdf, garbage4, deflateTrue, cleanTrue) size_before input_pdf.stat().st_size size_after output_pdf.stat().st_size print(f{input_pdf.name}: {size_before / 1024:.1f} KB - {size_after / 1024:.1f} KB) doc.close() if __name__ __main__: input_dir Path(pdf_input) output_dir Path(pdf_output) output_dir.mkdir(exist_okTrue) for pdf_path in input_dir.glob(*.pdf): out_path output_dir / pdf_path.name compress_with_pymupdf(pdf_path, out_path)PyMuPDF 胜在轻量不需要额外安装 Ghostscript适合 PDF 文件本身结构比较规范、压缩需求不是特别高的场景。但对图片密集型 PDF它的压缩率往往不如 Ghostscript 明显。5.4 运行与验证把需要压缩的 PDF 放入pdf_input然后执行python batch_pdf_compress.py \ --input pdf_input \ --output pdf_output \ --settings ebook \ --min-size-kb 100 \ --skip-existing \ --fallback预期日志输出类似于2025-01-15 10:00:01,123 [INFO] 共发现 5 个 PDF 文件 2025-01-15 10:00:02,456 [INFO] [1/5] 正在压缩: 扫描合同.pdf (15.2 MB) 2025-01-15 10:00:04,789 [INFO] 压缩后: 4.3 MB压缩率 71.7% 2025-01-15 10:00:05,012 [INFO] [2/5] 正在压缩: 产品手册.pdf (42.8 MB) 2025-01-15 10:00:07,345 [INFO] 压缩后: 18.1 MB压缩率 57.7%注意压缩率和具体文件内容强相关不同文件的体积缩减比例可能差异很大上面只是演示效果。运行完打开pdf_output里的文件随机抽几页检查文字是否可选、图片是否可接受再决定是否上调或下调压缩档位。6. 进阶参数与质量平衡6.1 四档 PDFSETTINGS 详解Ghostscript 的-dPDFSETTINGS参数有四个常用预设理解这些预设才能在不同场景下选对档位/screen最低质量适合电脑屏幕预览、快速预览。图片会被压到 72 DPI 左右体积最激进但打印效果通常不可接受。/ebook电子设备阅读约 150 DPI是多数办公文档的首选兼顾清晰度和体积。/printer面向打印机输出约 300 DPI适合需要打印但图片质量要求不极端的场景。/prepress面向印刷出版体积压缩有限适合需要保真输出的场景。如果你是财务或人力资源人员需要把一堆合同、发票压缩后归档/ebook足够。如果这些 PDF 之后可能被拿去打印、签章、作为正式材料建议用/printer避免因过度压缩影响法律效力或者可读性。6.2 手动控制图片分辨率预设档位不一定满足所有需求。某些扫描件只需要彩色 100 DPI、黑白 200 DPI但/ebook会统一处理。你也可以手动增加参数gs \ -sDEVICEpdfwrite \ -dPDFSETTINGS/ebook \ -dColorImageResolution120 \ -dGrayImageResolution150 \ -dMonoImageResolution200 \ -dColorImageDownsampleType/Bicubic \ -dGrayImageDownsampleType/Bicubic \ -dNOPAUSE \ -dBATCH \ -dQUIET \ -sOutputFileoutput.pdf \ input.pdf参数说明-dColorImageResolution彩色图片的目标分辨率。-dGrayImageResolution灰度图片的目标分辨率。-dMonoImageResolution黑白图片的目标分辨率。-dColorImageDownsampleType/Bicubic重采样算法双三次插值比平均采样能保留更多细节。使用手动分辨率参数时建议先取 3 到 5 个代表性文件做测试用肉眼确认文字清晰度再批量处理。6.3 处理加密 PDF 与元数据保留批量压缩时经常会遇到加密 PDF。这里的“加密”要区分两种打开密码打开文件就需要输入密码。权限密码可以打开但禁止打印、复制、编辑。对于有合法权限的文件在pikepdf.open()时传入密码即可import pikepdf # 打开密码模式下需要传 password with pikepdf.open(encrypted.pdf, password123456) as pdf: pdf.save( output.pdf, compress_streamsTrue, object_stream_modepikepdf.ObjectStreamMode.generate, )需要强调的是处理加密 PDF 必须在拥有合法授权的前提下进行。切勿绕过他人设置的访问控制或用这类技术处理没有权限的文件。如果希望压缩后保留基础元数据Ghostscript 默认会保留大部分文档信息。你也可以在脚本里追加-dPreserveMetadatatrue参数但要注意部分版本的实现差异。7. 常见问题与排查思路问题现象常见原因解决思路运行脚本时提示gs: command not foundGhostscript 未安装或不在 PATH 中安装 GhostscriptWindows 把安装目录加入 PATH或脚本里写绝对路径Windows 提示gswin64c 不是内部或外部命令安装时未勾选加入 PATH手动配置系统环境变量或使用shutil.which难以找到时直接改成绝对路径压缩后文件反而变大原 PDF 已经高度压缩Ghostscript 重新嵌入了字体或重采样效果不明显先统计原始 PDF 的类型改用compress_streamsTrue这类无损清理方案或降低 DPI压缩后字体变成方块或乱码字体未正确嵌入检查原 PDF 字体嵌入情况Ghostscript 参数增加-dEmbedAllFontstrue -dSubsetFontstrue压缩后图片模糊明显使用了/screen档位或 DPI 设置过低提升到/ebook或/printer减小重采样强度某个 PDF 直接压缩失败PDF 文件损坏、加密或结构异常用pikepdf尝试打开并修复或先转成标准 PDF 再压缩批量处理中途中断磁盘空间不足、权限不足清理磁盘确保输出目录可写使用日志定位最后处理到哪个文件输出文件包含多余空白页原 PDF 有空白页或扫描件包含空白页压缩前先做空白页检测或用 PDF 编辑工具删除空白页压缩后文本无法搜索原 PDF 本来就是扫描图片没有 OCR 文本层这类文件压缩前可以考虑加 OCR或保留原文件排查这类问题有一个通用套路先处理单文件再处理批量。先用命令行压缩单个 PDF观察是否成功失败则查看标准错误输出的末尾部分定位具体报错信息成功后再跑到脚本里排除“批量逻辑”和“单文件本身问题”两方面的原因。8. 最佳实践与工程建议8.1 保留原始文件压缩结果先输出到新目录批量压缩脚本默认把结果写入pdf_output不会覆盖pdf_input中的原始文件。这是一个非常重要的安全边界。在实际生产中建议不要一开始就原地覆盖文件而是先保持“输入目录”和“输出目录”分离等确认压缩效果、阅读体验、打印质量都符合预期后再由人工决定是否替换原文件。如果是需要长期运行的自动化流程还可以把“原始文件”和“压缩文件”之间的对应关系记录成 CSV包括文件名、大小、压缩率、时间戳方便审计。8.2 压缩前先做小样本验证无论你使用 Ghostscript、pikepdf 还是 PyMuPDF拿到一个新的 PDF 集合时都应该先抽 3 到 5 个代表性文件测试。代表性文件应该包含最小体积、最大体积、图片最多、文字最多的文件。确认压缩参数对这批文件有效之后再放开批量运行。这样做的原因很简单PDF 是高度异构的格式没有一种参数能通吃所有文件。只有通过小样本验证才能避免几百个文件处理完后才发现图片质量不可接受。8.3 记录日志确保可重复执行批量压缩脚本需要输出日志。我建议至少记录以下几点原始文件名和路径压缩前大小、压缩后大小、压缩率使用的 Ghostscript 参数处理是否成功失败时的错误信息。日志目录最好按天或者按时间戳归档防止多次运行相互覆盖。可重复执行是脚本工具与手工操作最大的区别。8.4 性能优化并行处理时的资源边界批量压缩大量 PDF 时如果机器 CPU 核心较多并行处理可以显著提速。但要注意Ghostscript 是 CPU 密集型进程如果同时启动十几个实例不仅 CPU 会占满磁盘 I/O 也会成为瓶颈反而可能拖慢整体速度甚至导致系统卡顿。一个相对稳妥的思路是先用串行脚本跑通流程统计每个文件的平均耗时在 CPU 核数允许的情况下再用concurrent.futures.ThreadPoolExecutor控制并发数比如设置为 2 到 4而不是无脑开满所有线程。8.5 隐私与合规边界很多 PDF 包含个人隐私、合同编号、身份证号、财务报表等信息。使用在线 PDF 压缩工具虽然方便但文件会被上传到第三方服务器存在泄密风险。对于敏感材料强烈建议本地脚本处理不要上传到不信任的在线平台。另外对加密 PDF、受限文档的压缩必须遵守合法授权和合规要求。如果没有处理权限不要尝试绕过限制也不要对他人资料做未授权操作。8.6 把压缩纳入归档流程从工程角度看PDF 压缩不应该是一次性的“补作业”而应该纳入归档流程。比如文件上传前自动压缩扫描件归档时统一使用/ebook档位每季度检查一次旧归档文件对未压缩的 PDF 执行批量压缩将压缩脚本和参数写入运维手册或项目文档保证后续接手的人能理解每个参数的作用。这样批量压缩就不再是一个临时脚本而是稳定可维护的工具。9. 总结与学习路线本文围绕“如何批量压缩 PDF 文档”这一需求讲解了 PDF 体积过大的原因、压缩的核心原理以及三种可行方案。其中最推荐的做法是“Python 脚本调用 Ghostscript”兼顾压缩率、批量处理能力和可维护性。脚本中包含了自动查找 Ghostscript、跳过小文件、跳过已存在文件、日志输出、pikepdf 兜底等设计你可以直接复制使用也可以按自己的目录结构微调。读完这篇文章你应该能够完成以下几件事判断一个 PDF 的体积来源是文本、图片还是混合型根据使用场景选择/screen、/ebook、/printer或/prepress四档压缩参数写出自己的批量压缩脚本并妥善处理日志和异常排查常见问题比如压缩后体积变大、字体乱码、工具找不到等。下一步如果你想继续深入建议学习三个方向一是用pikepdf做更精细的 PDF 对象级分析比如导出图片列表、统计每张图片分辨率二是结合 OCR 技术把扫描版 PDF 转换成可搜索文件同时压缩体积三是把这些脚本封装成带界面的小工具供团队里不熟悉命令行的同事使用。批量压缩 PDF 本质上就是一个“分析文件构成、选择合适参数、批量执行、验证结果”的工程问题。动手跑一次脚本比对压缩前后的文件质量和体积你会很快找到最适合自己业务场景的参数组合。如果本文对你有帮助可以先收藏备用后续压缩其他 PDF 时可以直接套用。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →