Word 简历批量转 PDF(LibreOffice 保真版):60 行脚本一次转完

· 喵窝资源铺

投递季最常见的死循环:招聘平台只收 PDF,你手里是几十份 .docx 简历,一个个「另存为 PDF」改到怀疑人生。本篇用 soffice --headless --convert-to pdf 批量转,走的是 LibreOffice 渲染引擎——字体、表格、分页和你在 Word 里看到的几乎一致,是「保真」路线;如果只要正文和表格内容、服务器上不方便装 LibreOffice,可以看纯 Python 版(python-docx + reportlab),两篇互为补充。

文中代码实跑验证,真实输出贴在下面,坑也是实跑踩出来的。

脚本(60 行)

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""Word简历批量转PDF:soffice --convert-to pdf,只扫顶层,
锁文件/非docx跳过,同名不覆盖"""
import os, sys, subprocess

SRC = sys.argv[1] if len(sys.argv) > 1 else "."
OUT = sys.argv[2] if len(sys.argv) > 2 else os.path.join(SRC, "pdf")
os.makedirs(OUT, exist_ok=True)
moved, skipped = [], []

for f in sorted(os.listdir(SRC)):
    p = os.path.join(SRC, f)
    if not os.path.isfile(p):
        continue                      # 子目录不递归,防输出目录套娃
    if f.startswith("~$"):
        skipped.append((f, "Office锁文件")); continue
    if not f.lower().endswith(".docx"):
        skipped.append((f, "非.docx")); continue
    dst = os.path.join(OUT, f[:-5] + ".pdf")
    if os.path.exists(dst):
        skipped.append((f, "目标PDF已存在,不覆盖")); continue
    # 一次转一个文件最稳(并发实例会抢同一 profile 互相踢)
    r = subprocess.run(
        ["soffice", "--headless", "--convert-to", "pdf",
         "--outdir", OUT, p],
        capture_output=True, text=True, timeout=120)
    if r.returncode == 0 and os.path.exists(dst):
        moved.append((f, os.path.basename(dst)))
    else:
        skipped.append((f, "转换失败: "
                        + (r.stderr or r.stdout).strip()[:80]))

print(f"共转换 {len(moved)} 个,跳过 {len(skipped)} 个")
for f, d in moved:   print(f"  [转出] {f} -> {d}")
for f, d in skipped: print(f"  [跳过] {f}: {d}")

实跑结果

测试集:5 份简历(中文 4 + 英文文件名 1)、1 个 说明.txt、1 个 Word 锁文件 ~$张三简历.docx、1 个子目录(里面还藏了份简历)、输出目录 pdf/ 就放在源目录里,且预先放了一份旧的假 张三简历.pdf(内容 "OLD"):

共转换 4 个,跳过 4 个
  [转出] Tom_Smith简历.docx -> Tom_Smith简历.pdf
  [转出] 李四简历.docx -> 李四简历.pdf
  [转出] 王五简历.docx -> 王五简历.pdf
  [转出] 赵六简历.docx -> 赵六简历.pdf
  [跳过] batch_docx2pdf.py: 非.docx
  [跳过] ~$张三简历.docx: Office锁文件
  [跳过] 张三简历.docx: 目标PDF已存在,不覆盖
  [跳过] 说明.txt: 非.docx

第二遍再跑:

共转换 0 个,跳过 8 个   (全部「目标PDF已存在,不覆盖」——幂等)

转出的 PDF 用 pdftotext 抽文本核对,标题/姓名/意向逐份对得上,中文字形正常。预置的假 张三简历.pdf(3 字节的 "OLD")全程原封未动。

实跑踩出的 4 个坑

  • 坑 1:soffice 对目标同名 PDF 是静默覆盖。故意放了个 3 字节假 PDF 再裸跑 soffice --convert-to,输出里轻飘飘一行 Overwriting: ...,旧文件直接没了、退出码 0。批量场景里上一批的成果可能被冲掉——所以脚本先查 exists 跳过并报告,不搞自动改名(文件悄悄变多对不上账更糟)。
  • 坑 2:--outdir 指到源目录本身,soffice 直接拒绝转换。实测报错罢工。所以输出目录要么独立、要么像本例的 pdf/ 子目录——反正脚本只扫顶层不递归,不会把自己的输出再吃进去。
  • 坑 3:并发跑多个 soffice 实例,第二个静默失败。同时转两个文件,一个成功一个啥都没说就不出了——它们抢同一个用户 profile,后来的实例把先发的踢掉。所以脚本一次只转一个、串行;几十份也就每份一秒左右,不值得为此上并发。真要提速,用 -env:UserInstallation=file:///tmp/lo_profile_N 给每个实例分独立 profile。
  • 坑 4:~$ 锁文件会被当正经文件转。Word 开着的文档旁边有个 ~$xxx.docx 临时文件,扔给 soffice 转出来是个垃圾 PDF。文件名开头判断 startswith("~$") 直接跳过。(和之前归档脚本踩的是同一个家族的坑:临时文件不在目录列表末尾,按扩展名过滤拦不住。)
  • 边界说明(如实)

  • 需要环境装有 LibreOffice(apt-get install libreoffice-writer,无界面也能跑);完全没有安装权限的服务器请用纯 Python 版。
  • 老 .doc 二进制格式:这条路线其实能转(LibreOffice 认得),但本脚本按扩展名只放行 .docx,要放行加一个条件即可。
  • 页眉页脚、艺术字等复杂元素有细微渲染差异;简历/合同这类常规排版实测一致。
  • 虚拟物品不退款政策在所有对外文案中一致。
  • 不想自己跑脚本?喵窝资源铺提供人工代跑+交付服务(miaowoo.900890.xyz):把你的 Word 文件打包发来,交付转换后的 PDF(逐份复核中文显示和表格数据)。由 AI 完成脚本与初验、人工复核后交付,9.9 元起。虚拟物品,交付后不退款,介意勿拍。

    ← 返回喵窝资源铺 · 相关:纯 Python 版 Word 批量转 PDF(不装 LibreOffice) · 相关:乱码文件批量转 UTF-8