扫描版PDF转换为EPUB电子书

1.项目

pdf-craft 可以将 PDF 文件转化为各种其他格式。该项目将专注于扫描书籍的 PDF 文件的处理。

2.PDF 转 MD

2.1.环境准备

VSCode 创建项目文件夹,文件夹下创建 pdf_soufce_files 和 md_output_files 和 model 三个子文件夹,分别放 pdf 扫描文件和转换后的 md 文件以及大模型。

点击 VSCode 的终端功能,新建虚拟环境并安装 pdf-craft 包。

python 复制代码
python -m venv .venv
.\.venv\Scripts\activate
pip install pdf-craft[cpu]
2.2.代码

注意:执行过程中,如果没有大模型会下载,看自己的网络,如果不行,可能需要其他办法。

python 复制代码
from pdf_craft import create_pdf_page_extractor, PDFPageExtractor, MarkDownWriter

extractor: PDFPageExtractor = create_pdf_page_extractor(
    device="cpu",  # 如果希望使用 CUDA,请改为 device="cuda" 这样的格式。
    model_dir_path="model",  # AI 模型下载和安装的文件夹地址
)
with MarkDownWriter("md_output_files/test.md", "images", "utf-8") as md:
    for block in extractor.extract(pdf="pdf_soufce_files/test.pdf"):
        md.write(block)
2.3.执行过程

3.PDF 转 EPUB

3.1.环境准备

VSCode 创建项目文件夹,文件夹下创建 pdf_soufce_files 并把戴转换的电子书放入其中。

analysing ,model,output/files,output/epub 文件夹会自动创建,分别放 pdf 扫描文件中间文件以及大模型和 EPUB 输出文件。

点击 VSCode 的终端功能,新建虚拟环境并安装 pdf-craft 包。

python 复制代码
python -m venv .venv
.\.venv\Scripts\activate
pip install pdf-craft[cpu]
3.2.申请 deepsessk key

进入 DeepSeek 开放平台,实名后充值即可,一本书一般不到五块钱。

3.3.代码

让 deepseek 写了一个,只需要把 pdf 文件放到 pdf_soufce_files 文件夹下即可,如果有中文,会自动翻译成英文。

使用前,需要配置一个叫 OPENAI_API_KEY 的环境变量。变量的值是上一步申请到的 key 。

python 复制代码
import os
import re
import requests

from pdf_craft import (
    create_pdf_page_extractor,
    PDFPageExtractor,
    LLM,
    analyse,
    generate_epub_file,
)

# -----------------------------
# 统一定义脚本目录(绝对路径)
# -----------------------------
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
SOURCE_DIR = os.path.join(BASE_DIR, "pdf_source_files")


# -----------------------------
# 文件名翻译(DeepSeek 简化版)
# -----------------------------
def translate_filename(text, api_key=None):
    """仅用于翻译 PDF 文件名,非常轻量"""

    if api_key is None:
        api_key = os.getenv("OPENAI_API_KEY")

    if not api_key:
        raise ValueError("未找到 API Key,请设置 OPENAI_API_KEY 环境变量。")

    url = "https://api.deepseek.com/chat/completions"
    headers = {
        "Content-Type": "application/json",
        "Authorization": f"Bearer {api_key}",
    }

    data = {
        "model": "deepseek-chat",
        "messages": [
            {
                "role": "system",
                "content": "Translate the following filename from Chinese to English. Only output the translated filename.",
            },
            {"role": "user", "content": text},
        ],
        "temperature": 0.1,
    }

    try:
        response = requests.post(url, headers=headers, json=data, timeout=10)
        response.raise_for_status()

        result = response.json()
        name = result["choices"][0]["message"]["content"].strip()

        name = re.sub(r'[\\/:*?"<>|]', "", name)
        return name

    except Exception as e:
        print(f"翻译失败,使用中文文件名:{text}, 错误:{e}")
        return text


