1. 项目背景与需求解析
飞书作为国内主流的企业协同办公平台,其文档功能在日常工作中被广泛使用。但飞书文档原生格式的封闭性给内容迁移和二次编辑带来了诸多不便:
- 技术文档需要发布到GitHub、博客等Markdown友好平台
- 本地备份需求(飞书文档存在误删风险)
- 需要与使用其他协作工具的团队交换文档内容
- 批量处理大量历史文档的格式转换需求
feishu2md正是为解决这些痛点而生的工具链解决方案。我在为技术团队搭建文档体系时,曾手动复制过上百篇飞书文档,不仅效率低下,还会丢失图片、表格等复杂格式。这个项目就是要实现自动化、保真度高的格式转换。
2. 技术方案设计
2.1 核心架构设计
项目采用分层架构设计:
[飞书API层] → [解析转换层] → [输出处理层]飞书API层:通过飞书开放平台获取文档原始数据
- 使用飞书文档的node-sdk进行认证和调用
- 需要申请企业自建应用并开通文档读写权限
- 特别注意:免费版账号有API调用频次限制
解析转换层:核心转换逻辑实现
- 文档块(block)级解析
- 富文本到Markdown的映射转换
- 特殊元素(表格、图片)处理
输出处理层:结果优化与输出
- 本地文件存储
- 图片等附件下载
- 格式美化(如统一标题层级)
2.2 关键技术选型
语言选择:Node.js (v16+)
- 优势:飞书官方SDK对Node支持最好
- 异步处理适合网络请求密集型场景
核心依赖库:
"dependencies": { "@larksuiteoapi/node-sdk": "^3.0.0", "turndown": "^7.1.1", "turndown-plugin-gfm": "^1.0.2", "axios": "^0.27.2", "fs-extra": "^10.1.0" }转换引擎:Turndown + 自定义规则
- 基础转换使用Turndown库
- 通过addRule()方法扩展飞书特有元素支持
- 使用GFM插件支持GitHub风格的Markdown
3. 核心实现细节
3.1 文档获取与解析
// 初始化飞书客户端 const client = new Client({ appId: process.env.APP_ID, appSecret: process.env.APP_SECRET }); // 获取文档原始内容 const response = await client.docs.documents.get({ document_id: docId }); // 解析文档块结构 const blocks = response.data.document.blocks;飞书文档采用block-based的结构设计,每个block包含:
- block_id: 唯一标识符
- block_type: 段落/标题/表格等
- children: 子块列表
- 其他类型相关属性
3.2 富文本转换实现
针对不同block_type编写转换处理器:
const converters = { paragraph: (block) => { const text = block.paragraph.elements .map(el => el.text_run.content) .join(''); return turndown.turndown(text); }, heading: (block) => { const level = block.heading.style.level; return `${'#'.repeat(level)} ${block.heading.elements[0].text_run.content}\n\n`; }, // 其他类型处理... };3.3 复杂元素处理
表格转换示例:
| Header 1 | Header 2 | |----------|----------| | Cell 1 | Cell 2 |实现要点:
- 解析表格行列结构
- 处理合并单元格情况
- 保持表头与内容对齐
- 支持表格内嵌其他元素
图片处理流程:
- 从飞书获取图片临时下载链接
- 使用axios下载到本地/images目录
- 替换为相对路径引用格式:

4. 高级功能实现
4.1 批量转换模式
通过文档目录接口实现批量处理:
const folderItems = await client.drive.folder.list({ folder_token: folderToken }); for (const item of folderItems.data.files) { if (item.type === 'docx') { await convertDocument(item.token); } }4.2 自定义模板支持
通过配置文件支持不同场景的Markdown输出:
# config.yaml templates: blog_post: frontmatter: true image_dir: assets/images heading_level_offset: 14.3 增量同步机制
利用飞书文档版本号实现增量更新:
- 记录已转换文档的version字段
- 定期检查版本变更
- 只处理有变动的文档
5. 部署与使用指南
5.1 环境配置
- 申请飞书开发者账号
- 创建自建应用并开通权限:
- 获取app_id和app_secret
- 开通:docs.doc:readonly权限
- 安装Node.js环境
5.2 基础使用
安装:
npm install -g feishu2md单文档转换:
feishu2md convert --doc https://example.feishu.cn/docx/DOCx123456批量转换:
feishu2md batch --folder https://example.feishu.cn/drive/folder/FOLx7890125.3 配置说明
配置文件示例(~/.feishu2mdrc):
{ "app_id": "cli_xxxxxx", "app_secret": "xxxxxx", "output_dir": "./output", "image_handling": "download" }6. 常见问题与解决方案
6.1 权限问题排查
症状:API返回权限错误
- 检查应用是否开通了文档读取权限
- 确认访问的文档是否在应用可见范围内
- 企业管理员是否已审核通过应用
6.2 格式错乱处理
标题层级不匹配:
- 使用--heading-level参数调整输出层级
- 在配置文件中设置heading_level_offset
表格对齐问题:
- 安装prettier进行Markdown后处理
- 使用column-width插件控制列宽
6.3 性能优化建议
- 对于大批量文档:
- 增加--delay参数控制请求间隔
- 使用--workers启动多进程处理
- 图片处理:
- 使用--skip-images跳过图片下载
- 配置CDN地址直接引用飞书图片链接
7. 开发扩展建议
7.1 支持更多元素类型
当前尚未完美支持的元素:
- 内嵌的思维导图
- 代码块语言检测
- 任务列表的状态同步
7.2 输出格式扩展
可增加的输出格式支持:
- 微信公众号排版格式
- Confluence Wiki格式
- PDF导出(通过pandoc转换)
7.3 与企业流程集成
可能的集成方向:
- Git Hook自动同步文档到代码仓库
- CI/CD流水线中的文档自动化处理
- 与知识管理系统对接
实际使用中发现,转换100页左右的文档平均耗时约30秒(含图片下载),内存占用稳定在200MB以内。对于特别复杂的文档,建议分拆处理以获得更好性能。