不用上传云端:用 anydoc 在本地把 Word、Excel、PPT 与 PDF 统一成 Markdown
团队里的历史资料往往并不缺:合同草稿在 Word,复盘在 PowerPoint,报价和清单在 Excel,规范又散落在 PDF、RTF 与 EPUB 中。真正困难的是后续使用:不同格式不能直接放进 Git 做差异审阅,也很难作为静态文档或本地知识库的统一输入。
通常的补救办法是把文件上传给某个在线转换器,或让脚本为每种格式拼一套依赖。这两种做法分别引入了数据出域和维护成本。Firecrawl 开源的 anydoc 提供了另一条更轻量的路径:它用 Rust 把多种办公文档解析为同一个文档模型,再经同一个 GitHub Flavored Markdown(GFM)序列化器输出 Markdown。对需要先把资料整理进本地工作流、再决定是否检索或交给 AI 的开发者,这个分层很有价值。
本文聚焦本地命令行与可审计的批处理方式;它不是 OCR 工具,也不应被当成“任何 PDF 都能完美还原”的承诺。
先确认它解决的边界
anydoc 支持 Word、PowerPoint、Excel、OpenDocument、RTF、EPUB、CSV 和 PDF:具体包括 .doc/.docx/.docm、.ppt/.pptx、.xls/.xlsx/.xlsm/.xlsb、.odt/.ods/.odp、.rtf、.epub、.csv 与 .pdf 等扩展名。项目的核心不是为每种文件造一个独立的 Markdown 模板,而是先把内容归一到共享的 Document 模型,再统一处理标题、列表、表格、脚注、链接和引用。
这种设计有两个实际收益。第一,输入来源再杂,输出的 Markdown 习惯更一致;例如表格转义或脚注格式的修复,不必在每个格式转换器中重复实现。第二,格式识别主要依赖文件字节中的标记,而不是只看扩展名:PDF 头、RTF 起始组、OLE 流和 ZIP 包的 MIME/内容类型都可以参与判断。文件名写错时仍有机会正确识别。
但边界也要写清楚。文本型 PDF 可以在本地处理;扫描件或只有图片的 PDF 没有可提取的文本层,anydoc 会将其视为不支持的输入。加密文件、结构损坏的文件,以及触发固定资源安全限制的文件,也会产生相应错误。若业务必须识别扫描件,应在转换前后增加单独的 OCR 流程,而不是把 OCR 能力臆测为 anydoc 的本地功能。
从一次转换开始,而不是一上来全量迁移
Node.js 环境中无需先全局安装,直接通过 npx 就能试用:
npx @firecrawl/anydoc report.docx npx @firecrawl/anydoc slides.pptx -o slides.md npx @firecrawl/anydoc - --format csv < data.csv
这里建议把“输出到标准输出”的第一条命令当作验收步骤,而不是只看退出状态。任选一份代表性文档,人工检查标题层级、合并单元格、脚注、编号列表和外链是否符合用途。确认可接受后再用 -o 写入文件。若要长期使用,可安装全局命令:
npm install -g @firecrawl/anydoc anydoc --help
一个常见误区是把 CSV 当成普通的可自动识别二进制文档。CSV 本身没有可靠的内容签名;当它来自管道或字节流时,应传递 --format csv,或在 API 中显式给出格式名。对于普通路径输入,扩展名能够提供这个线索。
把转换放进可回滚的资料整理流程
批量迁移最怕“成功了一半却不知道哪一半”。比起直接覆盖源文件,更稳妥的流程是保留原文件、单独存放 Markdown 输出,并记录失败清单。下面的 Bash 示例只处理一层目录,故意把失败项写入日志,方便后续决定是修复源文件、补 OCR,还是排除该文件:
mkdir -p markdown-output
: > conversion-failed.txt
for file in incoming/*; do
[ -f "$file" ] || continue
base=$(basename "$file")
stem=${base%.*}
if ! npx @firecrawl/anydoc "$file" -o "markdown-output/${stem}.md"; then
printf '%s\n' "$file" >> conversion-failed.txt
fi
done
这段脚本没有试图猜测失败原因。anydoc 的 Rust API 将无法输出有意义 Markdown 的情况区分为 Unsupported、Malformed、Encrypted、ResourceLimit、MissingPart 等错误;在自动化流程中,最重要的是保留源路径并让异常进入人工队列。特别是受密码保护的 Office 文件和图片型 PDF,不应在无人值守脚本中反复重试。
输出目录可与源文件一起提交到 Git,但不建议把敏感原件和转换结果混在公共仓库。一个更可靠的实践是:源文件留在受访问控制的存储中,Markdown 进入私有仓库;每次转换都在提交信息或清单中记录工具版本、源文件校验值和转换日期。这样以后看到 Markdown 变更时,能区分它是内容更新,还是转换器升级导致的渲染差异。
需要嵌入应用时,使用绑定而非 shell 拼接
命令行适合批处理,应用程序则可调用 Node.js 或 Python 绑定。Node.js 绑定暴露 toMarkdown、toMarkdownBytes 和 toDocument:前两个用于取得 Markdown,最后一个保留共享文档模型及嵌入资源信息。
import { toMarkdown, toMarkdownBytes, toDocument } from '@firecrawl/anydoc';
const markdown = await toMarkdown('report.docx');
const csvMarkdown = await toMarkdownBytes(csvBytes, 'csv');
const document = await toDocument(fileBytes);
Python 包的安装名是 firecrawl-anydoc,导入名则是 anydoc。这类命名差异很容易在部署脚本中踩坑:
import anydoc
markdown = anydoc.to_markdown("report.docx")
markdown_from_csv = anydoc.to_markdown_bytes(csv_bytes, "csv")
try:
document = anydoc.to_document(file_bytes)
except (anydoc.EncryptedError, anydoc.UnsupportedError) as error:
print(f"skip: {type(error).__name__}")
嵌入图片或对象不会自动变成可在 Markdown 中携带的二进制内容:Markdown 输出中会使用替代文本,而原始字节仍保留在 Document 模型的资源集合中。若你的目标是完整归档,应用层需要明确决定如何保存这些资源;若目标只是构建可搜索的文本索引,则可以把这一限制作为验收条件。
转换结果不是最终资料:建立可复现的验收基线
在第一次批量运行前,建议先为每种关键来源各挑两三份样本:一份结构简单的文档、一份含表格和脚注的文档,以及一份你已经知道会有问题的扫描件或加密件。把原文件、生成的 Markdown、运行命令和人工检查结论放在同一个验收目录。这样当未来升级 anydoc、Node.js 运行时或调用脚本时,可以重新转换这些固定样本,使用 Git diff 判断变化来自工具升级还是源文档本身。
对表格而言,检查的不只是行数。应确认列标题是否被当作标题行、合并单元格是否变成可理解的文本、金额和日期有没有错位;对演示稿则重点检查每页标题、项目符号及演讲者备注是否符合预期。Markdown 的优势是可以审阅和检索,不等于能保留页面像素级布局。把“内容结构可用”写成验收标准,通常比追求与原始 Office 页面完全一致更实际。
如果团队随后要把输出交给本地检索或模型,还应把引用原件的路径或不可变 ID 一并保存。检索得到的一段 Markdown 能回链到具体文件,才便于处理数字、条款或图表含义被误读时的溯源。转换层负责统一格式,事实确认仍应回到原件。
本地优先,不等于跳过质量控制
项目还提供 WebAssembly 演示页面,说明其浏览器版本可在设备本地转换文件;这对临时处理敏感材料很方便。不过“本地运行”只解决了传输路径的问题,并不替你判断语义是否丢失。转换后的 Markdown 仍应经过三类检查:
- 结构检查:抽查标题、表格、脚注与列表,确认它们可被目标渲染器正确展示。
- 内容检查:对财务数字、法律条款、版本号等高风险字段回看原件,避免把解析结果直接当作权威记录。
- 流程检查:把扫描件、加密件和解析失败文件留在失败清单中,不要用空 Markdown 假装转换完成。
anydoc 的项目仓库提供了与其他转换器的基准表,但该表来自项目方自己的语料、硬件与 LLM 评审方法,适合用来理解设计目标,不应替代你对自身文件集的抽样验收。对多数团队而言,最有价值的不是某个单一分数,而是把格式混杂的资料先变成可版本化、可审阅、可重跑的中间层。
什么时候适合用它
如果你的输入主要是文本型办公文档、目标是本地 Markdown、并且愿意把转换结果纳入抽样审核,anydoc 很适合作为资料迁移、静态文档整理或本地检索前的规范化步骤。它尤其适合“原始格式多、输出格式必须统一”的场景。
反过来,如果资料以扫描 PDF 为主、必须保留版式级视觉还原,或需要在没有人工验收的情况下输出具法律效力的内容,就应选择带 OCR、版面识别和专门质检链路的方案。先明确输入质量与输出责任边界,再把转换工具嵌入流程,才不会把“格式统一”误当成“信息已经被可靠理解”。