☰
调用MinerU的API,实现PDF转markdown文件:用TaoToken统一Key打通MCP调用链
2026/10/4 21:14:02 网站建设 项目流程

1. 为什么我要把 PDF 转成 Markdown:MinerU API 批量转换的真实场景

如果你正在做论文复现、知识库搭建或者 RAG 检索,大概率会遇到一个很烦的问题:手里一堆 PDF,想喂给大模型,但直接丢 PDF 进去既浪费 token,模型读起来也不稳定。PDF 本质上是给人看的排版格式,不是给机器读的结构化数据,表格、公式、多栏排版一进去就乱。

MinerU 就是解决这个问题的工具。它是 OpenDataLab 推出的文档解析模型,能把 PDF 转成 Markdown、JSON 这类机器可读格式,表格和公式也能保留结构。我这次的目标很明确:把本地papers/raw_papers目录下的论文批量转成 Markdown,输出到papers/mineru_outputs,并且用一套统一的 Key 管理调用凭证。

这里会涉及两个层面:一是直接写脚本调 MinerU 的 API,二是把脚本包装成 MCP server,让 Codex、Cursor、Claude Code 这类 AI Agent 用自然语言触发转换。而凭证管理这块,我用 TaoToken 的统一 Key/API 通道来管,避免每个工具各配一套 Key、到处散落。

适合谁看:需要批量处理 PDF 的科研党、做本地知识库的开发者、想把文档解析接进 Agent 工作流的人。下面从申请 Key 开始,一步步把整条链路跑通。

2. TaoToken 前置准备:统一 Key 与 API 通道配置

在写脚本之前,先把凭证这层理清楚。MinerU 的精准解析 API 需要 Token,而如果你同时还在用其他模型服务,Key 会越攒越多。我的做法是用 TaoToken 作为统一的 API 通道来管理调用凭证,这样脚本里读的是同一套环境变量,切换和轮换都方便。

TaoToken 的官网入口是 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,API 地址是 https://taotoken.net/api 。注意 API 地址后面不加 UTM 参数,直接用它作为 Base URL。

具体操作上,先去控制台创建 Key。控制台地址:https://taotoken.net/console?utm_source=taotoken_aicg_blog_end&utm_content=console&utm_campaign=rewrite 。在 API Keys 页面生成一个 Key,复制保存好,后面脚本和 MCP 配置都要用。API Keys 页面:https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api-keys&utm_campaign=rewrite 。

拿到 Key 之后,不要写死在代码里。我在项目根目录建了一个.env文件,内容就一行:

MINERU_API_TOKEN=你的Key

然后在.gitignore里加上.env,防止 Key 被 Git 跟踪。这一步很关键,我见过太多人把 Key 提交到仓库然后被迫轮换。

如果你用的是 VS Code,可以在.vscode/launch.json里配置envFile,让调试时自动加载.env:

{ "version": "0.2.0", "configurations": [ { "name": "Run MinerU Batch PDF", "type": "python", "request": "launch", "program": "${workspaceFolder}/tools/batch_pdf_to_markdown.py", "console": "integratedTerminal", "envFile": "${workspaceFolder}/.env" } ] }

这样脚本运行时通过os.environ.get("MINERU_API_TOKEN")就能拿到 Key,本地调试和命令行运行都不用手动 export。

关于模型选择,MinerU 提供pipeline、vlm、MinerU-HTML三个版本。官方推荐vlm,解析精度最高,我实测下来表格和公式的还原确实更好。语言参数用ch覆盖中英文混排的论文场景。输出格式除了默认的 Markdown、JSON,还可以额外导出docx、html、latex。

如果你打算长期跑批量转换或者接进 Agent 工作流,可以考虑 Coding Plan,地址:https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding-plan&utm_campaign=rewrite 。它更适合持续性的编码和 Agent 调用场景。

3. 可复制配置:batch_pdf_to_markdown.py 脚本与 MCP 注册片段

这一节给出可以直接复制的配置。先看脚本文件tools/batch_pdf_to_markdown.py的核心结构。它负责真正调用 MinerU API,包含文件收集、页数校验、上传、轮询、下载解压几个阶段。

关键常量部分:

BASE_URL = "https://mineru.net" FILE_URLS_BATCH_ENDPOINT = "/api/v4/file-urls/batch" URL_TASK_BATCH_ENDPOINT = "/api/v4/extract/task/batch" BATCH_RESULTS_ENDPOINT = "/api/v4/extract-results/batch" MAX_FILE_BYTES = 200 * 1024 * 1024 MAX_PDF_PAGES = 200 MAX_BATCH_FILES = 200 SUPPORTED_MODELS = {"pipeline", "vlm", "MinerU-HTML"} SUPPORTED_EXPORT_FORMATS = {"docx", "html", "latex"}

主流程在__main__里,参数集中在这里改:

PDF_DIR = Path("papers/raw_papers") OUTPUT_DIR = Path("papers") / "mineru_outputs" MODEL_VERSION = "vlm" EXPORT_FORMATS = ["docx", "html", "latex"] ENABLE_FORMULA = True ENABLE_TABLE = True LANGUAGE = "ch" POLL_SECONDS = 15 TIMEOUT_SECONDS = 60 * 60

运行前先装依赖:

python -m pip install -i https://pypi.tuna.tsinghua.edu.cn/simple pypdf

然后直接跑:

python tools/batch_pdf_to_markdown.py

脚本会先校验每个 PDF 的大小和页数,超过 200MB 或 200 页会直接报错。校验通过后请求签名上传 URL,逐个 PUT 上传,再轮询 batch 结果,最后下载 ZIP 并解压到papers/mineru_outputs/extracted/下,每篇论文一个文件夹。

接下来是 MCP 部分。新建tools/mineru_mcp_server.py,把上面的函数包装成 MCP tool:

from pathlib import Path from tools.batch_pdf_to_markdown import ( collect_pdf_paths, download_and_extract_results, get_api_token, request_local_upload_urls, poll_batch_results, upload_file_to_signed_url, validate_pdf_batch, ) DEFAULT_PDF_DIR = "papers/raw_papers" DEFAULT_OUTPUT_DIR = "papers/mineru_outputs" DEFAULT_MODEL_VERSION = "vlm" def convert_pdfs_to_markdown( pdf_dir=DEFAULT_PDF_DIR, output_dir=DEFAULT_OUTPUT_DIR, model_version=DEFAULT_MODEL_VERSION, extra_formats=None, enable_formula=True, enable_table=True, language="ch", poll_seconds=15, timeout_seconds=60 * 60, ): pdf_dir_path = Path(pdf_dir) output_dir_path = Path(output_dir) requested_extra_formats = list(["html", "latex"] if extra_formats is None else extra_formats) api_token = get_api_token() pdf_paths = collect_pdf_paths(pdf_dir_path) validate_pdf_batch(pdf_paths) batch_id, signed_upload_urls = request_local_upload_urls( pdf_paths, api_token, model_version, requested_extra_formats, enable_formula, enable_table, language, ) for pdf_path, signed_upload_url in zip(pdf_paths, signed_upload_urls): upload_file_to_signed_url(pdf_path, signed_upload_url) completed_results = poll_batch_results(batch_id, api_token, poll_seconds, timeout_seconds) saved_zip_paths = download_and_extract_results(completed_results, output_dir_path) return { "batch_id": batch_id, "pdf_count": len(pdf_paths), "saved_zip_paths": [str(path) for path in saved_zip_paths], "output_dir": str(output_dir_path), } def create_mcp_server(): from mcp.server.fastmcp import FastMCP mcp = FastMCP("mineru") mcp.tool()(convert_pdfs_to_markdown) return mcp if __name__ == "__main__": create_mcp_server().run()

MCP 环境建议单独建,避免和旧项目冲突:

conda create -n mineru-mcp python=3.12 -c https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main -c https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge conda activate mineru-mcp python -m pip install -i https://pypi.tuna.tsinghua.edu.cn/simple mcp pypdf

注册给 Codex:

codex mcp add mineru -- D:\Program\anaconda3\envs\mineru-mcp\python.exe D:\PycharmProjects\project\tools\mineru_mcp_server.py

这里三件套要写全:Base URL 用 TaoToken 的https://taotoken.net/api,Key 从.env读,Model ID 用vlm。注册完验证:

codex mcp list codex mcp get mineru

4. 验证请求与成功结果:单文件与批量目录两种场景

配置好之后,先验证单文件场景,再跑批量目录。

单文件验证最简单的方式是临时把PDF_DIR指向一个只放了一篇 PDF 的目录,或者直接在 MCP 里用自然语言指定。跑起来后终端会打印:

准备上传 1 个 PDF。 batch_id: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx 上传: attention_is_all_you_need.pdf 上传完成,开始轮询解析结果。 等待解析完成: attention_is_all_you_need.pdf=pending 等待解析完成: attention_is_all_you_need.pdf=running 下载完成: papers/mineru_outputs/zip/attention_is_all_you_need.zip

看到下载完成并且列出 ZIP 路径,就说明单文件链路通了。解压后的目录结构是:

papers/mineru_outputs/extracted/attention_is_all_you_need/ ├── attention_is_all_you_need.md ├── attention_is_all_you_need.json ├── attention_is_all_you_need.docx ├── attention_is_all_you_need.html └── attention_is_all_you_need.latex

打开.md文件检查一下:标题层级、表格、公式是否保留。我实测下来vlm模型对公式的还原比较到位,行内公式和独立公式都能转成 LaTeX 形式。

