notebooklm-py — 用 Python 程式驅動 Google NotebookLM
Google NotebookLM 沒有公開 API。
按理說,這種情況下你只剩兩條路:要嘛開瀏覽器自動化點按鈕,要嘛放棄自動化。但是 GitHub 上有個 14.9k star 的 repo 選了第三條——它打開 Chrome DevTools,把網頁裡每一次點擊背後的 XHR 請求抓下來,逆向出 Google 內部的 RPC 端點和那些被混淆過的 method ID,然後包成一個 Python SDK。
這個專案叫 notebooklm-py。它今天還在合併 PR,是少見的「非官方 Google 服務客戶端」做到專業到誇張的案例:6,186 unit tests、90% coverage、嚴格 SemVer、完整 ADR 記錄。Teng Lin 一個人寫的。
很多人聽到「沒有 API」會反射性想到 Selenium、Playwright、Puppeteer 那一套。但這個 repo 給了一個更值得想清楚的答案:瀏覽器自動化是為了當人,不是為了當機器。如果你能直接跟對方的 RPC 講話,為什麼還要假裝自己是個會點滑鼠的人?
它到底怎麼跟 NotebookLM 講話
你打開 NotebookLM 網頁時,Chrome DevTools 看到的所有 XHR 請求都打到同一個 endpoint:
1 | https://notebooklm.google.com/_/LabsTailwindUi/data/batchexecute |
這是 Google 內部用的 batchexecute RPC 通訊協定。每個操作對應一個被混淆過的 method ID——例如「建立 notebook」是某串看起來像亂碼的字串、「上傳 source」是另一串、「產生 podcast」又是另一串。這些 ID 是作者透過抓網路流量逆向出來的。
notebooklm-py 做的事情其實很單純:把這些 ID 包成 Python method,加上 retry、auth refresh、idempotency 保護,就成了一個完整的 SDK。
1 | import asyncio |
注意整個 API 是純 async。NotebookLMClient 綁定到開啟它的 event loop,跨 loop 重用會直接 raise RuntimeError、也不 thread-safe——每個 thread 或每個 loop 都要建自己的 client。這個設計選擇背後的理由很明顯:高頻 RPC 場景下,async 是必選項,不是裝飾品。
Playwright 只用在登入那一刻
這個 repo 最值得學的設計決策,是它沒有讓 Playwright 變成主流程。
很多人寫到「沒有 API」就會反射性 pip install playwright,然後從那一刻開始所有事情都會在瀏覽器裡跑。但 notebooklm-py 的選擇是:只有第一次互動式登入時用 Playwright——開個 Chromium 視窗讓你登 Google、把 cookies 抽出來存到 storage_state.json,之後所有 RPC 都直接走 httpx,根本不需要瀏覽器。
1 | notebooklm login |
如果你本地已經登入過 NotebookLM 的 Chrome、Edge、Firefox、Safari、Brave,還可以用 rookiepy 直接從本地瀏覽器 cookie store 抽憑證,連 Playwright 都不用裝:
1 | notebooklm login --browser-cookies chrome |
把瀏覽器當「拿到 cookies 的工具」,而不是「跑 RPC 的執行環境」。這個分界線一畫下去,整個系統的可靠性立刻不一樣——RPC 走 httpx 是純 HTTP 呼叫,可以放進 CI、可以併發、可以背景跑;如果整條路都靠 Playwright,光是 Chromium 佔的記憶體就會讓你不想開太多平行任務。
9 種 web UI 不給你的 artifact
如果 SDK 提供的功能跟網頁上一樣,那其實用 Playwright 也可以做。notebooklm-py 真正值錢的地方,是它把 NotebookLM 後端能生但前端不給下載的東西全部打開了:
| Artifact | Web UI 給嗎 | SDK 給的格式 |
|---|---|---|
| Podcast (audio) | 限線上播放 | MP3 直接下載 |
| Video overview | 限線上看 | MP4 直接下載 |
| Briefing doc | 給 | Markdown |
| Mind map | 限線上展開 | 樹狀 JSON 結構 |
| Study guide | 給 | Markdown |
| Quiz | 限線上做 | JSON / Markdown / HTML |
| Flashcards | 限線上看 | JSON 結構化資料 |
| Data table | 限線上看 | CSV |
| Slide deck | 限線上展示 | PPTX 檔 |
PPTX、Quiz JSON、Mind map 樹狀結構這三個是關鍵。web UI 是不給你的——你只能在頁面上看。如果你要把 NotebookLM 生成的內容餵到別的系統,例如把 quiz 匯進 Anki、把 mind map 接到 Obsidian 的知識圖譜、把 slide deck 套到自家簡報模板——這個 SDK 才是出口。
換句話說:NotebookLM 自己的網頁是給「個人用戶看完就好」的介面。notebooklm-py 是給「想把 NotebookLM 當生產線」的人用的。兩種使用者要的東西本來就不一樣,只是 Google 沒興趣同時服務後者。
認證機制是這個 repo 最棘手的部分
沒有 OAuth、沒有 API key,全靠 Google 帳號 cookies——SID、HSID、__Secure-1PSID、__Secure-1PSIDTS 這幾個。三種取得方式:
- 互動式登入:
notebooklm login開 Playwright 視窗,登完存 storage_state.json - 抽本地瀏覽器:
notebooklm login --browser-cookies chrome - 環境變數:
NOTEBOOKLM_AUTH_JSON直接放 JSON(CI/CD 用)
棘手的地方在於 cookies 會過期,特別是 __Secure-1PSIDTS 會不定期旋轉。SDK 處理了這幾件事:
- 每次 RPC 前自動檢查 CSRF token 是否仍有效
- Cold-start 時主動呼叫
accounts.google.com/RotateCookies補齊失效 token - 長時間執行的 client 可傳
keepalive=<seconds>啟動背景 task 定期 rotate - CLI 提供
notebooklm auth refresh,搭配 cron / launchd / systemd 排程跑
Headless server 沒辦法跑 Playwright 登入,標準做法是先在有顯示器的機器登一次,把 storage_state.json 搬到伺服器或塞進 CI secret。storage_state.json 在系統裡的權重等同密碼——POSIX 系統記得 chmod 600,CI 一律走 secret。
如果你要管多個 Google 帳號,profile 機制把 storage_state 隔開來:
1 | notebooklm profile create work # 建立 "work" profile |
或設 NOTEBOOKLM_PROFILE=work 環境變數切換。
Middleware Chain:可靠性是設計出來的
這個 repo 有一套 7-stage middleware chain 包在每個 RPC 外面:
1 | Drain → Metrics → Semaphore → Retry → AuthRefresh → ErrorInjection → Tracing |
每一層都解決一個具體問題。預設行為:
- 429 限流:尊重
Retry-Afterheader(capped 300 秒),fallback 指數退避min(2^attempt, 30)s + ±20% jitter,重試 3 次 - 5xx / 網路錯誤:同樣指數退避 3 次
- 併發控制:
max_concurrent_rpcs=16(一般 RPC)、max_concurrent_uploads=4(上傳,防 FD 耗盡) - Idempotency:建立類 RPC(建 notebook、加 source)用 probe-then-retry——網路斷線導致回應丟失時,先 list 一次找出已建立的資源,避免重複建立
add_text 是個值得單獨拉出來講的例外:它無法 dedupe,預設標記為 non-idempotent。如果你想強制重試,要明確傳 idempotent=True,否則會 raise NonIdempotentRetryError。這個設計擋住了一個常見的工程意外——同樣的文字被重試到變成三份。
端到端範例:從主題到 Podcast 一條龍
repo 附帶的 docs/examples/research-to-podcast.py 是個經典的串接範例。輸入一個主題,自動深度研究後生 podcast:
1 | import asyncio |
單一指令 python research-to-podcast.py "量子計算最新進展" 就能生出一集 podcast。主流程全程不到 30 行——而這 30 行做的事,如果你硬走 Playwright 路線,光是處理「等深度研究跑完」這個 polling 就會寫到一百行還處理不完。
它真正適合的使用情境
寫完 SDK 不代表所有人都該用。比較值得花力氣串的場景有這幾個:
自動化 Podcast 工廠:餵入 RSS 或新聞 URL 清單,自動跑 generate_audio 產出 MP3,上傳到 podcast host。每日新聞摘要、研究週報廣播這種重複性高、人工成本不划算的內容,跑這個流程很適合。
企業知識庫研究 pipeline:使用者輸入主題 → 跑深度 research → 自動 import 20+ 來源 → 同時產 briefing doc + mind map + study guide → 寫進 Confluence 或 Notion。比走 RAG 系統好的地方是 source citation 是 NotebookLM 親自爬的,引用準確度比 fragmented chunk 強很多。
教育與學習工具:學生上傳教科書 PDF,自動 generate_quiz 加 generate_flashcards 產生練習題,匯出 JSON 餵 Anki 或自家學習平台。把「讀完一章 → 出題」的時間從幾小時壓到幾分鐘。
競爭情報監控:排程定期爬競品官網跟部落格,加進 NotebookLM 後問「跟上週相比訊息策略有什麼變化?」自動產生週報。NotebookLM 對長文做差異比較和總結的能力,比一般 LLM 直接接 prompt 強得多,因為它有完整的 source-grounded context。
AI Agent 整合:repo 附帶 SKILL.md(35KB 完整使用說明),可以註冊給 Claude Code、OpenClaw、Codex 這些 agent,讓 LLM 用自然語言驅動 NotebookLM:
1 | notebooklm skill install |
一句話「幫我把這 5 個 URL 變成 30 分鐘的 deep-dive podcast」就能跑完。
多語言內容本地化:英文 source 直接 generate_audio(language="ja") 產日語 podcast,支援 50+ 語言。比走「英文 podcast → 字幕翻譯 → TTS 重錄」的傳統 pipeline 短得多。
該擔心的事情
帳號封鎖風險是這個 SDK 最大的不確定性。用未公開 API 加自動高頻 RPC,Google 可能視為自動化濫用。建議用次要帳號跑 batch,主帳號只做手動操作。
API 隨時可能變動:Google 的 RPC method ID 是逆向出來的,端點變了 SDK 就掛了。repo 有個聰明的設計——NOTEBOOKLM_RPC_OVERRIDES 環境變數允許社群熱修補不需等發版,但這也代表你不能假設「SDK 永遠跟得上 Google」。
不穩定的操作有幾類:audio、video、quiz、flashcard、infographic、slide-deck 容易因 Google rate limit 而 GENERATION_FAILED,需要 5-10 分鐘後重試。處理時間長:audio 10-20 分鐘、video 15-45 分鐘、deep research 15-30+ 分鐘。生產環境建議用 subagent 背景等待,不要在主流程同步阻塞使用者請求。
Source 上限依方案而定:Standard 50、Plus 100、Pro 300、Ultra 600。批次 import 前先查方案配額,跑到一半被 cap 住會很尷尬。
Python 3.13 + cookies extra 編譯失敗(已知限制),需要 rookiepy 的話請用 3.10–3.12。
真正值得帶走的觀察
「沒有公開 API」不等於「不能程式化」。RPC 端點都在那邊,只是 Google 沒貼說明書。如果一個服務的 web 介面跑得動,背後一定有 HTTP 流量可以分析。問題只是「值不值得花這個逆向工程的力氣」。
notebooklm-py 證明了一件事:當 web UI 卡住生產力的時候,把 Chrome DevTools Network panel 打開來看,往往比繼續用 Playwright 模擬點擊更接近正確答案。瀏覽器自動化是模擬人,但你不是人。
延伸閱讀
- GitHub: teng-lin/notebooklm-py
- PyPI: notebooklm-py
- Google NotebookLM: notebooklm.google.com
- License: MIT










