Pdf2md
a kinds of skills can run in any agents, totally free.
npx -y skills add renky1025/agent-skills --skill pdf2mdAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 4 stars4 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
将任意 PDF 文件高质量转换为 Markdown 格式。支持复杂布局、表格、公式、图片提取,自动处理大文件分页,提供多种输出模式。基于 OpenDataLoader PDF - Benchmark #1 准确率。使用方法: /pdf2md <pdf路径> [--output=<输出目录>] [--mode=fast|hybrid] [--extract-images=true|false] [--ocr-lang=<语言>]
SKILL.md
16.6 KB, as published. Nobody here has run it
pdf2md: PDF 转 Markdown 铸造器
基于 OpenDataLoader PDF 的高精度 PDF 解析工具,将 PDF 完美转换为 Markdown 格式,特别适合 AI/RAG 工作流。
核心优势
- 业界最高准确率:Benchmark #1,综合 0.90,表格 0.93,阅读顺序 0.94
- 双模式架构:本地模式(0.05s/页) + 混合模式(AI增强,复杂PDF专用)
- 完整内容还原:表格、LaTeX公式、图片、多栏布局、标题层级
- 大文件友好:自动分页处理,支持批量文件夹处理
- 边界框坐标:每个元素都有坐标,支持溯源引用
使用方法
/pdf2md <PDF路径> [--output=<目录>] [--mode=fast|hybrid] [--extract-images=true|false] [--ocr] [--ocr-lang=<语言>]
参数说明
| 参数 | 说明 | 默认值 |
|---|---|---|
PDF路径 | 单个PDF文件或包含PDF的文件夹 | 必填 |
--output | 输出目录 | ~/Downloads/pdf2md-output/ |
--mode | 处理模式: fast(本地) 或 hybrid(AI增强) | fast |
--extract-images | 是否提取图片 | true |
--ocr | 强制启用OCR(扫描版PDF) | false |
--ocr-lang | OCR语言: en, ch_sim, ch_tra, ja, ko 等 | en |
--formula | 提取数学公式为LaTeX(hybrid模式) | false |
--charts | 生成图表AI描述(hybrid模式) | false |
前置检查
在使用前,必须验证环境是否就绪:
# 1. 检查 Java 版本 (需要 11+)
java -version
# 2. 检查 Python 版本 (需要 3.10+)
python3 --version
# 3. 检查 OpenDataLoader 是否安装
pip show opendataloader-pdf
# 4. 检查 hybrid 模式依赖 (如果使用)
pip show opendataloader-pdf[hybrid]
使用 pdf2md CLI 工具
# 基础转换
python3 pdf2md/pdf2md.py document.pdf
# Hybrid 模式(高质量,支持复杂表格/公式)
python3 pdf2md/pdf2md.py document.pdf --mode=hybrid
# 扫描版PDF(带OCR)
python3 pdf2md/pdf2md.py scan.pdf --mode=hybrid --ocr --ocr-lang=ch_sim
# 学术论文(含公式)
python3 pdf2md/pdf2md.py paper.pdf --mode=hybrid --formula
# 批量处理文件夹
python3 pdf2md/pdf2md.py ./pdfs/ --mode=hybrid --output=./output/
# 检查环境
python3 pdf2md/pdf2md.py --check
# 安装依赖
python3 pdf2md/pdf2md.py --install
CLI 参数说明
参数:
input PDF文件或文件夹路径
可选参数:
-o, --output 输出目录 (默认: ~/Downloads/pdf2md-output)
-m, --mode 处理模式: fast 或 hybrid (默认: fast)
--no-images 不提取图片
--ocr 启用OCR (扫描版PDF)
--ocr-lang OCR语言 (默认: en, 可选: ch_sim/ch_tra/ja/ko)
--formula 提取数学公式为LaTeX (hybrid模式)
--charts 生成图表AI描述 (hybrid模式)
--port Hybrid后端端口 (默认: 5002)
--check 仅检查环境依赖
--install 安装/更新依赖
自动安装
如果未安装,助手会自动执行:
# 基础安装
pip install -U opendataloader-pdf
# 混合模式安装(推荐,支持OCR/公式/图表)
pip install -U "opendataloader-pdf[hybrid]"
执行步骤
步骤 1: 环境检查与初始化
import subprocess
import sys
def check_prerequisites():
"""检查并安装必要依赖"""
checks = {
"java": "java -version",
"python": "python3 --version",
"opendataloader": "pip show opendataloader-pdf"
}
for name, cmd in checks.items():
result = subprocess.run(cmd.split(), capture_output=True)
if result.returncode != 0:
if name == "opendataloader":
print(f"安装 {name}...")
subprocess.run([sys.executable, "-m", "pip", "install", "-U", "opendataloader-pdf"])
else:
raise RuntimeError(f"{name} 未安装,请先安装")
步骤 2: 文件分析与预处理
import os
from pathlib import Path
def analyze_pdf(input_path):
"""分析PDF文件,确定处理策略"""
path = Path(input_path)
if path.is_file() and path.suffix.lower() == '.pdf':
file_size = path.stat().st_size
pages = estimate_pages(file_size) # 估算页数
return {
"type": "single",
"path": str(path),
"size": file_size,
"pages": pages,
"recommend_mode": "hybrid" if pages > 50 else "fast"
}
elif path.is_dir():
pdfs = list(path.glob("**/*.pdf"))
return {
"type": "batch",
"count": len(pdfs),
"files": [str(p) for p in pdfs],
"recommend_mode": "hybrid" if len(pdfs) > 10 else "fast"
}
else:
raise ValueError(f"无效路径: {input_path}")
def estimate_pages(file_size_bytes):
"""根据文件大小估算页数 (约150KB/页)"""
return max(1, int(file_size_bytes / 150000))
步骤 3: 启动 Hybrid 后端 (如使用混合模式)
import subprocess
import time
def start_hybrid_backend(port=5002, ocr=False, ocr_lang="en", formula=False, charts=False):
"""启动混合模式后端服务器"""
cmd = ["opendataloader-pdf-hybrid", "--port", str(port)]
if ocr:
cmd.extend(["--force-ocr", "--ocr-lang", ocr_lang])
if formula:
cmd.append("--enrich-formula")
if charts:
cmd.append("--enrich-picture-description")
process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
# 等待服务启动
time.sleep(3)
# 检查服务是否就绪
import urllib.request
try:
urllib.request.urlopen(f"http://localhost:{port}/health", timeout=5)
return process
except:
process.terminate()
raise RuntimeError("Hybrid 后端启动失败")
步骤 4: 执行转换 (核心代码)
import opendataloader_pdf
import json
from pathlib import Path
def convert_pdf(input_path, output_dir, mode="fast", extract_images=True,
ocr=False, ocr_lang="en", formula=False, charts=False):
"""
转换PDF到Markdown
Args:
input_path: PDF文件路径或文件夹路径
output_dir: 输出目录
mode: 'fast' 或 'hybrid'
extract_images: 是否提取图片
ocr: 是否启用OCR
ocr_lang: OCR语言
formula: 是否提取公式
charts: 是否描述图表
"""
output_path = Path(output_dir)
output_path.mkdir(parents=True, exist_ok=True)
# 准备配置
formats = ["markdown", "json"] # JSON用于调试和元数据
kwargs = {
"input_path": input_path,
"output_dir": str(output_path),
"format": ",".join(formats),
"image_output": "external" if extract_images else "off",
"image_format": "png",
"use_struct_tree": True, # 使用PDF原有结构
}
# 混合模式配置
if mode == "hybrid":
kwargs["hybrid"] = "docling-fast"
if formula or charts:
kwargs["hybrid_mode"] = "full"
# 执行转换
try:
result = opendataloader_pdf.convert(**kwargs)
# 后处理:整合图片到markdown
if extract_images:
post_process_images(output_path)
# 后处理:修复表格格式
post_process_tables(output_path)
return {
"success": True,
"output_dir": str(output_path),
"files": list(output_path.glob("*"))
}
except Exception as e:
return {
"success": False,
"error": str(e),
"error_type": type(e).__name__
}
def post_process_images(output_dir):
"""优化图片路径和引用"""
import re
for md_file in Path(output_dir).glob("*.md"):
content = md_file.read_text(encoding='utf-8')
# 确保图片路径正确
content = re.sub(
r'!\[\]\(([^)]+)\)',
lambda m: f').name})',
content
)
md_file.write_text(content, encoding='utf-8')
def post_process_tables(output_dir):
"""优化表格Markdown格式"""
import re
for md_file in Path(output_dir).glob("*.md"):
content = md_file.read_text(encoding='utf-8')
# 修复可能的表格格式问题
# OpenDataLoader 输出通常是标准GFM格式
# 这里可以添加自定义修复逻辑
md_file.write_text(content, encoding='utf-8')
步骤 5: 大文件分批处理
import os
from pathlib import Path
import tempfile
def convert_large_pdf(input_path, output_dir, mode="hybrid", batch_size=100):
"""
大文件分批处理
对于超过 batch_size 页的PDF,建议:
1. 使用 OpenDataLoader 的批量处理功能(它会自动处理)
2. 或者预先分割PDF(不推荐,会丢失跨页内容)
"""
file_size = Path(input_path).stat().st_size
estimated_pages = estimate_pages(file_size)
if estimated_pages > batch_size:
print(f"⚠️ 大文件检测: 约 {estimated_pages} 页,建议使用 hybrid 模式以确保质量")
print(f" 自动切换到 hybrid 模式...")
mode = "hybrid"
# OpenDataLoader 内部已经优化了大文件处理
# 只需要在 batch 调用时一次性传入所有文件
return convert_pdf(input_path, output_dir, mode=mode)
def process_batch(pdf_files, output_dir, mode="fast"):
"""批量处理多个PDF文件"""
results = []
# OpenDataLoader 推荐一次性批量处理,而不是逐个处理
# 因为每个 convert() 调用会启动一次 JVM 进程
result = convert_pdf(pdf_files, output_dir, mode=mode)
results.append(result)
return results
步骤 6: 异常处理与重试
import time
import traceback
def safe_convert(input_path, output_dir, max_retries=2, **kwargs):
"""
带重试机制的转换
常见异常及处理:
1. JVM内存不足 -> 减小批次大小
2. 损坏的PDF -> 尝试修复模式
3. 加密PDF -> 提示用户解密
4. 混合模式后端未启动 -> 自动启动
"""
for attempt in range(max_retries + 1):
try:
result = convert_pdf(input_path, output_dir, **kwargs)
if result.get("success"):
return result
else:
raise Exception(result.get("error", "Unknown error"))
except Exception as e:
error_msg = str(e).lower()
if "memory" in error_msg:
print(f"⚠️ 内存不足,尝试用 fast 模式重试...")
kwargs["mode"] = "fast"
elif "password" in error_msg or "encrypted" in error_msg:
return {
"success": False,
"error": "PDF 已加密,请先解密后再处理",
"recoverable": False
}
elif "corrupted" in error_msg or "damaged" in error_msg:
print(f"⚠️ PDF 可能损坏,尝试修复模式...")
# 可以尝试用 PyPDF2 等工具修复
elif attempt < max_retries:
print(f"⚠️ 转换失败 ({attempt+1}/{max_retries+1}),{3}秒后重试...")
time.sleep(3)
continue
else:
return {
"success": False,
"error": str(e),
"traceback": traceback.format_exc(),
"recoverable": False
}
return result
步骤 7: 结果整理与输出
def organize_output(output_dir, original_name):
"""整理输出文件结构"""
output_path = Path(output_dir)
# 创建子目录
images_dir = output_path / "images"
images_dir.mkdir(exist_ok=True)
# 移动图片文件
for img in output_path.glob("*.png"):
img.rename(images_dir / img.name)
for img in output_path.glob("*.jpg"):
img.rename(images_dir / img.name)
# 更新 markdown 中的图片引用
for md_file in output_path.glob("*.md"):
content = md_file.read_text(encoding='utf-8')
content = content.replace("](", "](images/")
md_file.write_text(content, encoding='utf-8')
# 生成摘要文件
summary = {
"source": original_name,
"output_directory": str(output_path),
"files": {
"markdown": [str(f) for f in output_path.glob("*.md")],
"json": [str(f) for f in output_path.glob("*.json")],
"images": [str(f) for f in images_dir.glob("*")]
}
}
summary_file = output_path / "summary.json"
summary_file.write_text(json.dumps(summary, indent=2), encoding='utf-8')
return summary
完整使用示例
示例 1: 简单PDF转Markdown
# 用户命令: /pdf2md document.pdf
result = safe_convert(
input_path="document.pdf",
output_dir="~/Downloads/pdf2md-output/document/",
mode="fast",
extract_images=True
)
示例 2: 扫描版PDF(带OCR)
# 用户命令: /pdf2md scan.pdf --mode=hybrid --ocr --ocr-lang=ch_sim
result = safe_convert(
input_path="scan.pdf",
output_dir="~/Downloads/pdf2md-output/scan/",
mode="hybrid",
ocr=True,
ocr_lang="ch_sim", # 简体中文
extract_images=True
)
示例 3: 学术论文(含公式)
# 用户命令: /pdf2md paper.pdf --mode=hybrid --formula
result = safe_convert(
input_path="paper.pdf",
output_dir="~/Downloads/pdf2md-output/paper/",
mode="hybrid",
formula=True,
extract_images=True
)
示例 4: 批量处理文件夹
# 用户命令: /pdf2md ./pdfs/ --mode=hybrid --output=./output/
result = safe_convert(
input_path="./pdfs/",
output_dir="./output/",
mode="hybrid",
extract_images=True
)
输出结构
转换完成后,输出目录结构如下:
output/
├── document.md # 主Markdown文件
├── document.json # 结构化JSON(含边界框坐标)
├── summary.json # 处理摘要
└── images/ # 提取的图片
├── image_001.png
├── image_002.png
└── ...
Markdown 示例输出
# 文档标题
## 第一章 介绍
这是一段正文内容。OpenDataLoader 会正确保留**粗体**和*斜体*。
### 表格示例
| 列1 | 列2 | 列3 |
|-----|-----|-----|
| A1 | B1 | C1 |
| A2 | B2 | C2 |
### 图片示例