批量目录场景就是把多篇 PDF 放进papers/raw_papers,重新跑脚本。终端会显示每个文件的上传和轮询状态。全部完成后,extracted下会按 PDF 文件名生成多个文件夹。

如果你用 MCP,重启 Codex 后直接说:

调用 mineru,把 papers/raw_papers 里的 PDF 转成 Markdown,输出到 papers/mineru_outputs,模型用 vlm。

或者更短:

调用 mineru,把 papers/raw_papers 里的 PDF 转成 Markdown。

Agent 会调用convert_pdfs_to_markdown这个 tool,返回 batch_id、pdf_count 和输出目录。你可以根据返回的saved_zip_paths去确认结果。

验证成功的标准有三个:一是终端或 Agent 返回里没有报错;二是extracted目录下每个 PDF 都有对应文件夹;三是 Markdown 文件能正常打开且内容完整。如果只想快速验证模型效果,也可以去模型对话页面直接试:https://taotoken.net/model-chat?utm_source=taotoken_aicg_blog_end&utm_content=model-chat&utm_campaign=rewrite 。

5. 本篇常见错排查:401、local proxy failed、reading choices、OAuth

这一节把我踩过的坑和常见报错对照列出来。

401 Unauthorized:最常见的原因是.env没被加载,或者 Key 复制时带了空格。检查get_api_token()是否真的读到了值,可以在脚本里临时打印api_token[:8]确认。另外确认.env文件在项目根目录,且MINERU_API_TOKEN=后面没有多余引号。

local proxy failed / connection refused:这类报错通常是网络层的问题。先确认BASE_URL写的是https://mineru.net,没有多写路径。如果用了 TaoToken 的 API 通道,确认 Base URL 是https://taotoken.net/api,不要带 UTM 参数。签名上传 URL 是 MinerU 返回的临时地址,不要手动改。

reading choices / JSON 解析失败:这个报错一般出现在request_json里,说明返回的不是合法 JSON。可能是接口返回了 HTML 错误页,或者 batch_id 拼错了。检查BATCH_RESULTS_ENDPOINT拼接后的完整 URL,确认 batch_id 是从上传响应里取的data["batch_id"]。

OAuth / 登录态问题:MinerU 的精准解析 API 用的是 Bearer Token,不是 OAuth 流程。如果你看到 OAuth 相关报错,大概率是误用了其他接口。确认请求头是Authorization: Bearer <token>,而不是Authorization: OAuth ...。

pypdf 缺失:报错信息是需要安装 pypdf 才能在上传前校验 PDF 页数。解决:

python -m pip install -i https://pypi.tuna.tsinghua.edu.cn/simple pypdf

MCP 注册后 Codex 找不到工具:先codex mcp list确认 mineru 在列表里。如果不在,检查codex mcp add命令里的 Python 路径和脚本路径是否都是绝对路径。Windows 下路径用反斜杠,且确认mineru-mcp环境里装了mcp和pypdf。

上传超时:大文件上传可能超过默认超时。upload_bytes_to_signed_url里超时设的是 300 秒,如果还超时,检查文件是否接近 200MB 上限,或者网络是否稳定。

轮询一直 pending:poll_batch_results默认超时 1 小时。如果一直 pending,先确认 MinerU 服务状态,再检查POLL_SECONDS是否设得太短导致请求过频。我一般设 15 秒。

排障时如果涉及接入配置,可以对照接入文档:https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite 。API Keys 管理在 https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api-keys&utm_campaign=rewrite 。

6. 把链路接进你的工作流:从脚本到 Agent 的下一步

整条链路跑通之后,你会发现真正省事的地方在于复用。batch_pdf_to_markdown.py里的函数是纯逻辑,MCP server 只是薄薄一层包装。以后要加新功能,比如只转某个子目录、按文件名过滤、转换后自动切分 chunk,都只需要改脚本,MCP tool 自动继承。

凭证管理这块,用 TaoToken 统一 Key 的好处是脚本、MCP、Agent 读的是同一套环境变量。轮换 Key 时只改.env一处,不用去每个工具里翻配置。如果你后面还要接 Claude Code 做代码相关的 Agent 任务,可以看 ClaudeCodeAnthropic 的接入方式:https://taotoken.net/claudecode-anthropic?utm_source=taotoken_aicg_blog_end&utm_content=claudecode-anthropic&utm_campaign=rewrite 。

一个实用技巧:转换完成后,先别急着把整个 Markdown 丢给模型。MinerU 输出的 JSON 里带了版面结构信息,做 RAG 切分时用 JSON 比用 Markdown 更可控。我一般先用 Markdown 做人工检查,确认解析质量没问题,再用 JSON 做后续处理。

最后提醒一句,.env一定要进.gitignore。我见过有人把 Key 推到公开仓库,几分钟内就被扫到滥用。Key 泄露后第一时间去控制台轮换,别拖。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询