--- name: feishu-embedded-sheet version: 1.0.0 description: | 飞书云文档中内嵌电子表格(Sheet)的读取与写入技能。 当飞书 docx 文档中包含 `` 内嵌表格时,使用本技能进行精准的行列级读写操作。 **触发场景:** - 需要读取飞书文档中内嵌的 Excel/Sheet 表格数据 - 需要向飞书文档中内嵌的 Sheet 写入/更新数据 - 用户提到"文档里的表格"、"内嵌表格"、"剧本表格"等 - 从文档 markdown 中看到 `` 标签 metadata: requires: permissions: ["sheets:spreadsheet:readonly", "sheets:spreadsheet"] identity: bot --- # 飞书文档内嵌 Sheet 读写技能 ## 核心概念 飞书 docx 文档可以内嵌电子表格(Sheet)。通过 `lark-cli docs +fetch` 获取文档 markdown 时,内嵌表格会渲染为: ``` ``` **Token 结构解析:** - 完整 token:`WreDs73X1hrgdFtxdpJcItj2n5c_RuQopk` - `_` 前面部分 = `spreadsheet_token`:`WreDs73X1hrgdFtxdpJcItj2n5c` - `_` 后面部分 = `sheet_id`:`RuQopk` 同一个文档内嵌的多个 Sheet 共享同一个 `spreadsheet_token`,通过不同的 `sheet_id` 区分。 ## 前置步骤:获取 Bot Token 所有操作均使用 **Bot 身份**执行,禁止触发用户授权。 ```bash APP_ID="cli_a931175d41799cc7" APP_SECRET=$(jq -r '.apps[0].appSecret' /root/.openclaw/credentials/xiaoyan/config.json) TOKEN=$(curl -s -X POST "https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal" \ -H "Content-Type: application/json" \ -d "{\"app_id\":\"$APP_ID\",\"app_secret\":\"$APP_SECRET\"}" \ | jq -r '.tenant_access_token') ``` Token 有效期 2 小时,过期需重新获取。 ## 完整执行链路 ### 第一步:从文档中提取 Sheet Token 1. 先通过 `lark_wiki_operate_as_bot` 技能获取文档内容 2. 在返回的 markdown 中查找 `` 标签 3. 解析出 `spreadsheet_token` 和 `sheet_id` ```bash # 获取文档内容(以 wiki 文档为例) LARKSUITE_CLI_CONFIG_DIR=/root/.openclaw/credentials/xiaoyan \ lark-cli wiki spaces get_node --params '{"token":""}' --as bot LARKSUITE_CLI_CONFIG_DIR=/root/.openclaw/credentials/xiaoyan \ lark-cli docs +fetch --doc --as bot ``` ### 第二步:获取 Sheet 元数据(了解表结构) ```bash curl -s -X GET \ "https://open.feishu.cn/open-apis/sheets/v3/spreadsheets/${SPREADSHEET_TOKEN}/sheets/query" \ -H "Authorization: Bearer $TOKEN" | jq '.' ``` 返回信息包括: - `sheet_id`:每个子表的 ID - `title`:子表名称 - `grid_properties.row_count`:总行数 - `grid_properties.column_count`:总列数 - `grid_properties.frozen_row_count`:冻结行数(通常表头行) - `merges`:合并单元格信息 ### 第三步:读取数据 #### 读取指定范围 ```bash # 格式:{sheet_id}!{起始单元格}:{结束单元格} curl -s -X GET \ "https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/${SPREADSHEET_TOKEN}/values/${SHEET_ID}!A1:J196?valueRenderOption=ToString" \ -H "Authorization: Bearer $TOKEN" | jq '.data.valueRange.values' ``` **参数说明:** - `valueRenderOption=ToString`:所有值转为字符串返回(推荐,避免类型混乱) - Range 格式:`{sheet_id}!{列字母}{行号}:{列字母}{行号}` - 行号从 1 开始,列用字母表示(A=1, B=2, ..., Z=26, AA=27...) #### 读取全表 先从元数据获取 `row_count` 和 `column_count`,然后构造完整 range: ```bash # 例:10列196行 curl -s -X GET \ "https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/${SPREADSHEET_TOKEN}/values/${SHEET_ID}!A1:J196?valueRenderOption=ToString" \ -H "Authorization: Bearer $TOKEN" ``` #### 读取结果处理 返回的 `values` 是二维数组,每个元素是一行: ```json { "data": { "valueRange": { "values": [ ["类型", "组件配置", "ID", ...], // 第1行(表头) ["TL\nxxx", "S1前置xxx", null, ...], // 第2行 ... ] } } } ``` - `null` 表示空单元格 - 换行符在值中以 `\n` 表示 - 合并单元格:只有左上角单元格有值,其余为 `null` ### 第四步:写入数据 #### 写入/更新指定行 ```bash curl -s -X PUT \ "https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/${SPREADSHEET_TOKEN}/values" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{ "valueRange": { "range": "'${SHEET_ID}'!A197:J197", "values": [ ["对话测试", "S99主线\n自动\n对话测试", "9999901", "剧情描述", "User", "台词", "User", "润色台词", null, "知识点"] ] } }' ``` #### 批量写入多行 ```bash curl -s -X PUT \ "https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/${SPREADSHEET_TOKEN}/values" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{ "valueRange": { "range": "'${SHEET_ID}'!A197:J199", "values": [ ["行1列A", "行1列B", ...], ["行2列A", "行2列B", ...], ["行3列A", "行3列B", ...] ] } }' ``` #### 更新指定单元格 ```bash # 只更新单个单元格 curl -s -X PUT \ "https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/${SPREADSHEET_TOKEN}/values" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{ "valueRange": { "range": "'${SHEET_ID}'!H50:H50", "values": [["更新后的台词润色内容"]] } }' ``` #### 清空单元格 写入空字符串 `""` 即可清空单元格内容。 ### 第五步:写入后验证 **必须回读验证**,确保写入内容与预期一致: ```bash curl -s -X GET \ "https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/${SPREADSHEET_TOKEN}/values/${SHEET_ID}!A197:J197?valueRenderOption=ToString" \ -H "Authorization: Bearer $TOKEN" | jq '.data.valueRange.values' ``` ## 注意事项 1. **身份限制**:所有操作使用 Bot 身份,需要 Bot 应用对目标文档有编辑权限 2. **权限要求**:Bot 需在飞书开发者后台开通 `sheets:spreadsheet` 权限;目标文档/知识空间需将 Bot 添加为成员并授予编辑权限 3. **合并单元格**:写入合并单元格区域时,只写入左上角单元格即可,其余位置保持 null 4. **行数限制**:单次读取/写入建议不超过 500 行,超大表格请分批操作 5. **并发写入**:避免同时多次写入同一个 Sheet,可能导致数据覆盖 6. **数据类型**:写入时,数字直接用 number 类型,文本用 string,空值用 null 7. **换行符**:需要在单元格内换行时,在字符串中使用 `\n` ## 异常处理 | 错误码 | 含义 | 处理方式 | |--------|------|---------| | `1310251` | spreadsheet_token 格式错误 | 检查是否正确从 sheet token 中拆分出 spreadsheet_token | | `1310201` | 无权限 | Bot 未被添加为文档/知识空间成员,需用户授权 | | `1310212` | Range 格式错误 | 检查 sheet_id 和单元格范围格式 | | `1310214` | 超出表格范围 | 检查行列号是否超出实际表格大小 | ## 与其他技能的配合 - **读取文档内容**:先用 `lark_wiki_operate_as_bot` 技能获取文档 markdown,从中提取 `` 标签 - **多维表格操作**:如果目标是独立的多维表格(Bitable),应使用 `lark_bitable_operate_as_bot` 技能,而非本技能 - **文档写入**:如果需要修改文档中 Sheet 以外的内容(文本、表格等),使用 `feishu-update-doc` 技能