手把手教你用Python搭建零成本PDF文档自动翻译流水线

前言

最近在团队里做了一个小工具:用Python自动读取PDF,调用在线翻译服务,再把翻译结果整理好输出。整个过程零成本、全自动,省掉了手动复制粘贴和格式调整的麻烦。

这篇文章把完整方案分享出来,包括代码、踩坑点和优化思路。核心思路是用Python做自动化调度,借助PDFTranslator这类免费在线翻译工具完成实际的翻译任务。

适用场景

  • 需要批量处理英文PDF文档的开发团队
  • 做技术文档翻译的技术写作者
  • 想搭建自动化翻译管道的个人开发者

环境准备

  • Python 3.10+
  • 依赖:pip install openpyxl requests python-docx pdfplumber
pip install openpyxl requests python-docx pdfplumber

整体架构

PDF文件 → Python调度器 → 在线翻译服务 → 翻译结果 → 文件输出
                ↓
          翻译记录写入Excel

三个核心模块:

  1. 文件管理模块:扫描目录、文件去重、状态跟踪
  2. 翻译调度模块:调用在线翻译服务、轮询结果
  3. 结果处理模块:下载翻译文件、整理输出、更新记录

实现步骤

Step 1: 文件扫描与管理

首先需要扫描指定目录中的PDF文件,记录文件信息和翻译状态。

import os
import json
from datetime import datetime
from pathlib import Path


def scan_pdf_files(directory: str) -> list:
    """扫描目录中的所有PDF文件
    
    Args:
        directory: 要扫描的目录路径
        
    Returns:
        PDF文件信息列表,包含路径、大小、修改时间
    """
    pdf_files = []
    pdf_dir = Path(directory)
    
    for file_path in pdf_dir.glob("**/*.pdf"):
        file_stat = file_path.stat()
        pdf_files.append({
            "path": str(file_path),
            "name": file_path.name,
            "size_mb": round(file_stat.st_size / (1024 * 1024), 2),
            "modified": datetime.fromtimestamp(file_stat.st_mtime).isoformat(),
            "status": "pending"  # pending / translating / done / failed
        })
    
    return sorted(pdf_files, key=lambda x: x["name"])


def save_translation_log(files: list, log_path: str):
    """将文件状态保存到JSON日志
    
    Args:
        files: 文件信息列表
        log_path: 日志文件路径
    """
    with open(log_path, "w", encoding="utf-8") as f:
        json.dump(files, f, ensure_ascii=False, indent=2)
    print(f"[INFO] 日志已保存: {log_path}, 共 {len(files)} 个文件")

Step 2: 翻译服务调度器

在线翻译服务的核心操作流程:上传PDF → 选择语言 → 等待翻译完成 → 下载结果。

import time
import requests


class PDFTranslationScheduler:
    """PDF翻译任务调度器
    
    负责管理翻译任务队列,调用在线翻译服务接口
    """
    
    def __init__(self, service_url: str = "https://pdftranslator.org"):
        """初始化调度器
        
        Args:
            service_url: 翻译服务的URL
        """
        self.service_url = service_url
        self.session = requests.Session()
        self.session.headers.update({
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
                          "AppleWebKit/537.36"
        })
    
    def submit_task(self, file_path: str, source_lang: str = "auto",
                    target_lang: str = "zh") -> dict:
        """提交翻译任务
        
        Args:
            file_path: PDF文件路径
            source_lang: 源语言(auto为自动检测)
            target_lang: 目标语言
            
        Returns:
            任务信息,包含任务ID和状态
        """
        file_size_mb = os.path.getsize(file_path) / (1024 * 1024)
        
        if file_size_mb > 20:
            return {
                "success": False,
                "error": f"文件大小 {file_size_mb:.1f}MB 超出20MB限制",
                "file": file_path
            }
        
        # 注:实际API调用需参考具体服务的接口文档
        # 这里展示的是调度逻辑框架
        task_info = {
            "file_path": file_path,
            "file_size_mb": round(file_size_mb, 2),
            "source_lang": source_lang,
            "target_lang": target_lang,
            "submitted_at": datetime.now().isoformat(),
            "status": "submitted"
        }
        
        print(f"[INFO] 任务已提交: {Path(file_path).name} "
              f"({file_size_mb:.1f}MB) → {target_lang}")
        
        return {"success": True, "task": task_info}
    
    def wait_for_completion(self, task_id: str,
                            timeout: int = 600) -> dict:
        """等待翻译任务完成(轮询模式)
        
        Args:
            task_id: 任务ID
            timeout: 超时时间(秒),默认10分钟
            
        Returns:
            翻译结果
        """
        start_time = time.time()
        poll_interval = 5  # 每5秒轮询一次
        
        while time.time() - start_time < timeout:
            # 这里应该是查询翻译状态的API调用
            time.sleep(poll_interval)
            elapsed = int(time.time() - start_time)
            print(f"[INFO] 等待翻译完成... 已等待 {elapsed}秒")
        
        return {"success": False, "error": "翻译超时"}