### 数学公式
行内公式: $E = mc^2$
块级公式:
$$
\frac{f(x+h) - f(x)}{h}
$$
## 第二章 方法
...
常见问题处理
Q: 转换后表格格式错乱
A: 使用 mode=hybrid,它会自动处理复杂/无边框表格
Q: 扫描版PDF识别率低
A: 添加 --ocr 参数,并确保使用 --mode=hybrid
Q: 大文件内存不足
A: OpenDataLoader 会自动流式处理,如遇内存问题,改用 mode=fast
Q: 图片没有正确提取
A: 确保使用 --extract-images=true(默认开启),并检查输出目录的 images 文件夹
Q: 数学公式显示不正确
A: 使用 --mode=hybrid --formula,公式会以LaTeX格式输出
Q: 中文PDF乱码
A: 数字PDF应正常显示,扫描版PDF使用 --ocr --ocr-lang=ch_sim
性能参考
| 文档类型 | 模式 | 速度 | 准确率 |
|---|---|---|---|
| 简单数字PDF | fast | 20页/秒 | 0.72 |
| 复杂表格PDF | hybrid | 2页/秒 | 0.93 |
| 扫描版PDF | hybrid+OCR | 1页/秒 | 0.90+ |
依赖说明
- Java 11+: 解析引擎基于Java
- Python 3.10+: Python接口
- OpenDataLoader PDF:
pip install opendataloader-pdf - Hybrid模式额外依赖:
pip install "opendataloader-pdf[hybrid]"
相关链接
备选方案
- 原生 PDF 读取:对于简单的数字PDF文档,当前模型可直接读取 PDF 内容并输出 Markdown,无需安装 OpenDataLoader 工具链。适合快速处理少量简单文档。复杂表格、公式、扫描件仍需使用本技能的 hybrid 模式。
License
Apache 2.0 - 与 OpenDataLoader PDF 保持一致