在 Zotero 里管理大量电子书时,扫描版 PDF 常有这些问题:
- 扫描版 PDF 无法搜索、复制文字
- PDF 在手机上阅读体验差(固定排版,字小,无法自适应)
- 格式混乱:PDF、epub、txt、图片等格式混杂
因此需要一个工具链:扫描版 PDF → OCR 识别 → Markdown → EPUB
EPUB 的优势:手机自适应排版、可搜索、可标注、文件小。
使用火山引擎智能文档解析 API(OCRPdf v3)进行 OCR,相比本地 Tesseract:
- 中文识别率高很多,无空格问题
- 支持版面分析、表格识别、公式识别
- 输出结构化 Markdown
- 火山引擎 OCRPdf API v3 — OCR + 版面分析
- volcengine Python SDK — API 调用与签名
- pikepdf — PDF 分页拆分(应对 API 8MB 限制)
- ebooklib + markdown — Markdown → EPUB 转换
- Python 3.14(通过 pymanager 管理)
- 火山引擎 API 对接(OCRPdf v3,使用
visual_service.ocr_pdf()) - PDF 自动分块(大文件 pikepdf 拆分,小文件用 page_start/page_num 翻页)
- Markdown 输出
- Markdown → EPUB 转换(自动分章、中文 CSS 优化)
- CLI 工具完成(支持 --output / --md-only / --title / --chunk-size 等参数)
- 凭证管理(环境变量 / volc_config.json)
- 基本重试机制
- 扫描版 PDF 每页体积大,base64 编码后容易超过 API 的 8MB 限制
- 当前解决方案:用
--chunk-size 10手动调小每块页数 - 实测:258页扫描版(76MB),chunk-size=20 时第5块(7MB raw → ~9.3MB base64)超限失败
- chunk-size=10 可能可以通过,但尚未完整验证
- 当前解决方案:用
- 自动检测 chunk base64 大小,超 8MB 时自动拆更小(当前只按页数固定拆)
- 支持火山引擎对象存储上传:超大文件传
image_url而非image_base64,彻底解决 8MB 限制 - 断点续传:已处理的块跳过,避免重复消耗 API 额度
- EPUB 内嵌图片:API 返回的图片 URL 有效期仅 30 分钟
- 错误处理优化:区分"超限"和其他错误,超限时自动缩小 chunk
pip install volcengine pikepdf ebooklib markdown二选一:
# 方式一:环境变量
set VOLC_ACCESSKEY=你的AK
set VOLC_SECRETKEY=你的SK// 方式二:脚本同目录创建 volc_config.json
{"access_key": "你的AK", "secret_key": "你的SK"}凭证获取:火山引擎控制台 → 访问密钥
# 基本用法:PDF → EPUB(同时生成 .md)
python pdf2epub.py input.pdf
# 指定输出文件名和书名
python pdf2epub.py input.pdf --output book.epub --title "书名"
# 只输出 Markdown
python pdf2epub.py input.pdf --md-only
# 扫描版大文件用小 chunk(推荐 10 页)
python pdf2epub.py input.pdf --chunk-size 10
# 指定作者
python pdf2epub.py input.pdf --title "书名" --author "作者"- 免费额度:500 页
- 超出后:0.02 元/页
- 一本 300 页的书约 6 元
ebook-convert/
├── pdf2epub.py # 主脚本
├── volc_config.json.example # 凭证模板(复制为 volc_config.json 填入 AK/SK)
├── volc_config.json # 实际凭证(已 .gitignore,不提交)
└── README.md # 本文件