# 使用示例
if __name__ == "__main__":
    scheduler = PDFTranslationScheduler()
    
    # 扫描PDF文件
    pdf_files = scan_pdf_files("./待翻译文档")
    print(f"发现 {len(pdf_files)} 个PDF文件")
    
    # 提交翻译任务
    for pdf in pdf_files:
        result = scheduler.submit_task(pdf["path"], target_lang="zh")
        if result["success"]:
            print(f"✓ {pdf['name']} 已提交")
        else:
            print(f"✗ {pdf['name']}: {result['error']}")

Step 3: 翻译记录管理

用Excel记录所有翻译任务,方便追踪和回溯。

import openpyxl
from openpyxl.styles import Font, PatternFill, Alignment


def create_translation_log(excel_path: str):
    """创建翻译任务记录表
    
    Args:
        excel_path: Excel文件路径
    """
    wb = openpyxl.Workbook()
    ws = wb.active
    ws.title = "翻译记录"
    
    # 表头
    headers = ["文件名", "文件大小(MB)", "源语言", "目标语言",
               "提交时间", "完成时间", "耗时(秒)", "状态", "输出路径", "备注"]
    
    # 设置表头样式
    header_font = Font(bold=True, color="FFFFFF", size=11)
    header_fill = PatternFill(start_color="4472C4",
                              end_color="4472C4", fill_type="solid")
    
    for col, header in enumerate(headers, 1):
        cell = ws.cell(row=1, column=col, value=header)
        cell.font = header_font
        cell.fill = header_fill
        cell.alignment = Alignment(horizontal="center")
    
    # 设置列宽
    col_widths = [35, 12, 10, 10, 20, 20, 10, 12, 40, 30]
    for col, width in enumerate(col_widths, 1):
        ws.column_dimensions[openpyxl.utils.get_column_letter(col)].width = width
    
    wb.save(excel_path)
    print(f"[INFO] 翻译记录表已创建: {excel_path}")


def add_translation_record(excel_path: str, record: dict):
    """添加一条翻译记录
    
    Args:
        excel_path: Excel文件路径
        record: 翻译记录字典
    """
    wb = openpyxl.load_workbook(excel_path)
    ws = wb["翻译记录"]
    
    row = ws.max_row + 1
    fields = ["name", "size_mb", "source_lang", "target_lang",
              "submitted_at", "completed_at", "duration_sec",
              "status", "output_path", "note"]
    
    for col, field in enumerate(fields, 1):
        ws.cell(row=row, column=col, value=record.get(field, ""))
    
    wb.save(excel_path)
    print(f"[INFO] 翻译记录已添加: {record.get('name', 'Unknown')}")


# 创建示例记录表
create_translation_log("./翻译任务记录.xlsx")

Step 4: 主流程整合

将所有模块整合为一个完整的自动化脚本。

import argparse
import sys


