很多人使用 Joplin,只是把它当成一个轻量级 Markdown 笔记软件:写笔记、做分类、同步资料。但实际上,Joplin 还有一个容易被忽略的能力——它开放了本地 API。这意味着,Joplin 不只是一个“手动记录工具”,也可以变成一个可以被 Python 调用的本地知识库入口。只要桌面端正在运行,就可以通过脚本自动创建笔记、管理笔记本、添加标签,把外部内容直接写入 Joplin。比如,技术笔记、每日记录、网页摘要、实验日志、项目资料,都可以整理成 Markdown 后自动归档到 Joplin 中。本文就通过一个简单的 Python 示例,演示如何调用 Joplin API,把内容写入本地笔记库。
- Joplin Data API: https://joplinapp.org/help/api/references/rest_api/
- Joplin Clipper Authorization: https://joplinapp.org/help/dev/spec/clipper_auth/
一、Joplin API 是什么
Joplin 提供了一个本地 REST API。它依赖 Joplin 桌面端中的 Web Clipper 服务运行。虽然名字叫 Web Clipper,但它不只服务于网页剪藏。只要服务启动,其他程序也可以通过本机地址访问 Joplin,例如:它的使用方式和普通 REST API 类似。比如创建一条笔记,本质上就是向 /notes 接口发送一个 POST 请求。
二、开启 Joplin Web Clipper 服务
Tools → Options → Web Clipper
这个 token 相当于访问 Joplin 本地数据的钥匙。后续 Python 脚本请求 API 时,都需要携带它。如果端口不同,可以在 Web Clipper 设置页面查看实际端口。
三、先测试 Joplin 服务是否可用
import requestsdefcheck_joplin_service(port=41184): url =f"http://localhost:{port}/ping" response = requests.get(url, timeout=5)if response.text =="JoplinClipperServer":print("Joplin API service is running.")returnTrueprint("Unexpected response:", response.text)returnFalseif __name__ =="__main__": check_joplin_service()
Joplin API service is running.
四、用 Python 创建一条 Joplin 笔记
下面演示最核心的功能:创建一条 Markdown 笔记。将代码中的 YOUR_JOPLIN_TOKEN 替换为自己的 token。 (可参考下图位置找到自己的TOKEN)注意:下面这段 Python 代码本身包含 Markdown 代码块,所以本文档外层使用了四个反引号作为代码围栏,避免 Joplin 渲染时提前截断。import requestsJOPLIN_PORT =41184JOPLIN_TOKEN ="YOUR_JOPLIN_TOKEN"defcreate_note(title, body): url =f"http://localhost:{JOPLIN_PORT}/notes" params ={"token": JOPLIN_TOKEN} data ={"title": title,"body": body} response = requests.post(url, params=params, json=data, timeout=10) response.raise_for_status() note = response.json()return noteif __name__ =="__main__": title ="Python 写入 Joplin 测试笔记" body ="""# Python 写入 Joplin 测试笔记这是一条通过 Joplin Data API 自动创建的笔记。## 记录内容- 支持 Markdown- 支持代码块- 支持自动化写入- 可以继续扩展为知识库归档工具```pythonprint("Hello, Joplin!")```""" note = create_note(title, body)print("Note created successfully.")print("Note ID:", note["id"])print("Title:", note["title"])
运行后,打开 Joplin,就可以看到新创建的笔记。Python 文本内容 → Joplin API → Joplin 本地笔记
五、自动创建指定笔记本
如果希望把自动生成的内容统一放到某个笔记本中,可以先通过 API 创建一个笔记本。Joplin 中的笔记本在 API 里叫 folders。import requestsJOPLIN_PORT =41184JOPLIN_TOKEN ="YOUR_JOPLIN_TOKEN"defcreate_folder(title): url =f"http://localhost:{JOPLIN_PORT}/folders" params ={"token": JOPLIN_TOKEN} data ={"title": title} response = requests.post(url, params=params, json=data, timeout=10) response.raise_for_status()return response.json()if __name__ =="__main__": folder = create_folder("自动归档")print("Folder created successfully.")print("Folder ID:", folder["id"])
创建笔记本之后,再创建笔记时传入 parent_id,就可以把笔记放入指定笔记本。defcreate_note_in_folder(title, body, folder_id): url =f"http://localhost:{JOPLIN_PORT}/notes" params ={"token": JOPLIN_TOKEN} data ={"title": title,"body": body,"parent_id": folder_id} response = requests.post(url, params=params, json=data, timeout=10) response.raise_for_status()return response.json()
if __name__ =="__main__": folder = create_folder("自动归档") note = create_note_in_folder( title="自动归档测试", body="# 自动归档测试\n\n这条笔记会进入指定笔记本。", folder_id=folder["id"])print("Note created in folder.")print("Note ID:", note["id"])
六、查询已有笔记本,避免重复创建
实际使用时,不建议每次都创建一个新笔记本。更合理的做法是:
import requestsJOPLIN_PORT =41184JOPLIN_TOKEN ="YOUR_JOPLIN_TOKEN"defjoplin_url(path):returnf"http://localhost:{JOPLIN_PORT}{path}"defget_folders(): response = requests.get( joplin_url("/folders"), params={"token": JOPLIN_TOKEN}, timeout=10) response.raise_for_status()return response.json()["items"]deffind_folder_by_title(title): folders = get_folders()for folder in folders:if folder["title"]== title:return folderreturnNonedefcreate_folder(title): response = requests.post( joplin_url("/folders"), params={"token": JOPLIN_TOKEN}, json={"title": title}, timeout=10) response.raise_for_status()return response.json()defget_or_create_folder(title): folder = find_folder_by_title(title)if folder:return folderreturn create_folder(title)defcreate_note(title, body, folder_id=None): data ={"title": title,"body": body}if folder_id: data["parent_id"]= folder_id response = requests.post( joplin_url("/notes"), params={"token": JOPLIN_TOKEN}, json=data, timeout=10) response.raise_for_status()return response.json()if __name__ =="__main__": folder = get_or_create_folder("自动归档") markdown_body ="""# 自动写入示例这是一条自动写入 Joplin 的 Markdown 笔记。## 小结通过 Joplin API,可以很方便地把外部内容沉淀到本地知识库中。""" note = create_note( title="Joplin API 自动写入示例", body=markdown_body, folder_id=folder["id"])print("Created note:", note["title"])
七、更新已有笔记
Joplin API 使用 PUT /notes/:id 更新笔记。比如只修改正文:import requestsJOPLIN_PORT =41184JOPLIN_TOKEN ="YOUR_JOPLIN_TOKEN"defupdate_note_body(note_id, new_body): url =f"http://localhost:{JOPLIN_PORT}/notes/{note_id}" params ={"token": JOPLIN_TOKEN} data ={"body": new_body} response = requests.put(url, params=params, json=data, timeout=10) response.raise_for_status()return response.json()if __name__ =="__main__": note_id ="YOUR_NOTE_ID" new_body ="""# 更新后的内容这条笔记已经通过 Python 脚本更新。""" note = update_note_body(note_id, new_body)print("Updated note:", note["title"])
需要注意的是,Joplin 的 PUT 更新并不是必须传入完整笔记数据。只传入需要修改的字段即可,比如只传 title,就只修改标题;只传 body,就只修改正文。
八、给笔记添加标签
defcreate_tag(title): response = requests.post(f"http://localhost:{JOPLIN_PORT}/tags", params={"token": JOPLIN_TOKEN}, json={"title": title}, timeout=10) response.raise_for_status()return response.json()
defadd_tag_to_note(tag_id, note_id): response = requests.post(f"http://localhost:{JOPLIN_PORT}/tags/{tag_id}/notes", params={"token": JOPLIN_TOKEN}, json={"id": note_id}, timeout=10) response.raise_for_status()return response.json()
if __name__ =="__main__": tag = create_tag("Python自动化") note_id ="YOUR_NOTE_ID" add_tag_to_note(tag["id"], note_id)print("Tag added to note.")
这样就可以根据来源、项目、主题等信息自动给笔记打标签。
九、一个更完整的封装版本
注意:下面这段 Python 代码同样包含 Markdown 代码块,因此外层也使用四个反引号。import requestsfrom datetime import datetimeclassJoplinClient:def__init__(self, token, port=41184): self.token = token self.port = port self.base_url =f"http://localhost:{port}"defrequest(self, method, path,**kwargs): params = kwargs.pop("params",{}) params["token"]= self.token response = requests.request( method=method, url=f"{self.base_url}{path}", params=params, timeout=10,**kwargs) response.raise_for_status()if response.text:return response.json()returnNonedefping(self): response = requests.get(f"{self.base_url}/ping", timeout=5)return response.text =="JoplinClipperServer"defget_folders(self): data = self.request("GET","/folders")return data.get("items",[])deffind_folder(self, title):for folder in self.get_folders():if folder.get("title")== title:return folderreturnNonedefcreate_folder(self, title):return self.request("POST","/folders", json={"title": title})defget_or_create_folder(self, title): folder = self.find_folder(title)if folder:return folderreturn self.create_folder(title)defcreate_note(self, title, body, folder_id=None): data ={"title": title,"body": body}if folder_id: data["parent_id"]= folder_idreturn self.request("POST","/notes", json=data)defcreate_tag(self, title):return self.request("POST","/tags", json={"title": title})defadd_tag_to_note(self, tag_id, note_id):return self.request("POST",f"/tags/{tag_id}/notes", json={"id": note_id})if __name__ =="__main__": TOKEN ="YOUR_JOPLIN_TOKEN" client = JoplinClient(token=TOKEN)ifnot client.ping():raise RuntimeError("Joplin API service is not available.") folder = client.get_or_create_folder("自动归档") now = datetime.now().strftime("%Y-%m-%d %H:%M:%S") body =f"""# Joplin API 自动写入测试创建时间:{now}## 内容摘要这是一条通过 Python 自动写入 Joplin 的 Markdown 笔记。## 使用场景- 自动保存技术笔记- 自动生成项目日志- 自动归档学习材料- 自动整理外部文本内容## 代码片段```pythonprint("Write to Joplin by API")```""" note = client.create_note( title=f"自动写入测试 - {now}", body=body, folder_id=folder["id"]) tag = client.create_tag("自动化") client.add_tag_to_note(tag["id"], note["id"])print("Note created successfully.")print("Title:", note["title"])print("ID:", note["id"])
运行后,Joplin 中会自动出现一条新的 Markdown 笔记,并进入“自动归档”笔记本。效果如下:
十、为什么这里要用四个反引号
```pythonprint("hello")```
但是如果代码块内部本身也包含三反引号,例如 Python 字符串里保存了一段 Markdown:body = """```pythonprint("hello")```"""
那么外层如果仍然使用三个反引号,渲染器就会把内部的 ```python 误判为代码块边界,导致代码块提前结束。````pythonbody = """```pythonprint("hello")```"""````
Markdown 的规则是:只有同样长度或更长的代码围栏,才会结束当前代码块。因此外层用四个反引号时,内部三个反引号就只会被当作普通文本,不会破坏渲染结构。
十一、可以进一步扩展的方向
Joplin API 的价值不只是创建一条笔记,而是可以把很多重复性的整理工作自动化。- 把网页摘要、论文笔记、会议记录统一写入本地知识库;
- 定期把某个文件夹中的 Markdown 文件同步进 Joplin。
从这个角度看,Joplin 不只是一个笔记软件,也可以成为一个本地知识库入口。只要外部内容能够整理成 Markdown,就可以通过 API 自动写入 Joplin。
十二、几个使用建议
如果脚本只是自己本地使用,可以先写在代码里测试。正式使用时,更推荐放到环境变量或单独配置文件中。Joplin 对 Markdown 支持很好,标题、列表、代码块、引用块、表格等内容都可以较好保留。自动写入时,尽量先把内容整理成规范 Markdown。自动归档├── 技术笔记├── 项目日志├── 学习记录└── 临时收集
对于自动化脚本来说,可以先创建一条笔记,然后记录 note id。后续如果需要追加内容,就通过 note id 更新这条笔记。
结语
Joplin 的开放性是它很大的优势。通过本地 API,可以把 Joplin 从一个“手动记录工具”扩展成一个“自动化知识库”。Python 脚本负责采集和整理内容,Joplin 负责保存、搜索和同步。两者结合起来,就可以形成一个非常实用的个人知识管理工作流。对于技术学习、项目记录、代码实验和资料归档来说,这种方式足够简单,也足够灵活。