每日备份 2026-03-27

This commit is contained in:
OpenClaw Backup
2026-03-27 23:38:45 +08:00
parent 4f11cd7b03
commit d09281e48c
827 changed files with 6991 additions and 148648 deletions
+197
View File
@@ -0,0 +1,197 @@
#!/usr/bin/env python3
"""
使用飞书 API 和用户访问令牌创建云文档
"""
import requests
import json
import sys
# 飞书应用凭证
APP_ID = "cli_a93815b250b9dcb5"
APP_SECRET = "NogaPY8DiMHMyadOKDW26bqkGPnrOkND"
# 刷新令牌
REFRESH_TOKEN = "eyJhbGciOiJFUzI1NiIsImZlYXR1cmVfY29kZSI6IkZlYXR1cmVPQXV0aEpXVFNpZ25fQ04iLCJraWQiOiI3NjE2ODk0MzA1NzE3OTE0NTczIiwidHlwIjoiSldUIn0.eyJqdGkiOiI3NjE4Mjk3MjkyNDUzMzE3NTgxIiwiaWF0IjoxNzczNzczMDYyLCJleHAiOjE3NzQzNzc4NjIsInZlciI6InYxIiwidHlwIjoicmVmcmVzaF90b2tlbiIsImNsaWVudF9pZCI6ImNsaV9hOTM4MTViMjUwYjlkY2I1Iiwic2NvcGUiOiJhdXRoOnVzZXIuaWQ6cmVhZCBiYXNlOmFwcDpjb3B5IGJhc2U6YXBwOmNyZWF0ZSBiYXNlOmFwcDpyZWFkIGJhc2U6YXBwOnVwZGF0ZSBiYXNlOmZpZWxkOmNyZWF0ZSBiYXNlOmZpZWxkOmRlbGV0ZSBiYXNlOmZpZWxkOnJlYWQgYmFzZTpmaWVsZDp1cGRhdGUgYmFzZTpyZWNvcmQ6Y3JlYXRlIGJhc2U6cmVjb3JkOmRlbGV0ZSBiYXNlOnJlY29yZDpyZXRyaWV2ZSBiYXNlOnJlY29yZDp1cGRhdGUgYmFzZTp0YWJsZTpjcmVhdGUgYmFzZTp0YWJsZTpkZWxldGUgYmFzZTp0YWJsZTpyZWFkIGJhc2U6dGFibGU6dXBkYXRlIGJhc2U6dmlldzpyZWFkIGJhc2U6dmlldzp3cml0ZV9vbmx5IGJvYXJkOndoaXRlYm9hcmQ6bm9kZTpjcmVhdGUgYm9hcmQ6d2hpdGVib2FyZDpub2RlOnJlYWQgY2FsZW5kYXI6Y2FsZW5kYXIuZXZlbnQ6Y3JlYXRlIGNhbGVuZGFyOmNhbGVuZGFyLmV2ZW50OmRlbGV0ZSBjYWxlbmRhcjpjYWxlbmRhci5ldmVudDpyZWFkIGNhbGVuZGFyOmNhbGVuZGFyLmV2ZW50OnJlcGx5IGNhbGVuZGFyOmNhbGVuZGFyLmV2ZW50OnVwZGF0ZSBjYWxlbmRhcjpjYWxlbmRhci5mcmVlX2J1c3k6cmVhZCBjYWxlbmRhcjpjYWxlbmRhcjpyZWFkIGNvbnRhY3Q6Y29udGFjdC5iYXNlOnJlYWRvbmx5IGNvbnRhY3Q6dXNlci5iYXNlOnJlYWRvbmx5IGNvbnRhY3Q6dXNlci5iYXNpY19wcm9maWxlOnJlYWRvbmx5IGNvbnRhY3Q6dXNlci5lbXBsb3llZV9pZDpyZWFkb25seSBjb250YWN0OnVzZXI6c2VhcmNoIGRvY3M6ZG9jdW1lbnQuY29tbWVudDpjcmVhdGUgZG9jczpkb2N1bWVudC5jb21tZW50OnJlYWQgZG9jczpkb2N1bWVudC5jb21tZW50OnVwZGF0ZSBkb2NzOmRvY3VtZW50Lm1lZGlhOmRvd25sb2FkIGRvY3M6ZG9jdW1lbnQubWVkaWE6dXBsb2FkIGRvY3M6ZG9jdW1lbnQ6Y29weSBkb2NzOmRvY3VtZW50OmV4cG9ydCBkb2N4OmRvY3VtZW50OmNyZWF0ZSBkb2N4OmRvY3VtZW50OnJlYWRvbmx5IGRvY3g6ZG9jdW1lbnQ6d3JpdGVfb25seSBkcml2ZTpkcml2ZS5tZXRhZGF0YTpyZWFkb25seSBkcml2ZTpmaWxlOmRvd25sb2FkIGRyaXZlOmZpbGU6dXBsb2FkIGltOmNoYXQubWVtYmVyczpyZWFkIGltOmNoYXQ6cmVhZCBpbTptZXNzYWdlIGltOm1lc3NhZ2UuZ3JvdXBfbXNnOmdldF9hc191c2VyIGltOm1lc3NhZ2UucDJwX21zZzpnZXRfYXNfdXNlciBpbTptZXNzYWdlOnJlYWRvbmx5IHNlYXJjaDpkb2NzOnJlYWQgc2VhcmNoOm1lc3NhZ2Ugc2hlZXRzOnNwcmVhZHNoZWV0Lm1ldGE6cmVhZCBzaGVldHM6c3ByZWFkc2hlZXQ6Y3JlYXRlIHNoZWV0czpzcHJlYWRzaGVldDpyZWFkIHNoZWV0czpzcHJlYWRzaGVldDp3cml0ZV9vbmx5IHNwYWNlOmRvY3VtZW50OmRlbGV0ZSBzcGFjZTpkb2N1bWVudDptb3ZlIHNwYWNlOmRvY3VtZW50OnJldHJpZXZlIHRhc2s6Y29tbWVudDpyZWFkIHRhc2s6Y29tbWVudDp3cml0ZSB0YXNrOnRhc2s6cmVhZCB0YXNrOnRhc2s6d3JpdGUgdGFzazp0YXNrOndyaXRlb25seSB0YXNrOnRhc2tsaXN0OnJlYWQgdGFzazp0YXNrbGlzdDp3cml0ZSB3aWtpOm5vZGU6Y29weSB3aWtpOm5vZGU6Y3JlYXRlIHdpa2k6bm9kZTptb3ZlIHdpa2k6bm9kZTpyZWFkIHdpa2k6bm9kZTpyZXRyaWV2ZSB3aWtpOnNwYWNlOnJlYWQgd2lraTpzcGFjZTpyZXRyaWV2ZSB3aWtpOnNwYWNlOndyaXRlX29ubHkgb2ZmbGluZV9hY2Nlc3MiLCJhdXRoX2lkIjoiNzYxODI5NzI2NjgwOTM1OTU1MyIsImF1dGhfdGltZSI6MTc3Mzc3MzA2MiwiYXV0aF9leHAiOjE4MDUzMDkwNjIsImF0X2lkIjoiNzYxODI5NzI5MjQzNjU3MzExNSIsImF0X2V4cCI6MTc3Mzc4MDI2MiwidW5pdCI6ImV1X25jIiwidGVuYW50X3VuaXQiOiJldV9uYyIsIm9wYXF1ZSI6dHJ1ZSwiZW5jIjoiQWlRa0FRRUNBTUlEQUFFQkF3QUNBUTBBQXdzTEFBQUFBd0FBQUFkR1pXRjBkWEpsQUFBQUVHOWhkWFJvWDI5d1lYRjFaVjlxZDNRQUFBQUlWR1Z1WVc1MFNXUUFBQUFCTUFBQUFBUlVhVzFsQUFBQUNqRTNOek0yTVRreU1EQVBBQVFNQUFBQUFRb0FBV0xGSWxtdmdBQWlDd0FDQUFBQURFNkdsUjZPN0VpWjJQeGh0UXNBQXdBQUFEQmFqSDRQSmx6d2lISDZybXlCZVg4TWRjSHAxc2t0U3R6c3h2U1F5NUtSL2JEYlJhMnhoeVA5RHVYWDFvUTRvaFVBQ3dBRkFBQUFCV1YxWDI1akFKZlhUKzBCWk1PZU5oYVpyVEpIN0JPSTNoYWtLRmdWL2N5S2p2U294eE9nVmxDdStlclZUY2ZscGJFclMxd2hCcVBWU0MvcW1KSThVcGIvc2VlWHpwRTg0QkNRYXM3cHFTY2VuUm9kWit2Rk9nd1dlVC9XazJ6T0ZEZ1hUNmZLbVFnMFBabERJNWhDTHpzYUo0Sjl2dkR4YzNXbXMwdGpTZ201SnlZVHd0dUN1aUt0NCtGSWIxd00rVHJxdGxEeWhNeGxqZz09IiwiZW5jX3ZlciI6InYxIn0.QfPh3o5AW2ekxVLTGG993OwytuQxYkQ3qzCQTSwtSXqxoDwtAFjP2mP0_kPteBGlIHsjBHsAWmfA-HvFYy4SdQ"
def refresh_access_token():
"""使用刷新令牌获取新的访问令牌"""
url = "https://open.feishu.cn/open-apis/authen/v1/refresh_access_token"
headers = {
"Content-Type": "application/json"
}
payload = {
"grant_type": "refresh_token",
"refresh_token": REFRESH_TOKEN,
"client_id": APP_ID,
"client_secret": APP_SECRET
}
print("正在刷新访问令牌...")
resp = requests.post(url, json=payload, headers=headers, timeout=10)
print(f"HTTP 状态码:{resp.status_code}")
print(f"响应内容:{resp.text[:500]}")
try:
data = resp.json()
except:
data = {"raw": resp.text, "code": -1}
if data.get("code") != 0:
raise Exception(f"刷新令牌失败:{data}")
access_token = data["data"]["access_token"]
print(f"✓ 刷新成功,新令牌:{access_token[:30]}...")
return access_token
def create_document(token, title, markdown):
"""使用飞书 API 创建云文档"""
url = "https://open.feishu.cn/open-apis/docx/v1/documents"
headers = {
"Authorization": f"Bearer {token}",
"Content-Type": "application/json"
}
payload = {
"title": title,
"folder_token": "", # 空表示创建在个人空间根目录
}
print(f"正在创建文档:{title}")
resp = requests.post(url, json=payload, headers=headers, timeout=10)
print(f"HTTP 状态码:{resp.status_code}")
data = resp.json()
print(f"响应:{json.dumps(data, indent=2, ensure_ascii=False)[:500]}")
if data.get("code") != 0:
raise Exception(f"创建文档失败:{data}")
doc_token = data["data"]["document"]["token"]
doc_id = data["data"]["document"]["doc_id"]
doc_url = f"https://www.feishu.cn/docx/{doc_token}"
# 更新文档内容
print(f"正在更新文档内容...")
update_document_content(token, doc_token, markdown)
return doc_token, doc_id, doc_url
def update_document_content(token, doc_token, markdown):
"""更新文档内容(使用批量更新 API"""
url = f"https://open.feishu.cn/open-apis/docx/v1/documents/{doc_token}/batch_update"
headers = {
"Authorization": f"Bearer {token}",
"Content-Type": "application/json"
}
# 简单处理:将 Markdown 作为纯文本插入
# 飞书 API 需要特定的块格式,这里简化处理
blocks = []
# 解析 Markdown,转换为飞书文档块
lines = markdown.split('\n')
current_text = []
for line in lines:
if line.startswith('# '):
if current_text:
blocks.append({"text": {"elements": [{"text_run": {"content": "\n".join(current_text)}}]}})
current_text = []
blocks.append({"heading1": {"elements": [{"text_run": {"content": line[2:]}}]}})
elif line.startswith('## '):
if current_text:
blocks.append({"text": {"elements": [{"text_run": {"content": "\n".join(current_text)}}]}})
current_text = []
blocks.append({"heading2": {"elements": [{"text_run": {"content": line[3:]}}]}})
elif line.startswith('### '):
if current_text:
blocks.append({"text": {"elements": [{"text_run": {"content": "\n".join(current_text)}}]}})
current_text = []
blocks.append({"heading3": {"elements": [{"text_run": {"content": line[4:]}}]}})
elif line.startswith('> '):
if current_text:
blocks.append({"text": {"elements": [{"text_run": {"content": "\n".join(current_text)}}]}})
current_text = []
blocks.append({"quote": {"elements": [{"text_run": {"content": line[2:]}}]}})
elif line.startswith('- ') or line.startswith('* '):
if current_text:
blocks.append({"text": {"elements": [{"text_run": {"content": "\n".join(current_text)}}]}})
current_text = []
blocks.append({"bullet": {"elements": [{"text_run": {"content": line[2:]}}]}})
elif line.startswith('1. ') or line.startswith('2. '):
if current_text:
blocks.append({"text": {"elements": [{"text_run": {"content": "\n".join(current_text)}}]}})
current_text = []
content_text = line.split('. ', 1)[1] if '. ' in line else line
blocks.append({"ordered": {"elements": [{"text_run": {"content": content_text}}]}})
elif line.startswith('```'):
if current_text:
blocks.append({"text": {"elements": [{"text_run": {"content": "\n".join(current_text)}}]}})
current_text = []
elif line == '---':
if current_text:
blocks.append({"text": {"elements": [{"text_run": {"content": "\n".join(current_text)}}]}})
current_text = []
blocks.append({"divider": {}})
elif line.strip() == '':
if current_text:
blocks.append({"text": {"elements": [{"text_run": {"content": "\n".join(current_text)}}]}})
current_text = []
else:
current_text.append(line)
if current_text:
blocks.append({"text": {"elements": [{"text_run": {"content": "\n".join(current_text)}}]}})
# 构建请求体
requests_body = {
"requests": []
}
for i, block in enumerate(blocks):
requests_body["requests"].append({
"action": "append_block",
"args": {
"block": block,
"parent_block_id": "",
"index": i
}
})
resp = requests.post(url, json=requests_body, headers=headers, timeout=30)
print(f"更新内容 HTTP 状态码:{resp.status_code}")
data = resp.json()
if data.get("code") != 0:
print(f"警告:更新文档内容部分失败:{data}")
else:
print(f"✓ 成功更新 {len(blocks)} 个块")
def main():
if len(sys.argv) < 3:
print("用法:python3 create_feishu_doc_api.py <title> <content_file>")
sys.exit(1)
title = sys.argv[1]
content_file = sys.argv[2]
# 读取文档内容
with open(content_file, 'r', encoding='utf-8') as f:
markdown = f.read()
print(f"创建文档:{title}")
print(f"内容来源:{content_file}")
print(f"内容长度:{len(markdown)} 字符")
# 刷新访问令牌
access_token = refresh_access_token()
# 创建文档
doc_token, doc_id, doc_url = create_document(access_token, title, markdown)
print(f"\n✓ 文档创建成功!")
print(f"文档 Token: {doc_token}")
print(f"文档 ID: {doc_id}")
print(f"文档 URL: {doc_url}")
return doc_url
if __name__ == "__main__":
main()