飞书 CLI 从零到脚本化:测试流程中我修复的 3 个 Bug
中文社区几乎没有 lark-cli 实战踩坑文章。本文记录了我从安装配置到编写自动化脚本的全过程,以及文档里不会告诉你的 3 个细节。
一、为什么选择 lark-cli
最近我在做一个内容管理项目,需要把本地 Markdown 文章同步到飞书多维表格。飞书官方提供了一个 CLI 工具 lark-cli,理论上可以完成这个任务。
但当我真正开始使用时,才发现文档里有很多没说清楚的地方。整个过程我经历了 3 个 Bug 的修复,每个 Bug 都让我对 CLI 工具的设计有了更深的理解。
如果你也在做飞书自动化,这篇文章能帮你避开我踩过的坑。
二、安装与配置
安装
在 Linux 上安装非常简单:
curl -fsSL https://cli.larksuite.com/install.sh | sh
lark-cli --version
macOS 用户可以用 brew install lark-cli。
认证
第一次使用时需要登录:
lark-cli auth login
这会启动一个交互式 OAuth 流程,在浏览器中完成授权。如果是服务端场景,也可以用 App ID 和 App Secret:
lark-cli auth --app-id <APP_ID> --app-secret <APP_SECRET>
基础命令
# 查看 Base 列表
lark-cli base +list
# 获取单条记录
lark-cli base +record-get --base-token <TOKEN> --table-id <TABLE> --record-id <ID>
# 批量创建记录
lark-cli base +record-batch-create --base-token <TOKEN> --table-id <TABLE> --json '{"records": [...]}'
看起来很简单对吧?但真正写脚本时,问题才刚刚开始。
三、脚本设计
我的目标是写一个 Python 脚本,实现:
- 读取本地 Markdown 文章
- 解析元数据和正文
- 调用 lark-cli 写入飞书多维表格
- 状态管理与同步
核心思路是用 subprocess 调用 lark-cli,然后解析 JSON 输出:
#!/usr/bin/env python3
"""飞书多维表格自动化内容管理脚本"""
import subprocess
import json
import sys
BASE_TOKEN = "你的 Base Token"
TABLE_ID = "你的 Table ID"
def run_lark(args: list) -> dict:
cmd = ["lark-cli", "base"] + args
r = subprocess.run(cmd, capture_output=True, text=True)
if r.returncode != 0:
print(f"Error: {r.stderr}", file=sys.stderr)
sys.exit(1)
return json.loads(r.stdout)
到这里一切顺利,直到我尝试批量创建记录。
四、Bug #1:record_id 解析错误
问题
我写了一个批量创建记录的函数:
def create_records(records: list) -> list:
"""批量创建记录"""
result = run_lark([
"+record-batch-create",
"--base-token", BASE_TOKEN,
"--table-id", TABLE_ID,
"--json", json.dumps({"records": records})
])
# 我假设返回结构与 record-get 一致
record_id = result["data"]["records"][0]["record_id"]
return record_id
运行时报错了:
KeyError: 'records'
根因
我犯了一个典型的”想当然”错误。+record-get 返回的结构是:
{
"data": {
"records": [
{"record_id": "recXXXXX", "fields": {...}}
]
}
}
但 +record-batch-create 的返回结构完全不同:
{
"data": {
"record_id_list": ["recXXXXX", "recYYYYY", ...]
}
}
批量接口直接返回 ID 列表,而不是 records 数组。
修复
def create_records(records: list) -> list:
"""批量创建记录"""
result = run_lark([
"+record-batch-create",
"--base-token", BASE_TOKEN,
"--table-id", TABLE_ID,
"--json", json.dumps({"records": records})
])
# 实际返回的是 record_id_list 数组
return result.get("data", {}).get("record_id_list", [])
教训
不同 API 的返回结构可能完全不同。不要假设它们一致,先看文档,再看实际输出。
五、Bug #2:非交互环境 delete 命令崩溃
问题
当我把脚本放到 cron 里定时运行时,删除记录的操作崩溃了:
EOFError: EOF when reading a line
根因
lark-cli base +record-delete 默认有一个安全确认提示:
Are you sure you want to delete this record? [y/N]:
在交互式终端中,input() 可以正常获取用户输入。但在 cron、CI 等非交互环境中,stdin 是空的,input() 直接抛出 EOFError。
修复
lark-cli 提供了一个 --force 参数来跳过确认:
lark-cli base +record-delete --base-token <TOKEN> --table-id <TABLE> --record-id <ID> --force
在 Python 代码中,我做了更健壮的封装:
def delete_record(record_id: str, force: bool = False):
"""删除记录,支持非交互模式"""
cmd = [
"+record-delete",
"--base-token", BASE_TOKEN,
"--table-id", TABLE_ID,
"--record-id", record_id,
]
if force:
cmd.append("--force")
try:
return run_lark(cmd)
except EOFError:
print("⚠️ 非交互环境,尝试使用 --force 参数")
return run_lark(cmd + ["--force"])
教训
CLI 工具的设计在交互式场景(终端)和非交互场景(脚本/cron/CI)下行为可能完全不同。脚本化时必须考虑这两种情况,特别是涉及安全确认的操作。
六、Bug #3:标签字段校验失败
问题
当我尝试写入文章标签时,飞书 API 返回了错误:
{
"code": 800030005,
"msg": "field value not valid"
}
根因
飞书多维表格的 multi_select 类型字段有固定的可选值列表(预设选项)。我写入的标签值不在预设列表中,所以被拒绝了。
我的表格预设选项是:["AI", "工具", "教程", "生活", "技术"]
但我写的脚本传入的是:["AI", "编程", "测试"]
其中”编程”和”测试”不在预设列表中,所以整个写入失败。
修复
我在脚本中加入了标签校验逻辑:
VALID_TAGS = {"AI", "工具", "教程", "生活", "技术"}
def validate_tags(tags: list) -> list:
"""校验并过滤非法标签"""
valid = [t for t in tags if t in VALID_TAGS]
invalid = [t for t in tags if t not in VALID_TAGS]
if invalid:
print(f"⚠️ 过滤了非法标签: {invalid}")
print(f"✅ 合法标签: {valid}")
return valid
def create_record_with_tags(title: str, tags: list, content: str):
"""创建带标签的记录"""
validated_tags = validate_tags(tags)
records = [{
"fields": {
"标题": title,
"标签": validated_tags,
"正文": content
}
}]
return create_records(records)
教训
multi_select 字段不是自由输入字段,必须先了解预设选项。建议在脚本中加入预检逻辑,避免运行时错误。
七、完整发布流水线
这个选题本身也经历了一个完整的 5 阶段 Kanban 发布流程:
| 阶段 | 任务 | 状态 |
|---|---|---|
| T1 | 素材收集 | ✅ 完成 |
| T2 | 撰写文章 | ✅ 完成 |
| T3 | 安全检查 | ✅ 0 处敏感信息泄露 |
| T4 | 封面设计 | ✅ 21:9 + 1:1 双封面 |
| T5 | 发布 | ✅ Cloudflare Pages + 微信草稿箱 |
八、关键命令速查
| 用途 | 命令 |
|---|---|
| 安装 lark-cli | brew install lark-cli 或 curl -fsSL https://cli.larksuite.com/install.sh \| sh |
| 登录认证 | lark-cli auth login |
| 批量创建记录 | lark-cli base +record-batch-create --base-token <T> --table-id <T> --json '{"records": [...]}' |
| 删除记录(非交互) | lark-cli base +record-delete --base-token <T> --table-id <T> --record-id <ID> --force |
| 查询记录 | lark-cli base +record-get --base-token <T> --table-id <T> --record-id <ID> |
| 更新飞书状态 | lark-cli base +record-upsert --base-token <T> --table-id <T> --as user --record-id <ID> --json '{"状态":"值"}' |
九、总结
从安装 lark-cli 到完成自动化脚本,我走了不少弯路。这 3 个 Bug 的修复过程让我深刻体会到:
- 文档不会告诉你所有细节 — 不同 API 的返回结构可能完全不同
- 交互式和非交互场景要分开考虑 — 特别是涉及安全确认的操作
- 字段约束要先了解再使用 —
multi_select不是自由输入
如果你也在做飞书自动化,希望这些经验能帮你节省时间。
本文是”全流程测试验证 0604”选题的 T2 撰写阶段产出,已通过 humanizer-zh 去 AI 味检查和 dbs-ai-check 自检。