还在一页页复制 PPT?我用 Obsidian + Python 一键读完
- 2026-11-10 16:17:10


你有没有遇到过这种场面👇
领导甩过来一个 PPT,说:“这个内容你整理一下。”
你打开一看:
几十页,全是文本,没有原稿,没有备注,没有 Word。
那一刻你是不是也在想:👉 “难道只能一页一页复制粘贴吗?”👉 “我都写代码了,还要干这种体力活?”
别慌,这事儿真的可以自动搞定。
背景:我为什么要“读”PPT?
事情的起因其实很简单。
我需要把 PPT 里的所有文本一次性拷出来,用于后续处理,比如:
写公众号文章
丢给大模型总结
做结构化整理
或者单纯不想再手动复制
但问题来了:
PPT 不是纯文本文件,Obsidian 也不能直接读。
那怎么办?
答案只有一个:
👉 让 Python 出手
整体思路,用一句话说清楚
Obsidian 负责“选文件 + 执行命令”,Python 负责“真正读取 PPT 内容”,最后结果直接进剪贴板。
全程无界面、无手动复制,体验就是一句话:丝滑。
//js //templaterletPYTHON = ['/home/jushen1/miniconda3/envs/py3.10/bin/python'].filter(x=>ea.ns.fsEditor.isfile(x))[0]if(!PYTHON){return}asyncfunctionselect_outlink_file(cfile,extensions){let files = ea.nc.chain.get_outlinks(cfile,false).filter(x=>extensions.contains(x.extension));let file = null;if(files.length==1){file = files[0]}else{file = await ea.nc.chain.sugguster_note(files);}return file;}let pyfile = awaitselect_outlink_file(tp.config.template_file,['py'])if(!pyfile){return}let pypath = ea.ns.fsEditor.abspath(pyfile);let pptfile = awaitselect_outlink_file(tp.config.active_file,['ppt','pptx'])if(!pptfile){return}let pptpath = ea.ns.fsEditor.abspath(pptfile);functionexecAsync(cmd){returnnewPromise((resolve, reject) => {exec(cmd, (err, stdout, stderr) => {if (err) {reject(err);return;}resolve(stdout); // ✅ 这是字符串});});}let stdout = awaitexecAsync(`${PYTHON}${pypath}${pptpath}`);await navigator.clipboard.writeText(stdout);newNotice(stdout.slice(0,100))
第一步:在 Obsidian 里选对文件
这里用的是 Obsidian 的 Templater + 扩展能力。
逻辑很简单:
找到一个
文件(负责读 PPT).py找到当前笔记关联的
.ppt / .pptx自动让你选择(如果不止一个)
你不用记路径,不用复制文件名,
点几下就行。
第二步:异步执行 Python(重点来了)
这里最容易踩坑的是:
👉 Node.js 执行外部命令,返回的不是你想象的“字符串”。
所以我们用一个 包一层 Promise,execAsync
确保拿到的是真正的 stdout 文本。
这一步做对了,后面就全是快乐。
第三步:直接写进剪贴板
拿到 Python 输出的文本后,
干三件事:
写入系统剪贴板
弹个 Notice 提示
随便预览前 100 个字符,确认没翻车
到这里,你已经可以:
👉 Ctrl + V,粘到任何地方
Word、Obsidian、微信编辑器,
想贴哪贴哪。
那 Python 文件干了什么?
一句话版解释:
👉 用 Python 把 PPT 里的每一页、每一个文本框都读出来,拼成纯文本。
具体实现我放在了这个文件里:
#!/usr/bin/env python3import argparseimport osfrom pptx import Presentationtry:import pyperclipCLIPBOARD_AVAILABLE = Trueexcept ImportError:CLIPBOARD_AVAILABLE = Falsedef extract_ppt_text(ppt_path, include_notes=True):prs = Presentation(ppt_path)texts = []for slide_idx, slide in enumerate(prs.slides, start=1):texts.append(f"\n=== Slide {slide_idx} ===")for shape in slide.shapes:# 文本框if shape.has_text_frame:for p in shape.text_frame.paragraphs:if p.text.strip():texts.append(p.text)# 表格if shape.has_table:for row in shape.table.rows:for cell in row.cells:if cell.text.strip():texts.append(cell.text)# 备注页if include_notes and slide.has_notes_slide:notes = slide.notes_slide.notes_text_frame.textif notes.strip():texts.append("[Notes]")texts.append(notes)return "\n".join(texts)def main():parser = argparse.ArgumentParser(description="Extract all text from a PPTX file")parser.add_argument("ppt",help="Path to .pptx file")parser.add_argument("-o", "--output",help="Output text file path (optional)")parser.add_argument("--no-notes",action="store_true",help="Do not include notes pages")parser.add_argument("--clipboard",action="store_true",help="Copy extracted text to clipboard")args = parser.parse_args()ppt_path = os.path.abspath(args.ppt)if not os.path.isfile(ppt_path):raise FileNotFoundError(f"PPT file not found: {ppt_path}")text = extract_ppt_text(ppt_path,include_notes=not args.no_notes)# 输出到文件if args.output:out_path = os.path.abspath(args.output)with open(out_path, "w", encoding="utf-8") as f:f.write(text)print(f"✅ Text written to: {out_path}")# 复制到剪贴板if args.clipboard:if not CLIPBOARD_AVAILABLE:raise RuntimeError("pyperclip not installed, run: pip install pyperclip")pyperclip.copy(text)print("✅ Text copied to clipboard")# 如果既不输出文件也不复制,就直接打印(可重定向)if not args.output and not args.clipboard:print(text)if __name__ == "__main__":main()
(你可以按自己的需求改格式、加页码、加分隔符,完全自由)
为什么我强烈推荐你这么干?
因为这套方案解决的不是“读 PPT”,
而是一个更大的问题:
如何把“封闭格式”的信息,变成可再利用的知识。
一旦你打通了这条链路:
PPT → 文本
文本 → 笔记
笔记 → 再创作
你会发现,
很多以前看起来很麻烦的事,其实都能自动化。