def main():
    """主流程:PDF翻译自动化流水线"""
    parser = argparse.ArgumentParser(
        description="PDF文档自动翻译流水线")
    parser.add_argument("--input-dir", required=True,
                        help="待翻译PDF文件目录")
    parser.add_argument("--output-dir", default="./翻译结果",
                        help="翻译结果输出目录")
    parser.add_argument("--target-lang", default="zh",
                        help="目标语言代码")
    parser.add_argument("--log-excel", default="./翻译任务记录.xlsx",
                        help="翻译记录Excel路径")
    
    args = parser.parse_args()
    
    # 1. 初始化
    print("=" * 50)
    print("PDF翻译自动化流水线启动")
    print(f"输入目录: {args.input_dir}")
    print(f"输出目录: {args.output_dir}")
    print(f"目标语言: {args.target_lang}")
    print("=" * 50)
    
    # 2. 确保输出目录存在
    os.makedirs(args.output_dir, exist_ok=True)
    
    # 3. 确保Excel记录表存在
    if not os.path.exists(args.log_excel):
        create_translation_log(args.log_excel)
    
    # 4. 扫描文件
    pdf_files = scan_pdf_files(args.input_dir)
    pending = [f for f in pdf_files if f["status"] == "pending"]
    
    if not pending:
        print("[INFO] 没有待翻译的文件")
        return
    
    print(f"\n[INFO] 待翻译文件: {len(pending)} 个")
    for pdf in pending:
        print(f"  - {pdf['name']} ({pdf['size_mb']}MB)")
    
    # 5. 启动翻译调度器
    scheduler = PDFTranslationScheduler()
    
    # 6. 逐文件提交翻译任务
    success_count = 0
    fail_count = 0
    
    for pdf in pending:
        print(f"\n--- 处理: {pdf['name']} ---")
        
        try:
            # 提交任务
            result = scheduler.submit_task(
                pdf["path"],
                target_lang=args.target_lang
            )
            
            if result["success"]:
                success_count += 1
                print(f"[OK] {pdf['name']} 提交成功")
                
                # 记录到Excel
                add_translation_record(args.log_excel, {
                    "name": pdf["name"],
                    "size_mb": pdf["size_mb"],
                    "target_lang": args.target_lang,
                    "submitted_at": datetime.now().isoformat(),
                    "status": "submitted"
                })
            else:
                fail_count += 1
                print(f"[FAIL] {pdf['name']}: {result.get('error')}")
                
        except Exception as e:
            fail_count += 1
            print(f"[ERROR] {pdf['name']}: {str(e)}")
    
    # 7. 输出汇总
    print("\n" + "=" * 50)
    print(f"处理完成: 成功 {success_count}, 失败 {fail_count}")
    print(f"共处理 {success_count + fail_count} 个文件")
    print("=" * 50)


if __name__ == "__main__":
    main()

完整代码

以上所有代码已经内嵌在对应的步骤中,直接复制到 .py 文件中即可运行。

运行效果

python pdf_translation_pipeline.py --input-dir ./待翻译文档 --target-lang zh

运行后会:

  1. 自动扫描 ./待翻译文档 中的PDF文件
  2. 逐个提交到在线翻译服务
  3. 将处理记录写入 翻译任务记录.xlsx
  4. 在终端输出实时进度

优化建议

实际使用中,根据场景调整以下参数:

  1. 文件大小阈值:PDFTranslator 最大支持 20MB,在代码中做了校验,可根据实际服务调整
  2. 超时时间:大文件翻译可能需要更长时间,建议 timeout 设为 600 秒以上
  3. 并发处理:如果有大量文件,可以考虑用 concurrent.futures 实现多文件并行提交
  4. 错误重试:网络不稳定时加 retry 机制,提高成功率

总结

这套方案的核心价值在于:用一个调度脚本把"手动翻译PDF"变成了"自动翻译PDF"。虽然实际的翻译能力依赖在线服务,但自动化调度本身就能省下大量重复操作的时间。

适合需要批量处理PDF翻译的开发团队或技术写作者使用。代码可以根据具体需求扩展——比如加上Webhook通知、翻译质量评分、或者对接内部翻译系统。

如果你对某个模块的实现有疑问,欢迎在评论区交流。

标签:Python自动化、PDF翻译、效率工具、AI翻译、开发者工具

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值