在处理大型PDF文档翻译时,直接上传整份文件有时会遇到超时、内存占用高或部分页面格式异常的问题。一个实用的思路是:先把PDF按页拆分成小文件,逐个翻译,最后再把结果合并起来。这篇文章分享一个基于Python的完整流水线实现,代码可直接运行。
前言
我之前翻译过一份300多页的产品手册,直接上传整份PDF时遇到了两个问题:
- 翻译时间过长,HTTP连接超时;
- 中间某一页格式复杂,导致整份文档的排版都受影响。
后来改成"拆分-翻译-合并"的流水线方式,稳定性和成功率都明显提升。这个方案特别适合:
- 超过100页的大文档;
- 页面版式差异较大的混合文档;
- 需要部分页面单独处理的场景。
环境准备
bash
pip install pypdf requests
完整代码
python
import os
import time
import requests
from pathlib import Path
from pypdf import PdfReader, PdfWriter
UPLOAD_DIR = Path("uploads")
SPLIT_DIR = Path("split")
TRANS_DIR = Path("translated")
MERGE_DIR = Path("merged")
for d in [UPLOAD_DIR, SPLIT_DIR, TRANS_DIR, MERGE_DIR]:
d.mkdir(exist_ok=True)
API_URL = "https://api.example.com/translate"
API_KEY = "your_api_key"
def split_pdf(input_path: str, chunk_size: int = 10):
"""按chunk_size页拆分PDF"""
reader = PdfReader(input_path)
total = len(reader.pages)
chunks = []
for start in range(0, total, chunk_size):
writer = PdfWriter()
end = min(start + chunk_size, total)
for i in range(start, end):
writer.add_page(reader.pages[i])
chunk_path = SPLIT_DIR / f"chunk_{start+1}_{end}.pdf"
with open(chunk_path, "wb") as f:
writer.write(f)
chunks.append(str(chunk_path))
return chunks
def translate_pdf(pdf_path: str, source_lang="auto", target_lang="zh"):
"""调用翻译API翻译单个PDF"""
with open(pdf_path, "rb") as f:
resp = requests.post(
API_URL,
files={"file": f},
data={
"source_lang": source_lang,
"target_lang": target_lang,
"api_key": API_KEY,
},
timeout=120,
)
if resp.status_code != 200:
raise RuntimeError(f"Translation failed: {resp.text}")
# 假设API返回下载链接
result = resp.json()
download_url = result.get("download_url")
# 下载翻译后的文件
file_name = Path(pdf_path).stem + "_translated.pdf"
output_path = TRANS_DIR / file_name
r = requests.get(download_url, timeout=60)
with open(output_path, "wb") as f:
f.write(r.content)
return str(output_path)
def merge_pdfs(pdf_paths: list, output_path: str):
"""合并多个PDF文件"""
writer = PdfWriter()
for p in pdf_paths:
reader = PdfReader(p)
for page in reader.pages:
writer.add_page(page)
with open(output_path, "wb") as f:
writer.write(f)
def process_pdf(input_path: str, chunk_size: int = 10):
"""完整流水线:拆分 -> 翻译 -> 合并"""
print(f"[1/4] 开始拆分: {input_path}")
chunks = split_pdf(input_path, chunk_size)
print(f"[2/4] 拆分为 {len(chunks)} 个子文件")
translated = []
for idx, chunk in enumerate(chunks, 1):
print(f"[3/4] 正在翻译第 {idx}/{len(chunks)} 个子文件...")
try:
out = translate_pdf(chunk)
translated.append(out)
except Exception as e:
print(f"第 {idx} 个子文件翻译失败: {e}")
# 失败时保留原文,避免合并缺失
translated.append(chunk)
time.sleep(1)
output_name = MERGE_DIR / f"{Path(input_path).stem}_final.pdf"
print(f"[4/4] 合并结果到: {output_name}")
merge_pdfs(translated, str(output_name))
return str(output_name)
if __name__ == "__main__":
pdf_file = UPLOAD_DIR / "manual.pdf"
if not pdf_file.exists():
print(f"请把待翻译PDF放到: {pdf_file}")
else:
result = process_pdf(str(pdf_file), chunk_size=10)
print(f"完成: {result}")
代码说明
split_pdf:使用pypdf按指定页数拆分PDF,生成多个小文件。chunk_size可根据实际情况调整,通常10-20页一组比较均衡。
translate_pdf:调用翻译API,上传单个PDF并下载翻译后的文件。示例假设API返回download_url,实际接口请根据具体情况调整。
merge_pdfs:使用pypdf按顺序合并所有翻译后的子文件。
process_pdf:主流程,包含错误处理------如果某个子文件翻译失败,保留原文件继续合并,避免整份文档作废。
注意事项
-
拆分后的页眉页脚:如果原文页眉页脚包含页码,拆分翻译合并后页码可能不连续。可以在合并后重新生成页眉页脚,或者在上传时选择保留原页眉页脚的翻译模式。
-
跨页表格:如果表格跨页存在,拆分后可能出现表格被截断的情况。建议先检查文档结构,对跨页表格做合并处理。
-
批注和书签:pypdf默认不会保留书签大纲,如果文档有目录,合并后需要重新添加。
-
API调用频率:批量上传时注意控制频率,避免触发限流。示例中每次翻译后sleep 1秒,可根据接口限制调整。
优化方向
- 使用线程池并行翻译多个子文件,缩短总耗时;
- 引入任务队列(如Celery),支持断点续传;
- 对翻译失败的分片支持单独重试;
- 增加文件MD5校验,避免重复翻译。
总结
"拆分-翻译-合并"是一种务实的大文档处理策略,尤其适合几百页的PDF翻译场景。它不能完全替代整篇翻译,但在稳定性、失败容忍度和处理效率上都有明显优势。配合合适的翻译API,这条流水线可以无缝融入现有的文档处理系统中。
标签:PDF翻译、Python自动化、AI翻译、文档处理、效率工具