揮一揮API,帶走所有json
算起來語雀也經營了不算短的時間,去年服務器宕機加之玉伯離開是棄絕該平台的直接原因,但根本上,還是因為意識到這個平台骨子裡是封閉的,自我審查到變態程度,更極難自己對接到主流的AI上;最近還發現又多了一個特定IP不能訪問的毛病。去年一年基本沒動,前年課程數據也都擱置在內僅懷舊。
新學期,論壇整理完畢,順手清理之前數據到語雀。看了下,語雀官方去年底更新了API獲取文檔的說明: https://www.yuque.com/yuque/developer/gyht993a76zg54mv 。仅旗舰版空间可使用,還故意僅寫一個思路,基本就是直白地在說,我不想你往外導數據。唉,開放點,就那麼難嗎⋯⋯
好吧,核心的課程數據也就在一個團隊,自己遷出自己,夠了。
客觀上,雖然是以團隊而非空間為導出單位,畢竟,可以一個個團隊導出所有數據,這就意味著,真有要遷移一個整體空間的要求時,收集到全部團隊API,做好時間間隔設置,是可以整體搬家的。當然,因為噁心的 獨有lakebook,導出的json最多就是存檔,幾乎是不可直接對接別家的。
這就很完美閉環,因為封閉,所以封閉;當初超星家的PDG都沒你噁心。
I generated an image with the prompt: ‘farewell image for a platform called Yuque, depicting its closed nature’.–By Grok
清理完本輪,算真的再見了。
text
import requests
import os
import re
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
API_TOKEN = ''
BASE_URL = 'https://www.yuque.com/api/v2'
TEAM_NAMESPACE = 'qrvbic'
headers = {
'X-Auth-Token': API_TOKEN
}
# 設置重試策略
retry_strategy = Retry(
total=5, # 重試次數
backoff_factor=1, # 重試間隔時間
status_forcelist=[429, 500, 502, 503, 504], # 會觸發重試的 HTTP 狀態碼
allowed_methods=["HEAD", "GET", "OPTIONS"] # 適用於重試的 HTTP 方法
)
adapter = HTTPAdapter(max_retries=retry_strategy)
http = requests.Session()
http.mount("https://", adapter)
# 創建存放導出文件的文件夾
if not os.path.exists(TEAM_NAMESPACE):
os.makedirs(TEAM_NAMESPACE)
# 獲取團隊中的所有 repository
def get_repos(team_namespace):
url = f'{BASE_URL}/groups/{team_namespace}/repos'
try:
response = http.get(url, headers=headers, verify=False)
response.raise_for_status()
except requests.exceptions.RequestException as e:
print(f"Error fetching repositories: {e}")
return []
return response.json()
# 獲取每個 repository 中的文檔
def get_docs(repo_id):
url = f'{BASE_URL}/repos/{repo_id}/docs'
try:
response = http.get(url, headers=headers, verify=False)
response.raise_for_status()
except requests.exceptions.RequestException as e:
print(f"Error fetching documents: {e}")
return []
return response.json()
# 將文檔導出為 Markdown 格式
def export_doc(repo_id, doc_id, title):
url = f'{BASE_URL}/repos/{repo_id}/docs/{doc_id}?raw=1'
try:
response = http.get(url, headers=headers, verify=False)
response.raise_for_status()
except requests.exceptions.RequestException as e:
print(f"Error exporting document '{title}': {e}")
return
# 處理文件名中的非法字符
safe_title = re.sub(r'[\/:*?"<>|]', '_', title)
# 創建 repository 對應的文件夾
repo_dir = os.path.join(TEAM_NAMESPACE, str(repo_id))
if not os.path.exists(repo_dir):
os.makedirs(repo_dir)
# 將文檔保存為 Markdown 文件
file_path = os.path.join(repo_dir, f"{safe_title}.md")
with open(file_path, "w") as f:
f.write(response.text)
# 主邏輯
if __name__ == '__main__':
# 獲取團隊下的所有 repository
repos = get_repos(TEAM_NAMESPACE)
if repos:
# 遍歷每個 repository
for repo in repos['data']:
repo_id = repo['id']
repo_name = repo['name']
print(f"正在導出 repository: {repo_name}")
# 獲取該 repository 下的所有文檔
docs = get_docs(repo_id)
# 導出每個文檔
if docs:
for doc in docs['data']:
title = doc['title']
doc_id = doc['id']
print(f" 導出文檔: {title}")
export_doc(repo_id, doc_id, title)
print("導出完成!")