办公类工作里有一类需求频率极高,却经常让会一点 Python 的人卡住:PDF。你可以在 Excel 里用 openpyxl 逐个改单元格,在 Word 里用 python-docx 定位段落,但遇到 PDF 时,很多人的第一反应还是“打开文件、手动复制、另存为”。如果只是几份文件,手动处理尚可接受;一旦变成几十份扫描件、合同、说明书、报表,效率问题就会被无限放大。
如果只看表面,很多人会以为“办公自动化 + PDF”等同于“装一个能读 PDF 的库,然后像读 txt 一样把它读出来”。但实际处理过就会发现,情况要复杂得多:有的 PDF 提取文本之后没有空格,有的 PDF 提取出来是乱码,有的 PDF 用尽各种库都提取不到一个字,还有的转成 Word 之后版式彻底崩坏。
这篇文章想解决三个具体问题:第一,PDF 在办公自动化里为什么不像 Word、Excel 那么“听话”;第二,面对合并、拆分、提取文本、抽取图片、转 Word 这些高频需求时,应该选哪个 Python 库、怎么写完整代码;第三,遇上扫描版 PDF、加密 PDF、中文乱码 PDF 时,应该怎么判断问题,而不是盲目换库瞎试。
如果你已经掌握 Python 基础语法,正在从“会写脚本”走向“能解决实务”,这篇内容很适合作为办公自动化 PDF 方向的系统整理。下面会给出完整的可运行示例、环境搭建方式和问题排查清单,建议先收藏,再跟着代码实践。
1. 先把 PDF 当成“打印快照”,而不是“文档模型”
PDF 的全称是 Portable Document Format,常被称为便携式文档格式,由 Adobe 推出,后来成为国际标准化组织制定的开放标准。它最初要解决的问题是跨操作系统、跨软件、跨字体环境下保持版式一致。正是因为目标强调“打印出来什么样,在哪台设备上看都一样”,PDF 内部记录的并不是作者在编辑器里输入的“段落、标题、表格结构”,而是“这一页最终应该如何绘制”。
从技术角度看,PDF 页面里通常包含内容流(content stream),里面是一系列绘图指令,例如 BT/ET、Tj、TJ,配合字体对象、字形编号、坐标参数,告诉渲染引擎“在哪个位置,用哪个字形,绘出什么文字”。这种设计让 PDF 在展示层极其稳定,却也导致它不像 DOCX 那样有清晰的 paragraph 对象,也不像 XLSX 那样有行和列的结构可以轻易遍历。
因此,处理 PDF 办公自动化的第一课,不是去背某个库的 API,而是先建立一个认知:PDF 里的内容以“页面”和“图像绘制指令”的方式存在,处理需求必须先分层看。
从办公实务出发,PDF 大体可以分成两类,处理策略完全不同。
第一类是文本型 PDF,由 Word、LaTeX、专业排版软件导出,或者通过虚拟打印机生成。这类 PDF 内部真实包含文本内容,可以用代码提取文字,但由于生成工具不同,提取难度也有差异。
第二类是扫描版 PDF,本质上是一张或多张图片的集合,没有文本层。无论你用多强的文本提取工具,直接读取都会得到空字符串,常规做法是走 OCR 流程,先识别图片上的文字,再做后续处理。
这个区别解释了办公自动化里最常见的“诡异现象”:为什么同一个脚本处理 A 文件正常,处理 B 文件却什么都没有?大概率不是代码写错了,而是 B 文件根本没有文本层。
所以,办公自动化语境里的“PDF 了解”,真正含义不是了解文件格式的历史,而是了解一段真实业务里 PDF 的内容形态。每次拿到文件,先判断它是“文本型”还是“扫描型”,再决定调用哪一类库,后面才不会浪费时间。
2. Python PDF 处理库全景与选型思路
Python 处理 PDF 的生态比较分散,每个库各有侧重点。很多初学者犯的第一个错误,是试图用一个库完成所有 PDF 操作。实际上,不同库擅长的处理层级各有不同。
| 库 | 安装包名称 | 导入方式 | 适合的处理层级 | 典型用途 |
|---|---|---|---|---|
| pypdf | pypdf | from pypdf import PdfReader, PdfWriter | 页面层 | 合并、拆分、旋转、加密、解密、读取页数 |
| PyPDF2 | PyPDF2 | from PyPDF2 import PdfReader | 页面层 | 老项目常见,新项目建议优先考虑 pypdf |
| pdfplumber | pdfplumber | import pdfplumber | 文本与坐标层 | 提取文字、提取表格、获取文本坐标 |
| PyMuPDF | PyMuPDF | import fitz | 文本层与图像层 | 渲染页面为图片、抽取图片、按页取文本 |
| pdf2docx | pdf2docx | from pdf2docx import Converter | 排版重建层 | 将 PDF 视觉还原为 DOCX |
| pdf2image | pdf2image | from pdf2image import convert_from_path | 图像层 | 将每一页 PDF 渲染成 PNG/JPEG |
| reportlab | reportlab | from reportlab.pdfgen import canvas | PDF 生成层 | 程序化创建 PDF 文件 |
先解释一下最容易被绕晕的 pypdf 与 PyPDF2 关系。PyPDF2 是一个非常老牌的纯 Python PDF 库,后来社区维护重心转向了 pypdf 项目,两者 API 风格高度相似。为了减少长期项目里的维护风险,新代码建议以 pypdf 为准,不要在新项目里继续沿用 PyPDF2 旧接口。
pdfplumber 适合处理文本与表格提取。它的底层依赖 pdfminer.six,在解析字符坐标、线条、矩形方面做了不少封装,能从 PDF 页面中尽量还原文字顺序和表格边界。实际使用中,对由 Word 导出的简单表格效果最好,对复杂跨页表格则不一定能完全复原。
PyMuPDF 非常重要,只是它的导入名很容易让人迷惑:安装包叫 PyMuPDF,代码里却要写import fitz。这是因为 PyMuPDF 绑定的是底层 C 库 MuPDF,Python 侧保留了 fitz 这个历史模块名。它的优势是速度快,既能提取文本,也能把页面渲染成图片,还能抽取 PDF 内嵌图片资源,是办公自动化里的“多面手”。
pdf2docx 解决的场景比较特殊:用户希望把手里的 PDF 转成可编辑的 Word 文档。这里必须提前说明,它生成的 Word 并不是“从 PDF 恢复出原来的 Word 文件”,而是把 PDF 的视觉排版重新映射成 DOCX 的段落、表格与图片。版式接近,但编辑还原程度有限。
选型时,可以用一句判断概括:按“页”操作,用 pypdf;按“文字和表格”研究,用 pdfplumber;按“图片和渲染”处理,用 PyMuPDF;想保留近似排版转 Word,用 pdf2docx。先确定你要操作的内容层,再去选库,比记住一大堆安装命令更有意义。
3. 环境准备与测试文件生成
开始写代码之前,先建立一个干净实验目录,避免把测试文件散落得到处都是。本文示例采用如下目录结构:
pdf-office-demo/ ├── .venv/ ├── sample_files/ │ ├── input/ │ ├── output/ │ └── logs/ ├── make_test_pdf.py ├── merge_pdfs.py ├── split_pdf.py ├── extract_text_and_archive.py ├── extract_images.py └── pdf_to_word.py建议在项目目录里创建 Python 虚拟环境。macOS 或 Linux 使用以下命令:
mkdir pdf-office-demo cd pdf-office-demo python3 -m venv .venv source .venv/bin/activateWindows 下命令稍有不同:
mkdir pdf-office-demo cd pdf-office-demo python -m venv .venv .venv\Scripts\activate激活虚拟环境后,安装本文需要的依赖。核心依赖是 pypdf、pdfplumber、PyMuPDF。pdf2docx 依赖较多,如果只是为了学习,可以先不装;但如果需要跑 PDF 转 Word 示例,就一起安装。
pip install -U pypdf pdfplumber PyMuPDF pdf2docx reportlab安装完成后,可以执行一行命令快速确认关键库可以正常导入:
python -c "import pypdf, fitz, pdfplumber; print('ready')"如果没有报错,说明环境就绪。注意,这里导入的是fitz而不是pymupdf,这是新手最容易踩的坑之一。
接下来需要生成一批测试 PDF。真实业务里 PDF 通常来自同事或系统导出,但为了可以稳定复现示例,建议先用 reportlab 生成两个带文本的 PDF 文件。下面的脚本会在sample_files/input下创建invoice_001.pdf和invoice_002.pdf。
# make_test_pdf.py from pathlib import Path from reportlab.lib.pagesizes import A4 from reportlab.pdfgen import canvas OUTPUT_DIR = Path("sample_files") / "input" def make_demo_pdf(filename: str, title: str, invoice_number: str): OUTPUT_DIR.mkdir(parents=True, exist_ok=True) file_path = OUTPUT_DIR / filename c = canvas.Canvas(str(file_path), pagesize=A4) c.setFont("Helvetica", 18) c.drawString(72, 800, title) c.setFont("Helvetica", 12) c.drawString(72, 760, f"Invoice No.: {invoice_number}") c.drawString(72, 740, "Item: Python Office Automation Demo") c.drawString(72, 720, "This PDF is generated by reportlab.") c.showPage() c.setFont("Helvetica", 12) c.drawString(72, 800, "This is the second page.") c.drawString(72, 780, f"File name: {filename}") c.showPage() c.save() print(f"[INFO] generate {file_path}") if __name__ == "__main__": make_demo_pdf("invoice_001.pdf", "Demo Invoice 001", "INV-2025-001") make_demo_pdf("invoice_002.pdf", "Demo Invoice 002", "INV-2025-002")运行方式:
python make_test_pdf.py这里刻意使用英文文本生成测试文件,是因为 reportlab 在未注册中文字体的情况下,用默认 Helvetica 绘制中文会出现字形问题。实际业务中,你可以用 Word 或 WPS 另存为 PDF 来生成一份中文测试文件,后文所有中文提取逻辑都是通用的,核心思路不受字体语言影响。
4. 批量合并 PDF:pypdf 实现
合并 PDF 是最常见的办公自动化需求之一。典型场景包括:月底把多份扫描合同按客户汇总成一份,提交系统前把多个附件拼接成一个 PDF,把分散的项目材料合并后发给外部协作方。
pypdf 的用法很直观:用PdfReader逐个读取源文件,再通过PdfWriter把每一页添加到输出文件里。下面是完整脚本:
# merge_pdfs.py from pathlib import Path from pypdf import PdfReader, PdfWriter INPUT_DIR = Path("sample_files") / "input" OUTPUT_FILE = Path("sample_files") / "output" / "merged.pdf" def merge_pdfs(input_dir: Path, output_file: Path) -> None: pdf_files = sorted(input_dir.glob("*.pdf")) if not pdf_files: print("[WARN] input directory does not contain any pdf files") return writer = PdfWriter() for file_path in pdf_files: reader = PdfReader(str(file_path)) page_count = len(reader.pages) for page in reader.pages: writer.add_page(page) print(f"[INFO] {file_path.name}: {page_count} pages") output_file.parent.mkdir(parents=True, exist_ok=True) with output_file.open("wb") as fp: writer.write(fp) print(f"[INFO] merged pdf saved to {output_file}, total pages: {len(writer.pages)}") if __name__ == "__main__": merge_pdfs(INPUT_DIR, OUTPUT_FILE)运行脚本:
python merge_pdfs.py在这个示例里,有两个关键点需要理解。第一,pdf_files = sorted(input_dir.glob("*.pdf"))只是按字符串顺序排序,如果文件名是invoice_2.pdf和invoice_10.pdf,字符串排序会把invoice_10.pdf排在前面。真实业务中文件顺序通常有业务含义,建议在文件名里用零填充,例如invoice_002.pdf,或者实现自然排序函数。
第二,reader.pages在没有特殊加密保护时可以直接访问和遍历,但使用完PdfWriter后,代码并没有手动调用writer.close()。write会把文件内容写入,程序结束后对象自动释放。在脚本型任务里这是可行的,若在服务端长期运行,则建议在finally块中释放资源。
批量合并的进阶场景是按业务编号分组。例如文件名包含客户号时,可以提取规则后把同一客户的文件合并到一个 PDF 中,代码结构与上面类似,只是需要先把文件分组再逐组调用合并函数。
5. 按页码范围拆分 PDF:pypdf 实现
拆分 PDF 也经常出现在办公自动化中:一份 20 页的合同扫描件只需要把签章页发给法务,或者一本手册需要按章节拆成多个文件发给不同部门。
下面的split_pdf_pages函数接收源文件和起止页码,逻辑是根据页码范围创建新文件。注意,用户在业务口语里说的“第 1 页到第 2 页”是自然页码,从 1 开始;而 Pypdf 内部索引从 0 开始,所以读取页的时候要做start - 1的转换。
# split_pdf.py from pathlib import Path from pypdf import PdfReader, PdfWriter INPUT_FILE = Path("sample_files") / "input" / "invoice_001.pdf" OUTPUT_FILE = Path("sample_files") / "output" / "invoice_001_p2_3.pdf" def split_pdf_pages(pdf_path: Path, start: int, end: int, output_file: Path) -> None: reader = PdfReader(str(pdf_path)) total = len(reader.pages) if not (1 <= start <= end <= total): raise ValueError( f"invalid range: start={start}, end={end}, total={total}" ) writer = PdfWriter() for idx in range(start - 1, end): writer.add_page(reader.pages[idx]) output_file.parent.mkdir(parents=True, exist_ok=True) with output_file.open("wb") as fp: writer.write(fp) print(f"[INFO] pages {start}-{end} saved to {output_file}") if __name__ == "__main__": split_pdf_pages(INPUT_FILE, 2, 2, OUTPUT_FILE)运行:
python split_pdf.py这段代码中有一个值得留意的设计:先读取total,再用if not (1 <= start <= end <= total)做参数校验。真实办公脚本里,用户输入的页码范围经常出错,比如开始页大于结束页,或者结束页超过文件总页数。提前校验能让问题在写入文件之前暴露,而不是等到生成一个空 PDF 或异常中断后才开始排查。
如果想循环拆分一个文件,比如每 5 页拆成一个小文件,只需要在外面套一个for start in range(1, total + 1, 5)循环。此时建议在输出文件名中包含页码范围,避免多个输出文件相互覆盖。
6. 批量提取 PDF 文本并按关键词自动归档
文本提取是办公自动化的核心需求。例如财务需要从一堆 PDF 中找出所有发票号,行政需要把合同按客户名称归档,研发需要批量搜索产品手册里的关键字。要完成这类需求,通常分两步:先把 PDF 中的文字提取成普通字符串,再用正则或关键词做匹配。
pdfplumber 提取文本的写法和 pypdf 不同,它打开文档后直接遍历页面列表,页面对象有extract_text()方法。需要注意,extract_text()对没有文本层的扫描版 PDF 会返回None或空字符串,所以代码里建议用or ""做兜底。
# extract_text_and_archive.py import shutil from pathlib import Path import pdfplumber INPUT_DIR = Path("sample_files") / "input" OUTPUT_DIR = Path("sample_files") / "output" / "archived" KEYWORDS = ["INV-2025", "Invoice"] def extract_text_from_pdf(pdf_path: Path) -> str: text_parts = [] with pdfplumber.open(str(pdf_path)) as pdf: for page in pdf.pages: page_text = page.extract_text() or "" text_parts.append(page_text) return "\n".join(text_parts) def archive_by_keywords(input_dir: Path, output_dir: Path, keywords: list[str]) -> None: if not input_dir.exists(): print(f"[WARN] {input_dir} does not exist") return for pdf_file in input_dir.glob("*.pdf"): text = extract_text_from_pdf(pdf_file) matched_keywords = [] lowered_text = text.lower() for keyword in keywords: if keyword.lower() in lowered_text: matched_keywords.append(keyword) if not matched_keywords: print(f"[INFO] {pdf_file.name}: no keyword matched") continue target_dir = output_dir / "-".join(matched_keywords) target_dir.mkdir(parents=True, exist_ok=True) target_file = target_dir / pdf_file.name shutil.copy2(pdf_file, target_file) print( f"[INFO] {pdf_file.name}: matched {matched_keywords}, " f"copied to {target_file}" ) if __name__ == "__main__": archive_by_keywords(INPUT_DIR, OUTPUT_DIR, KEYWORDS)运行方式:
python extract_text_and_archive.py在实际业务里,关键词匹配往往不是“整词是否出现”,而是需要按规则提取字段。例如要从文本中提取INV-2025-001这样的编号,更稳妥的做法是使用正则表达式。
import re text = extract_text_from_pdf(Path("your_file.pdf")) pattern = re.compile(r"(INV-\d{4}-\d{3})") matches = pattern.findall(text) print(matches)这里真正容易踩坑的地方在于:PDF 中的文字可能是按坐标片段存储的,同一个单词可能被拆成多个文本块,或者行尾含有不必要的换行。pdfplumber 已经做了不少优化,但面对复杂排版时仍建议先把提取出的文本打印到控制台或文件中观察格式,再写匹配规则。
另外要提醒一点,关键词自动归档虽然能显著提高效率,但在处理合同、发票、个人证件等材料时,必须先确认自己有合法处理权限。自动化脚本本身没有判断能力,操作者的合规边界才是底线。
7. 从 PDF 批量抽取图片
除了文本,PDF 中的图片也常需要抽取。典型场景包括:从设计效果图 PDF 中挑出素材图,从产品说明书里导出流程截图,从历史报告中找回丢失的配图原图。
PyMuPDF 是目前处理这类需求最高效的选择。它的page.get_images(full=True)可以获取页面引用的图像资源列表,列表里每个元素包含图片对象的 xref 编号。拿到 xref 后,可以使用doc.extract_image(xref)获取图片的原始二进制数据和扩展名。
# extract_images.py from pathlib import Path import fitz INPUT_FILE = Path("sample_files") / "input" / "invoice_001.pdf" OUTPUT_DIR = Path("sample_files") / "output" / "extracted_images" def extract_images(pdf_path: Path, output_dir: Path) -> None: output_dir.mkdir(parents=True, exist_ok=True) doc = fitz.open(str(pdf_path)) try: for page_index, page in enumerate(doc): image_list = page.get_images(full=True) for img_index, image_info in enumerate(image_list): xref = image_info[0] base_image = doc.extract_image(xref) image_bytes = base_image["image"] ext = base_image["ext"] # 过滤过小图片,通常是 logo、图标或背景纹理 if len(image_bytes) < 1024: continue stem = pdf_path.stem filename = f"{stem}_page{page_index + 1}_{img_index + 1}.{ext}" target_file = output_dir / filename target_file.write_bytes(image_bytes) print( f"[INFO] extracted {filename}, " f"size={len(image_bytes)} bytes" ) finally: doc.close() if __name__ == "__main__": extract_images(INPUT_FILE, OUTPUT_DIR)运行:
python extract_images.py这里有一个非常实用的细节:image_info[0]是 xref,也就是 PDF 内部的间接对象编号。同一个图片可能会被多个页面引用,直接extract_image会重复导出同一张图。如果业务上需要每张图只导出一次,可以在遍历外层维护一个seen_xrefs集合,遇到重复 xref 就跳过。
还有一个常见情况:有些 PDF 里的图片其实不是内嵌图片,而是页面绘制出来的矢量图形。这种情况下get_images()可能返回空列表,或者只找到少量图片资源。如果你想得到“肉眼看到的完整截图”,应该改用页面渲染成图片的方式,也就是把整页 PDF 转成 PNG。PyMuPDF 的page.get_pixmap()是完成这件事的常用 API,办公场景中更适合用来“把某页发给别人确认”。
8. PDF 转 Word 的参考实现与效果边界
PDF 转 Word 是搜索热度很高、但被误解也最多的需求。很多人希望像“PDF 转回原版 Word”一样完美还原,但从技术上要理解:PDF 本来就不存储可编辑的段落结构,转 Word 本质是“从可视化结果反向重建文档结构”,必然存在偏差。
pdf2docx 库的底层依赖 PyMuPDF 解析页面布局,再通过 python-docx 构造新的 DOCX 内容,对段落、表格、图片会做近似还原。基本代码如下:
# pdf_to_word.py from pathlib import Path from pdf2docx import Converter INPUT_FILE = Path("sample_files") / "input" / "invoice_001.pdf" OUTPUT_FILE = Path("sample_files") / "output" / "invoice_001.docx" def pdf_to_word(pdf_path: Path, docx_path: Path) -> None: docx_path.parent.mkdir(parents=True, exist_ok=True) cv = Converter(str(pdf_path)) try: cv.convert(str(docx_path)) print(f"[INFO] converted {pdf_path.name} to {docx_path}") finally: cv.close() if __name__ == "__main__": pdf_to_word(INPUT_FILE, OUTPUT_FILE)运行:
python pdf_to_word.py运行完成之后,输出目录会出现invoice_001.docx文件。用 Word 或 WPS 打开后,你会看到文本内容大体可以编辑,但页面边距、字体段落、复杂表格可能与原始 PDF 略有差别。对跨页表格、分栏排版、艺术字、特殊字体嵌入等情况,偏差会更明显。
因此,在生产环境中做一个重要判断:如果用户只是想偶尔编辑一次,转 Word 是可行的;如果用户意图是把 PDF 内容纳入自动化流程做后续字段处理,建议优先提取文本而不是转 Word。转 Word 适合“人要再编辑”的场景,不适合“程序要批量消费数据”的场景。
如果扫描版 PDF 本身没有文本层,直接转 Word 得到的往往是若干页图片粘贴在文档里,文字依然无法编辑。此时应该先走 OCR,把图片识别成文字,再根据业务需求生成新的 Word 内容。OCR 方案属于另一个专题,这里先给一个判断方向:需要离线轻量方案可以考虑 Tesseract,需要识别中文表格可以考虑国内常用OCR组件或云服务,但要注意相关授权与数据安全要求。
9. 运行结果与效果验证
代码写完后,不能只看“没有报错”就认为任务完成。办公自动化脚本的验证标准应该是:输出文件存在、内容正确、文件名符合预期、重复执行不会出错。
按照前面的顺序依次运行:
python make_test_pdf.py python merge_pdfs.py python split_pdf.py python extract_text_and_archive.py python extract_images.py python pdf_to_word.py预期结果如下:
make_test_pdf.py在sample_files/input下生成两个 PDF,每个 PDF 有两页。merge_pdfs.py在sample_files/output下生成merged.pdf,一共 4 页。split_pdf.py从invoice_001.pdf中抽出第 2 页,生成单页文件invoice_001_p2_3.pdf。extract_text_and_archive.py会匹配到INV-2025和Invoice两个关键词,并把两个 PDF 复制到output/archived/INV-2025-Invoice目录。extract_images.py默认测试 PDF 中可能不含超过 1 KB 的内嵌图片,所以控制台可能提示没有抽取到图片。建议用含真实截图的 PDF 测试这个脚本。pdf_to_word.py生成invoice_001.docx。
如果脚本中途出现问题,第一件事不是去改代码,而是先确认 PDF 本身是否有文本层。判断方法如下:
import fitz doc = fitz.open("your_file.pdf") first_page = doc[0] text = first_page.get_text().strip() if text: print("这个页面包含文本层,前 50 个字符是:", text[:50]) else: print("这个页面大概率是扫描版 PDF,没有文本层") doc.close()这段判断逻辑可以放在任何 PDF 批处理脚本的最前面。如果页面没有文本层,后续的文本提取和转 Word 都会失败,先检查这个前提能节省大量调试时间。
10. 常见问题与排查思路
通过长期处理 PDF 办公自动化,你会发现大多数问题都出在对 PDF 内容形态的误判上,而不是 Python 语法。下面整理几个高频问题:
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
安装 PyMuPDF 后import fitz失败 | 混淆了安装包名和导入名 | 执行pip show pymupdf | 安装PyMuPDF,代码导入fitz |
调用PdfFileReader报错 | 使用了 PyPDF2 旧版 API 或导入 pypdf 后仍沿用旧写法 | 查看异常堆栈中的类名 | 新代码统一使用PdfReader、PdfWriter |
extract_text()返回空字符串 | PDF 是扫描版,没有文本层 | 用 PyMuPDF 的get_text()验证 | 走 OCR,而不是继续更换文本提取库 |
| 提取的中文乱码或丢字 | PDF 字体使用子集嵌入,或文本映射特殊 | 将同一页分别交给 pdfplumber、PyMuPDF 提取对比 | 优先尝试 PyMuPDF;仍乱码可尝试渲染页面后做 OCR |
| 合并后 PDF 文件很大 | 源文件包含大量图片和字体资源 | 检查单个源文件大小 | 按需压缩图片或评估是否需要合并全部内容 |
| pdf2docx 转出的 Word 中表格丢失 | 原 PDF 表格是绘图线条,无语义结构 | 对比原 PDF 与 Word 输出 | 接受近似结果;表格结构化需求改用表格提取 |
| 程序日志显示成功但 output 没有文件 | 输出目录与脚本运行目录不一致 | 打印Path.cwd()和输出绝对路径 | 工程中使用绝对路径或基于项目根目录拼接 |
仔细看这几个问题,会发现一个共性:解决方案不是“记住更多 API”,而是增加前置探测步骤。批量脚本在执行主逻辑前,先检查目录是否存在、文件是否有文本层、输出目录是否可写,就能提前拦截大多数失败。
11. 最佳实践与工程建议
如果你的目标不仅是跑通本文示例,而是把 PDF 处理真正沉淀到日常办公流程,下面几条工程建议可以直接用。
第一,合理组织目录结构。不要把输入、输出、日志混在同一个文件夹里。建议使用input/、output/、logs/三个目录,脚本运行前创建目录