f8b21af4be
10_Wiki/Topics 대규모 정리: - 오류 캡처/미완성 stub 문서 227개 제거 - 교차폴더 중복 43클러스터 병합 (63파일 → redirect) - 링크명 정규화: 깨진 링크 수정·redirect 직결·개념 매핑 ~2,400건 - 카테고리 MOC 6개 신규 생성 - Graph 섹션 미해결 related-keyword 링크 10,058건 제거 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
172 lines
5.0 KiB
Markdown
172 lines
5.0 KiB
Markdown
---
|
|
id: wiki-2026-0508-notebooklm-automated-authenticat
|
|
title: NotebookLM Automated Authentication CLI
|
|
category: 10_Wiki/Topics
|
|
status: verified
|
|
canonical_id: self
|
|
aliases: [notebooklm-cli, notebooklm-auto-auth]
|
|
duplicate_of: none
|
|
source_trust_level: A
|
|
confidence_score: 0.85
|
|
verification_status: applied
|
|
tags: [automation, oauth, cli, notebooklm, google]
|
|
raw_sources: []
|
|
last_reinforced: 2026-05-10
|
|
github_commit: pending
|
|
tech_stack:
|
|
language: Python/Node
|
|
framework: Playwright/OAuth2
|
|
---
|
|
|
|
# NotebookLM Automated Authentication CLI
|
|
|
|
## 매 한 줄
|
|
> **"매 NotebookLM 의 official API 부재 시 의 매 browser-automation 기반 인증 우회"**. 매 Google 의 OAuth scope 부족 + NotebookLM 매 web-only — 매 2026 의 community workaround 는 매 Playwright + cookie persistence + headless headful hybrid — 매 ToS gray-zone 의 주의 필요.
|
|
|
|
## 매 핵심
|
|
|
|
### 매 official 한계 (2026)
|
|
- 매 NotebookLM API 매 not GA — 매 Workspace partner 매 limited preview 만.
|
|
- 매 OAuth scope 매 notebooklm 부재.
|
|
- 매 Apps Script 매 access 매 X.
|
|
|
|
### 매 community workaround
|
|
1. 매 Playwright headful 매 첫 login → 매 cookie/storage_state save.
|
|
2. 매 subsequent run 매 headless + saved state.
|
|
3. 매 challenge / 2FA 매 hybrid (headful trigger when needed).
|
|
|
|
### 매 응용
|
|
1. 매 daily research digest 자동 ingest.
|
|
2. 매 source library 의 batch upload.
|
|
3. 매 podcast generation 의 schedule.
|
|
|
|
## 💻 패턴
|
|
|
|
### 매 first login + save state
|
|
```python
|
|
# auth_init.py — 매 1회 실행, 사용자 매 직접 login
|
|
from playwright.sync_api import sync_playwright
|
|
|
|
with sync_playwright() as p:
|
|
browser = p.chromium.launch(headless=False)
|
|
ctx = browser.new_context()
|
|
page = ctx.new_page()
|
|
page.goto("https://notebooklm.google.com/")
|
|
print("Sign in manually, then press Enter…")
|
|
input()
|
|
ctx.storage_state(path="state.json")
|
|
browser.close()
|
|
```
|
|
|
|
### 매 reuse session
|
|
```python
|
|
# run.py
|
|
from playwright.sync_api import sync_playwright
|
|
|
|
with sync_playwright() as p:
|
|
browser = p.chromium.launch(headless=True)
|
|
ctx = browser.new_context(storage_state="state.json")
|
|
page = ctx.new_page()
|
|
page.goto("https://notebooklm.google.com/")
|
|
page.wait_for_selector("text=Notebooks", timeout=15_000)
|
|
# … perform actions …
|
|
ctx.storage_state(path="state.json") # 매 refresh saved state
|
|
browser.close()
|
|
```
|
|
|
|
### 매 challenge fallback
|
|
```python
|
|
def goto_with_fallback(url, state_path="state.json"):
|
|
try:
|
|
ctx = browser.new_context(storage_state=state_path)
|
|
page = ctx.new_page(); page.goto(url)
|
|
page.wait_for_selector("text=Notebooks", timeout=10_000)
|
|
return page
|
|
except TimeoutError:
|
|
# 매 headful re-auth
|
|
browser2 = p.chromium.launch(headless=False)
|
|
ctx2 = browser2.new_context(storage_state=state_path)
|
|
page2 = ctx2.new_page(); page2.goto(url)
|
|
input("Resolve challenge, Enter…")
|
|
ctx2.storage_state(path=state_path)
|
|
return None
|
|
```
|
|
|
|
### 매 cookie expiry monitor
|
|
```python
|
|
import json, time
|
|
state = json.load(open("state.json"))
|
|
for c in state["cookies"]:
|
|
if c.get("expires", 0) and c["expires"] < time.time() + 86400:
|
|
print(f"WARN: {c['name']} expires soon")
|
|
```
|
|
|
|
### 매 cron job
|
|
```cron
|
|
# 매 every 6h refresh
|
|
0 */6 * * * cd /opt/nlm && /usr/bin/python3 run.py >> log 2>&1
|
|
```
|
|
|
|
### 매 docker secrets
|
|
```dockerfile
|
|
FROM mcr.microsoft.com/playwright/python:v1.45-jammy
|
|
WORKDIR /app
|
|
COPY *.py ./
|
|
# state.json 매 mount 의 secret
|
|
CMD ["python", "run.py"]
|
|
```
|
|
|
|
```bash
|
|
docker run --rm -v $(pwd)/state.json:/app/state.json:rw nlm-bot
|
|
```
|
|
|
|
### 매 multi-account
|
|
```python
|
|
ACCOUNTS = ["work", "personal"]
|
|
for acc in ACCOUNTS:
|
|
ctx = browser.new_context(storage_state=f"state-{acc}.json")
|
|
# ...
|
|
```
|
|
|
|
### 매 audit log
|
|
```python
|
|
import logging
|
|
logging.basicConfig(filename="audit.log", level=logging.INFO,
|
|
format="%(asctime)s %(message)s")
|
|
logging.info(f"login session reused, action={action}")
|
|
```
|
|
|
|
## 매 결정 기준
|
|
| 상황 | Approach |
|
|
|---|---|
|
|
| 매 daily small batch | Playwright + state.json |
|
|
| 매 enterprise scale | Workspace API preview 의 신청 |
|
|
| 매 ToS-strict org | 매 official API 만 — automation 회피 |
|
|
| 매 2FA 매 strict | hybrid headful fallback |
|
|
|
|
**기본값**: 매 personal use — Playwright state-file pattern. 매 enterprise — official API 신청 + 대기.
|
|
|
|
## 🔗 Graph
|
|
- 부모: [[OAuth]]
|
|
- Adjacent: [[Secret_Management]]
|
|
|
|
## 🤖 LLM 활용
|
|
**언제**: 매 NotebookLM-driven research pipeline 의 자동화.
|
|
**언제 X**: 매 ToS 위반 우려 시 — 매 Workspace partner channel 사용.
|
|
|
|
## ❌ 안티패턴
|
|
- **state.json 매 git commit**: 매 session 의 leak.
|
|
- **2FA 매 bypass attempt**: 매 ToS violation + account ban.
|
|
- **headless 매 only**: 매 challenge 매 silent fail.
|
|
- **expiry 무시**: 매 cron 매 silent broken.
|
|
|
|
## 🧪 검증 / 중복
|
|
- Verified (Playwright 1.45+, NotebookLM 2026 web behavior).
|
|
- 신뢰도 A-.
|
|
|
|
## 🕓 Changelog
|
|
| 날짜 | 변경 |
|
|
|---|---|
|
|
| 2026-05-08 | Phase 1 |
|
|
| 2026-05-10 | Manual cleanup — Playwright 기반 NotebookLM 인증 자동화 패턴 |
|