夜雨聆风学习资料网

ARTICLE · 1080410

EP06|PDF 转 Word:实测劝退 Stirling-PDF,我自建了一个 11MB 的服务

EP06|PDF 转 Word:实测劝退 Stirling-PDF,我自建了一个 11MB 的服务

NAS 全家桶 · 实战系列

需求特别朴素:把 PDF 报告转成能编辑的 Word。网上清一色推荐 Stirling-PDF,我也装了——然后在真实中文文档上翻车,最后自己搓了个 11MB 的微服务。这篇全是实测数据。

▲ 两个方案的实测对比

Stirling-PDF 的三宗罪(2.14.3 实测)

·中文 PDF 转 Word 全文逐句重复:它的转换链走 LibreOffice,把正文和文本框各导出一份。同一份 PDF:Stirling 抽出 19620 字符、2540 个 textbox;pdf2docx 抽出 4165 字符、0 个 textbox。三个不同来源的 PDF 全部复现

·接口有暗桩:/api/v1/convert/pdf/word 必须带 outputFormat=docx 参数,只传文件会返回 400 且响应体为空,日志里没有任何线索。查参数最快的方法:curl /v1/api-docs 翻 OpenAPI 定义

·吃内存:空载 926MB。在 6GB 总内存、swap 常年 900MB 的机器上,这是奢侈品

自建方案:pdf2docx 微服务

方案本身没有黑科技:Python 的 pdf2docx 库 + 一个裸二进制 HTTP 接口,本地构建镜像 pdf2docx-svc:latest,空载内存 11MB——是 Stirling 的 1/84。

从零复刻只要三步,部署物一共三个文件(/volume1/docker/pdf2docx/:Dockerfile、server.py、docker-compose.yml)。前两个全文如下,短到不需要解释:

# DockerfileFROM python:3.11-slimRUN pip install --no-cache-dir pdf2docx   # PyMuPDF/python-docx 都有 wheel,装得不慢WORKDIR /appCOPY server.py /app/server.pyENV PORT=8090ENV MAX_MB=120EXPOSE 8090CMD ["python", "-u", "server.py"]# docker-compose.yml 要点services:  pdf2docx:    build: .    image: pdf2docx-svc:latest    container_name: pdf2docx    restart: unless-stopped    ports:      - "8090:8090"    environment:      - PORT=8090      - MAX_MB=120          # 超限直接拒,防止大文件打爆内存    mem_limit: 1g           # 这台机器可用内存就 2.4G 左右    cpu_shares: 512         # ⚠️ 千万别写 cpus: —— 内核不支持 CFS 调度,容器直接起不来

· ① 建目录放三个文件 → ② docker compose up -d --build(首次构建两三分钟)→ ③ 拿一份小 PDF 跑下面的 curl 验证

# API 刻意做薄:不做 multipart,body 就是 PDF 字节流curl -sS --data-binary @报告.pdf \     -H 'Content-Type: application/pdf' \     http://10.0.0.x:8090/convert -o 报告.docx# 响应头 X-Cleaned-Numbers: 3   ← 本次自动清洗的坐标残留数

转换质量之外的增值是坐标数字清洗:pdf2docx 偶尔会把内部坐标值(长得像 -1079500 这种)当正文吐出来。服务在转完后自动清一遍——整段是 6 位以上纯数字的删段,run 级只清「负号 + 6 位数字」且不是段落唯一内容的;2024、1,234 这类正常数字一律保留。规则刻意保守,宁可漏放不可误杀。

💡 小贴士|Stirling-PDF 没删,容器留着但停着。它家强项是 OCR 和格式互转全家桶——需要 OCR 时 docker start 用完即停,别让这头 900MB 的内存巨兽常驻。

文档链路打通了,下一篇解决物理世界:EP07 · 打印机代理。

NAS 全家桶 · 实战系列 | 老姚的投资笔记 | EP06 / 11

相关学习资料