# -----------------------------
# 主流程:扫描 PDF → 重命名 → 转换 → EPUB
# -----------------------------
def auto_convert():
    print("开始扫描 pdf_source_files 目录...")

    if not os.path.exists(SOURCE_DIR):
        print(f"目录 {SOURCE_DIR} 不存在,已创建。")
        os.makedirs(SOURCE_DIR)
        return

    pdf_files = [f for f in os.listdir(SOURCE_DIR) if f.lower().endswith(".pdf")]

    if not pdf_files:
        print("未发现 PDF 文件,请放入 pdf_source_files 后重新运行。")
        return

    api_key = os.getenv("OPENAI_API_KEY")
    if not api_key:
        raise ValueError("未设置 OPENAI_API_KEY 环境变量!")

    pdf_page_extractor: PDFPageExtractor = create_pdf_page_extractor(
        device="cpu",
        model_dir_path=os.path.join(BASE_DIR, "model"),  # 绝对路径
    )

    llm = LLM(
        key=api_key,
        url="https://api.deepseek.com",
        model="deepseek-chat",
        token_encoding="o200k_base",
    )

    for pdf in pdf_files:
        full_path = os.path.join(SOURCE_DIR, pdf)
        base_name = os.path.splitext(pdf)[0]

        print(f"\n=== 处理文件:{pdf} ===")

        if re.search(r"[\u4e00-\u9fa5]", base_name):
            print("检测到中文文件名,正在翻译...")
            new_name = translate_filename(base_name, api_key=api_key)
            new_pdf = new_name + ".pdf"
            new_path = os.path.join(SOURCE_DIR, new_pdf)

            os.rename(full_path, new_path)
            print(f"文件已重命名为:{new_pdf}")

            full_path = new_path
            base_name = new_name

        # -----------------------------
        # 所有路径改成绝对路径
        # -----------------------------
        analysing_dir = os.path.join(BASE_DIR, "analysing", base_name)
        output_dir = os.path.join(BASE_DIR, "output", "files", base_name)
        epub_output = os.path.join(BASE_DIR, "output", "epub", base_name + ".epub")

        os.makedirs(analysing_dir, exist_ok=True)
        os.makedirs(output_dir, exist_ok=True)
        os.makedirs(os.path.dirname(epub_output), exist_ok=True)

        print("开始分析 PDF...")
        analyse(
            llm=llm,
            pdf_page_extractor=pdf_page_extractor,
            pdf_path=full_path,
            analysing_dir_path=analysing_dir,
            output_dir_path=output_dir,
        )

        print("生成 EPUB 文件...")
        generate_epub_file(
            from_dir_path=output_dir,
            epub_file_path=epub_output,
        )

        print(f"EPUB 生成完成:{epub_output}")

    print("\n 所有文件已处理完毕!")


if __name__ == "__main__":
    auto_convert()
相关推荐
lichong95113 小时前
《postman、apipost、smartApi 等使用与特点 3 天路线图(可打印 PDF+互动脑图)》
前端·测试工具·macos·pdf·postman·大前端·大前端++
u***284713 小时前
SpringBoot实战(三十二)集成 ofdrw,实现 PDF 和 OFD 的转换、SM2 签署OFD
spring boot·后端·pdf
你挚爱的强哥1 天前
【sgSelectExportDocumentType】自定义组件:弹窗dialog选择导出文件格式word、pdf,支持配置图标和格式名称,触发导出事件
vue.js·pdf·word
shouchaobao4 天前
免费PDF工具:PDF转Word/Excel/图片+AI总结+合并拆分+OCR识别,多端无广告!
pdf·word·excel
南风微微吹4 天前
2026年最新国考《行测》《申论》历年真题及答案PDF电子版(2000-2025年)
pdf·国考
q***01774 天前
SpringBoot实战(三十二)集成 ofdrw,实现 PDF 和 OFD 的转换、SM2 签署OFD
spring boot·后端·pdf
嗯、.4 天前
使用Itext9生成PDF水印,兼容不同生成引擎的坐标系(如: Skia、OpenPDF)
java·pdf·itextpdf·openpdf·坐标变换矩阵
拓端研究室4 天前
专题:2025AI产业全景洞察报告:企业应用、技术突破与市场机遇|附920+份报告PDF、数据、可视化模板汇总下载
大数据·人工智能·pdf
南风微微吹4 天前
2026年新大纲普通话考试真题题库50套PDF电子版
pdf·普通话