尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

anydoc Node.js 绑定完整指南:用 @firecrawl/anydoc 将 Word、PPT、Excel、PDF 等文档转换为 GitHub-Flavored Markdown

anydoc Node.js 绑定完整指南:用 @firecrawl/anydoc 将 Word、PPT、Excel、PDF 等文档转换为 GitHub-Flavored Markdown anydoc Node.js 绑定完整指南用 firecrawl/anydoc 将 Word、PPT、Excel、PDF 等文档转换为 GitHub-Flavored Markdown【免费下载链接】anydocConvert Word, PowerPoint, Excel, OpenDocument, RTF, EPUB, CSV, and PDF to clean Markdown. Built in Rust, with Node.js and Python bindings.项目地址: https://gitcode.com/gh_mirrors/any/anydoc本指南围绕node/README.md展开系统讲解 anydoc 官方 Node.js 绑定firecrawl/anydoc的安装、CLI 与编程接口。该包以 N-API 原生模块形式封装 anydoc 的 Rust 转换内核能把 Word、PowerPoint、Excel、OpenDocument、RTF、EPUB、CSV 与 PDF 等八类格式统一转换为干净的 GitHub-Flavored MarkdownGFM且转换在 libuv 线程池上执行、绝不阻塞事件循环。读完本文你将掌握npx零安装转换、基于文件路径/字节/文档模型三种调用方式、错误码驱动的健壮批处理、基于内容的格式探测以及文档模型块、表格、列表、脚注、内嵌资源的完整结构可直接用于构建文档批处理管线或 Agent 工具。设计理念一种输出模型统一所有格式任何格式的文件都会先被各自的格式解析器解析进同一个共享文档模型再经同一个 Markdown 序列化器渲染输出。因此无论输入是 2003 年的.doc还是新生成的.pptx标题、表格、列表、脚注、转义规则和标题锚点的表现都完全一致。正如根目录 README.md 中的架构示意所示document bytes │ ├─► format detection → content markers, not the extension │ ├─► format parser → one per format (doc, docx, ppt, pptx, xls, │ xlsx, odt/ods/odp, rtf, epub, csv) │ │ │ └─► Document → shared model: blocks, inlines, tables, │ footnotes, assets │ │ │ └─► GFM serializer → Markdown │ └─► PDF → pdf-inspector → Markdown directly这一设计的收益在于因为所有格式都汇入同一套模型与序列化器输出质量问题只需修复一次——例如 docx 的表格转义修复会自动成为 rtf、odt 等其他格式的表格转义修复。安装与环境要求npm install firecrawl/anydocNode 版本node/package.json中engines声明为node 20。原生模块包通过 NAPI-RSnode/package.json中的napi-rs/cli构建生成平台专属二进制index.js在运行时按process.platform与process.arch自动加载对应.node文件。官方构建目标覆盖 macOSx64/arm64、Linuxx64/arm64含 musl 与 gnu 变体、Windowsx64-msvc等平台见node/package.json的napi.targets。TypeScript 类型包随附index.d.ts所有接口与枚举均带完整 JSDoc 注释ConvertErrorCode等联合类型开箱即用。若原生绑定加载失败index.js会回退尝试 WASI 构建anydoc.wasi.cjs并给出明确的排查提示。支持的格式与扩展名格式扩展名Word.doc,.docx,.docmPowerPoint.ppt,.pps,.pot,.pptx,.pptm,.ppsx,.ppsmExcel.xls,.xlsx,.xlsm,.xlsbOpenDocument.odt,.ods,.odpRich Text Format.rtfEPUB.epubCSV.csvPDF.pdf从 node/src/lib.rs 可以看到Node 绑定只暴露 12 个核心Format枚举值doc、docx、odt、pdf、ppt、pptx、rtf、epub、xlsx、ods、odp、csv。像.docm、.xlsm、.ppsx这类与某解析器共享实现的容器变体在枚举层面会映射到对应的核心格式——例如formatFromExtension(.pptm)返回pptx、formatFromExtension(xls)返回xlsx。CLI无需安装即可转换包在bin字段中注册了anydoc命令见 node/package.json因此可以直接用npx调用无需先安装npx firecrawl/anydoc report.docx # Markdown 输出到 stdout npx firecrawl/anydoc slides.pptx -o slides.md # 或输出到文件 npx firecrawl/anydoc - --format csv data.csv # 从 stdin 读取Markdown 走 stdout错误信息走 stderr。想常驻使用可全局安装npm install -g firecrawl/anydoc获得永久anydoc命令anydoc --help可查看全部选项。CLI 完整参数根据 node/cli.js 中的帮助文本与参数解析实现完整用法如下anydoc file [options] anydoc - [options] file选项说明-o, --output path将 Markdown 写入path而不是 stdout-f, --format format显式指定输入格式而非自动探测。可选值doc, docx, odt, pdf, ppt, pptx, rtf, epub, xlsx, ods, odp, csvxls、docm、ppsx等扩展名别名也会解析到上述格式-h, --help打印帮助并退出-V, --version打印版本号并退出CLI 的退出码约定对脚本化调用至关重要退出码含义0成功1文档无法读取或转换2用法错误未知选项、缺少输入、--format非法几个值得注意的 CLI 行为细节均可在 node/cli.js 源码中验证一次调用只转换一个文档传入第二个输入文件会以退出码 2 报错--之后的参数一律视为位置参数用于处理以连字符开头的文件名支持--outputpath、--formatcsv这类内联传值形式从 stdin 读取时若检测到 stdin 是终端TTY会直接以用法错误退出提示需要管道或重定向stdin 没有扩展名所以从 stdin 输入 CSV 必须显式加--format csv输出到管道被下游提前关闭如anydoc big.xlsx | head时按成功处理EPIPE不视为转换失败--help与--version在加载原生绑定之前处理因此即使本机缺少可用绑定这两个命令也能正常工作扫描版/纯图片 PDF 需要 OCR而 anydoc 不做 OCR此类输入会以unsupported错误失败。Node.js API三种调用方式import { toDocument, toMarkdown, toMarkdownBytes } from firecrawl/anydoc; // 方式一从文件路径转换格式从文件内容探测 const markdown await toMarkdown(report.docx); // 方式二从字节转换格式由内容自动探测 const fromBytes await toMarkdownBytes(bytes); // 方式三显式指定格式无签名格式如 CSV 必须如此 const fromCsv await toMarkdownBytes(bytes, csv); // 方式四止步于文档模型模型同时携带内嵌资源 const document await toDocument(bytes);三个函数的语义差异函数输入输出适用场景toMarkdown(path)文件路径Promisestring直接处理磁盘文件文件不可读时拒绝为io错误toMarkdownBytes(bytes, format?)Uint8Array 可选格式Promisestring内存/网络流数据CSV 必须显式传csvtoDocument(bytes, format?)Uint8Array 可选格式PromiseDocument需要文档模型块结构、表格、脚注、内嵌资源的二次加工场景从 node/src/lib.rs 的实现可见三个函数全部返回AsyncTaskRust 侧的计算在 libuv 线程池上执行compute完成后再切回 JS 主线程resolve/reject因此任何转换都不会阻塞事件循环可在高并发 Web 服务中放心使用。一个特殊限制PDF 不支持 toDocument根据 node/src/lib.rs 与index.d.ts中Format.pdf的注释PDF 由 pdf-inspector 直接产出 Markdown没有文档模型形式因此toDocument对 PDF 输入会失败如需 PDF 请走toMarkdownBytes/toMarkdown。错误处理以error.code驱动批处理转换只在无法产出任何有意义的 Markdown 时才拒绝Promise reject文件里的小瑕疵会被尽量恢复或跳过而不是报错。拒绝时抛出的Error带有code属性指明失败类别。官方推荐的批处理模式try { return await toMarkdown(path); } catch (error) { // 这类文件永远转换不出来记录下来继续处理下一个。 if (error.code encrypted || error.code unsupported) { unconverted.push({ path, reason: error.code }); return null; } throw error; }错误码全表code含义unsupported未知格式或无法转换的格式如纯图片 PDFmalformed结构不可用无法提取任何有意义的内容encrypted加密或受密码保护resourceLimit触发了固定安全上限解压、嵌套深度、节点数量missingPart缺少产出任何有意义输出所必需的部件package partio文件无法读取仅toMarkdown会抛出error.message携带详细说明当格式能识别出具体部件时会点名出错的包部件。在 src/error.rs 中可以看到这些code字符串与 Rust 侧ConvertError变体的一一对应Unsupported→unsupported、Malformed→malformed、Encrypted→encrypted、ResourceLimit→resourceLimit、MissingPart→missingPart、Io→io。Node 侧通过 node/src/lib.rs 的Failure结构在跨线程传递时保留错误类别最终以error.code形式呈现给 JS。TypeScript 用户可直接使用随包导出的联合类型ConvertErrorCode进行类型安全的错误分支import type { ConvertErrorCode } from firecrawl/anydoc;该类型定义在 node/index.d.ts 中六个取值与上表完全一致。格式检测看内容不看扩展名格式从文件内容本身读取依据各格式规范指定的特征标记PDF文件头%PDF-等 headerRTF开头的{\rtf开放组OLE 容器.doc/.ppt/.xls等老格式OLE 流名称ZIP 容器.docx/.pptx/.odt等包内的 mimetype 与 content typesCSV没有任何特征标记因此探测返回null只能靠扩展名或显式指定格式来命名。formatFromBytes(bytes); // docx或什么都匹配不上时返回 null formatFromExtension(.pptm); // pptx formatFromPath(report.odt); // odt三个函数的行为可从 node/src/lib.rs 确认formatFromBytes(bytes)纯内容探测返回Format | nullformatFromExtension(extension)接受带或不带前导点号的扩展名trim_start_matches(.).pptm归一为pptxformatFromPath(path)取路径的扩展名再探测。由于检测基于内容而非文件名即使文件被错误命名如把.docx内容命名为.txt仍能正确转换。需要说明的是CSV 因无签名formatFromBytes对它返回null测试用例 node/test.mjs 中也专门断言了这一点formatFromBytes对 CSV fixture 返回null且不传格式直接转 CSV 会以unsupported拒绝显式传csv才能成功。深入文档模型Document、Block、Inline 与各类结构化对象toDocument返回的Document对象由三部分组成见 node/src/document.rs 与 node/index.d.tsinterface Document { blocks: ArrayBlock; // 顶层块标题、段落、列表、表格、引用、代码块… notes: ArrayNote; // 脚注/尾注正文正文中的 noteRef 按 id 引用 assets: ArrayAsset; // 内嵌二进制资源图片、对象载荷 }Block七种块类型type BlockKind heading | paragraph | list | table | blockQuote | codeBlock | rule; interface Block { kind: BlockKind; level?: number; // heading: 1-6 anchor?: string; // heading: 文档内部指向该标题时的稳定锚点 id content?: ArrayInline; // heading、paragraph list?: List; // list table?: Table; // table blocks?: ArrayBlock; // blockQuote嵌套块 lang?: string; // codeBlock代码语言 text?: string; // codeBlock代码文本 }Inline六种行内元素type InlineKind text | link | image | anchor | noteRef | lineBreak; interface Inline { kind: InlineKind; text?: string; // text style?: Style; // text已完全解析的字符样式 content?: ArrayInline; // link链接内联内容 target?: LinkTarget; // link alt?: string; // image替代文本 source?: ImageSource; // image anchor?: string; // anchor锚点 id noteId?: string; // noteRefDocument.notes 中的 id }其中Style是完全解析后的字符样式bold、italic、strike、code四个布尔值意味着继承链上的样式已折叠成最终生效值无需调用方自己回溯样式表。LinkTarget区分三种目标node/src/document.rstype LinkTargetKind external | relative | anchor; interface LinkTarget { kind: LinkTargetKind; value: string; }external带 scheme 的绝对 URLrelative无 scheme 的相对引用按原样保留anchor内部目标指向标题锚点或某个anchor内联元素。List 与 ListItem保留源文档编号type MarkerKind bullet | decimal | lowerAlpha | upperAlpha | lowerRoman | upperRoman; interface List { marker: MarkerKind; // 源文档使用的标记族 start: number; // 首个条目的起始序号 items: ArrayListItem; } interface ListItem { blocks: ArrayBlock; checked?: boolean; // 任务列表复选框状态仅当条目带复选框时 markerLabel?: string; // 字面标记文本当源编号无法由 marker位置重现时使用 // 如 1-a) 这类复合编号文本 }Table规范化网格 合并单元格表格被表示为规范化网格每个逻辑网格位置恰好出现一次。内容与跨行跨列信息放在origin槽位上被覆盖的每个位置则是一个指向 origin 的covered槽位node/src/document.rstype TableKind data | layout; // layout 指文本框、定位表等布局脚手架 interface Table { grid: ArrayArrayCellSlot; // 规范化网格 headerRows: number; // 前导表头行数0 无表头 kind: TableKind; } interface CellSlot { kind: origin | covered; cell?: Cell; // origin单元格内容与跨度 originRow?: number; // covered所属 origin 的行 originCol?: number; // covered所属 origin 的列 } interface Cell { blocks: ArrayBlock; colSpan: number; rowSpan: number; }Note 与 Asset脚注和二进制资源type NoteKind footnote | endnote; interface Note { id: string; kind: NoteKind; blocks: ArrayBlock; } interface Asset { id: number; // 在 Document.assets 中的索引供 image source 引用 mediaType: string; // MIME 类型如 image/png originPart: string; // 来源的包部件或流用于溯源 data: Buffer; // 原始字节 }Asset的字节始终完整保留因此文档在模型层面自包含node/src/document.rs这对需要把图片落盘或转存的对象存储的调用方非常方便。图片与嵌入对象Markdown 里留 alt字节留在 assetsMarkdown 无法内嵌二进制字节因此 anydoc 的处理策略是内嵌图片在 Markdown 中渲染为其 alt 文本原始字节保留在document.assets中并附带 MIME 类型与来源部件originPart带外部 URL 的图片渲染为普通 Markdown 图片alt来源不可用图片部件缺失或不可读且无 URL仅保留 alt 文本。ImageSource用kind区分三种情况node/src/document.rstype ImageSourceKind external | asset | unavailable; interface ImageSource { kind: ImageSourceKind; url?: string; // external assetId?: number; // asset指向 Document.assets 的索引 }在 node/test.mjs 的测试中可以验证toDocument后document.assets中能直接找到mediaType image/png的资源data是合法的BufferBuffer.isBuffer(image.data)且长度大于 0且asset.id等于其在数组中的索引。事件循环友好libuv 线程池上的异步转换这是 Node 绑定区别于其他语言绑定的关键设计。从 node/src/lib.rs 的实现可以看到MarkdownFileTask、MarkdownBytesTask、DocumentTask都是 napi 的AsyncTask其compute方法在libuv 线程池上执行 Rust 转换reject阶段再切回 JS 线程构造携带code的错误对象。这意味着大批量转换不会阻塞事件循环其他请求/IO 照常处理多个转换可在线程池中并行执行错误对象跨线程传递时通过Failure结构保留错误类别避免在线程池上构造 JS 错误那里没有Env。测试与质量保障仓库内的验证手段node 绑定自带冒烟测试node/test.mjs覆盖了本指南涉及的全部行为可作为理解 API 语义的最佳参考资料toMarkdown从内容探测格式并输出标题/^# /mtoMarkdownBytes支持显式格式与自动探测两种路径且断言 CSV 必须显式命名toDocument暴露文档模型标题level在 1–6 之间、内联text与style.bold为布尔值toDocument携带内嵌资源为 Buffer格式探测三函数content/extension/path的行为逐一断言错误分支malformed、unsupported、encrypted、io各类code均被固定下来CLI 的 stdout 输出、-o写文件、stdin 显式格式、退出码 1转换失败与 2用法错误、--help/--version退出码 0 全部有测试用例。仓库的根级tests/fixtures/下维护了一整套各格式 fixture 语料docx、pptx、ods、rtf、epub、pdf 等并配有快照测试tests/snapshots/与健壮性变异测试tests/robustness.rsfuzz/目录还提供了按格式划分的 cargo-fuzz 模糊测试目标。开发与自构建可选如果需要在本地从源码构建 node 绑定cd node npm install npm run build npm testnode/package.json中的脚本说明npm run build使用napi build --platform --release生成当前平台的 release 原生绑定npm test运行node --test执行上述冒烟测试。小结firecrawl/anydoc把 Rust 核心的高性能和文档还原能力带入了 Node.js 生态toMarkdown面向磁盘文件、toMarkdownBytes面向内存字节、toDocument面向需要结构化访问文档模型的场景三者均异步运行于 libuv 线程池error.code错误码、基于内容的格式探测、以及统一文档模型共同构成了构建稳健文档处理管线的基础。更多关于整体架构、基准与各语言绑定Python、WebAssembly、Rust的说明见根目录 README.md。License本项目采用 MIT 开源协议。【免费下载链接】anydocConvert Word, PowerPoint, Excel, OpenDocument, RTF, EPUB, CSV, and PDF to clean Markdown. Built in Rust, with Node.js and Python bindings.项目地址: https://gitcode.com/gh_mirrors/any/anydoc创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表