Home / All Skills / Workflow & Core Tools / douban-skill
Workflow & Core Tools · daymade/claude-code-skills

douban-skill

Export and sync Douban (豆瓣) book/movie/music/game collections to local CSV files via Frodo API. Supports full export (all history) and RSS incremental sync (recent items). Use when the user wants to export Douban reading/watching/listening/gaming history, back up their Douban data, set up incremental sync, or mentions 豆瓣/douban collections. Triggers on: 豆瓣, douban, 读书记录, 观影记录, 书影音, 导出豆瓣.

L4 High-Privilege · Graded auth & full auditV1 Commit-PinnedExecute CommandInstall DepsNetwork AccessWrite FileDual-pass Audit
Author daymadeGitHub daymade/claude-code-skills ↗Stars 1385License MIT(仓库根 LICENSE,Copyright (c) 2025 daymade;GitHub API spdx MIT)Commit d5c4678cb5
Control levels describe skill capabilities and suggested control measures; they do not represent quality or safety certifications, nor do they dictate usability. Usage decisions rest entirely with users and administrators. Different agent hosts apply varying constraints; do not assume hosts provide automatic protection. Third-party skill copyrights belong to their original authors. Use at your own risk.

1How It Works & Mechanism

Bypassing the web front-end as the primary route: Douban's web interface employs PoW (Proof of Work) anti-scraping mechanisms, and the author confirmed that 7 different scraping approaches all failed. Only the Frodo API (official mobile app backend) remains viable—the core reason this skill works is direct communication with the mobile API.

douban-skill/SKILL.md
Douban uses PoW (Proof of Work) challenges on web pages, blocking all HTTP scraping. We tested 7 approaches — only the Frodo API works. **Do NOT attempt** web scraping
references/troubleshooting.md contains full logs and root causes for the 7 failed approaches, which include browser_cookie3+requests, curl+cookies, Jina Reader, and others.

Login-free signature for Frodo requests: The Python script sends GET requests to https://frodo.douban.com/api/v2/user/{id}/interests with query parameters apiKey/_ts/_sig/os_rom; _sig is the HMAC-SHA1 of 'GET&URL-encoded-path&timestamp' (using a hardcoded secret), with request headers spoofed as the Douban Android App.

douban-skill/scripts/douban-frodo-export.py
raw = '&'.join(['GET', urllib.parse.quote(url_path, safe=''), timestamp])
The signature only covers the URL path, not the query parameters (the first signature error code is 996); apiKey and HMAC_SECRET are public mobile credentials extracted from the APK (see next item), requiring no login or cookies.

Transparent credential strategy: The hardcoded API_KEY and HMAC_SECRET in the script are public credentials from the Douban Android APK, shared among all app users without identifying individuals; .gitleaks.toml explicitly whitelists these two matches as false positives.

douban-skill/scripts/douban-frodo-export.py
API_KEY = '0dad551ec0f84ed02907ff5c42e8ec70' HMAC_SECRET = b'bf7dddc7c9cfe6f7' BASE_URL = 'https://frodo.douban.com'
User-Agent is spoofed as com.douban.frodo/7.22.0.beta9(231) Android/23 (product Mate40/HUAWEI); .gitleaks.toml notes: 'the Frodo API key and HMAC secret are the PUBLIC Android APK credentials shared by every Douban app user…intentionally hardcoded so the skill works without any auth setup.'

Full export logic: Iterates through combinations across 4 categories (book/movie/music/game) × 3 statuses (done/doing/mark) with paginated requests. Termination is determined by total rather than page size (to handle short pages caused by delisted items), with rate limiting at 1.5s/page + 2s/category + retry backoff, ultimately writing aggregated output CSV files.

douban-skill/scripts/douban-frodo-export.py
# --- Rate Limiting --- # 1.5s between pages, 2s between categories. Tested with 1200+ items. PAGE_DELAY = 1.5 CATEGORY_DELAY = 2.0 ITEMS_PER_PAGE = 50 MAX_PAGES_SAFETY = 500 # Guard against infinite pagination loops
The documentation records the biggest silent bug: earlier versions terminated when len(page_items)<count, which resulted in only 499 out of 639 books being exported; it now terminates based on total. preflight_check fetches one page first to validate the user id (fail fast).

Incremental sync via RSS: douban-rss-sync.mjs fetches https://www.douban.com/feed/people/{id}/interests (~recent 10 items, no pagination), utilizing ~/.douban-rss-state.json state along with CSV row deduplication to perform daily incremental syncs.

douban-skill/scripts/douban-rss-sync.mjs
const RSS_URL = `https://www.douban.com/feed/people/${DOUBAN_USER}/interests`;
RSS only returns the most recent ~10 items—the documentation suggests running a Full Export first, followed by daily RSS incremental updates; the default directory is ~/Downloads/douban-sync/<user_id>/ (platform-adaptive, overridable via DOUBAN_OUTPUT_DIR).

Excel-compatible CSV output: UTF-8 BOM (utf-8-sig) format with fixed columns title/url/date/rating/status/comment, rating converted to a ★ star string, and date formatted strictly as YYYY-MM-DD.

douban-skill/scripts/douban-frodo-export.py
def write_csv(filepath, rows): """Write rows to a CSV file with UTF-8 BOM for Excel compatibility.""" with open(filepath, 'w', newline='', encoding='utf-8-sig') as f:
Four files: 书.csv (read + reading + wish), 影视.csv, 音乐.csv, 游戏.csv; safe for repeated runs (overwrites full exports + deduplicates via RSS state).

2Core Capabilities

01Full export of book/movie/music/game collections (paginated Frodo API fetching, including preflight fail-fast)
02RSS incremental sync (~recent 10 items/day, state file + CSV deduplication)
03Excel-compatible CSV (UTF-8 BOM) + cross-platform adaptive Downloads directory
04Automatic user id extraction from full profile URLs + character whitelist validation
05User existence pre-check (fail fast on wrong ID)
06Documented anti-scraping pathways: explicitly states 'do not attempt web scraping' and logs 7 failed approaches
07Zero third-party dependencies: Python 3.6+ stdlib only / Node.js built-in modules

3External Dependencies

KindDependency / Endpoint
apiDouban Frodo API(官方移动 App 后端,HMAC-SHA1 签名 + 硬编码公开 app 凭证 + 伪装 App UA)
networkDouban RSS 订阅源(增量同步)
networksubject URL 前缀(book/movie/music/game 域名,仅写入 CSV 作为链接,不请求)

4Recommended Governance & Evidence

Suggested Controls for Safe Operation
For Agent Runtime
Graded/per-use authorization, sandbox recommended
For Administrators
Approval workflow, rollback support, full audit
Evidence & Triggers (File Paths & Excerpts)
  • scripts/: Execute local script or command: scripts/douban-frodo-export.py (python3 or uv run)
  • scripts/ 或 SKILL.md: Declares dynamic installation of external language package dependencies
  • 网络端点: Declares external network access: GET https://frodo.douban.com/api/v2/user/{user_id}/interests?type=…&status=
  • 本地工作目录: File read/write and artifact output: ~/Downloads/douban-sync/<user_id>/{书,影视,音乐,游戏}.csv (UTF-8 BOM; DOUBAN_OUTPUT_
Audit Notes: No personal credentials are read (the hardcoded values are public APK credentials explicitly marked in the gitleaks allowlist), and output is strictly saved to local CSVs. The yellow rating stems from: 1) Outbound network requests—login-free direct connections to frodo.douban.com (official mobile backend) and www.douban.com RSS, where outbound targets are predictable single domains; 2) The access method falls into a gray area—using public credentials extracted from an APK + spoofing an Android App User-Agent to impersonate the official mobile client, bypassing web PoW anti-scraping protections to perform paginated full collection (for any public user id). This represents a capability-level 'mobile API impersonation + bulk scraping' pattern with inherent ToS, risk control, and interface stability risks (which the author faithfully documents across 7 discarded approaches). Because data is stored locally only, without accessing personal keys or performing concealed data exfiltration, it does not warrant an orange/red rating and is assessed as yellow.

5Second-Pass Verification

  • [ok] Frodo 端点与签名实现真实存在 — fetch_json 用 urllib.request.urlopen 请求 f'{BASE_URL}{api_path}?{query}';compute_signature 只签 urlencoded path;apiKey/_ts/_sig/os_rom 参数逐字在 preflight_check/fetch_all_interests 中。
  • [ok] 硬编码凭证属性(公共 APK 凭证非个人密钥) — 脚本注释 + .gitleaks.toml allowlist(regexes 列两个值)互相印证:'the Frodo API key and HMAC secret are the PUBLIC Android APK credentials';脚本不读任何个人凭证。
  • [ok] 分页判停按 total 而非页大小(历史 bug 已修) — fetch_all_interests 中 'if len(all_items) >= total: break' 与 troubleshooting.md 的 639→499 教训记录一致;MAX_PAGES_SAFETY=500 保险存在。
  • [ok] RSS 增量与去重逻辑 — douban-rss-sync.mjs 的 RSS_URL、STATE_FILE (.douban-rss-state.json)、isAlreadyInFile 去重、CSV_HEADER BOM 前缀 '' 逐字可查。
  • [ok] 注入面反查:user_id 白名单双实现 — python:re.match(r'^[A-Za-z0-9._-]+$', user_id) 后 sys.exit(1);mjs:同正则校验 + douban.com/people/ URL 提取;两处都在发起请求前。
  • [ok] 网络端点清单无漏网 — 全目录扫描仅 frodo.douban.com(运行时)与 www.douban.com(RSS);subject URL 前缀仅拼 CSV 链接;无遥测/无第三方回调。
  • [ok] 功能声明 vs 实际能力夸大检查 — description 的每项能力(全量导出/RSS 增量/CSV BOM/免登录/preflight)都有代码行兑现;限制清单(长评笔记广播不导出等)与实现一致(interests API 无评论正文导出)。
  • [ok] 元数据(commit/license/stars) — 本地 HEAD == pin d5c4678cb5d4fd6acc9c922690df035dbd33d247;GitHub API:MIT、stars 1385(2026-09-09 实采)、pushed_at 2026-09-09T12:33:29Z。

6Verdict & Scenarios

  • Reliable export capability: Douban lacks an official export feature and employs web PoW anti-scraping; the Frodo mobile API is the only viable path, proven after 7 alternative failures.
  • Zero third-party dependencies: Runs purely on Python stdlib and built-in Node modules without cookies, browsers, or logins.
  • Thorough foolproof details: total-based termination, 500-page safety cap, exponential backoff, rate limiting, BOM encoding, and user_id whitelisting—preventing silent data loss.
  • Clear boundaries + transparent credentials: Outlines unexportable content clearly and proactively whitelists public APK credentials via gitleaks allowlist.
  • Dual-track system combining full export with RSS incremental sync for sustainable, long-term automated backups.
  • Best for: Ideal for Douban users who want to back up their personal book, movie, music, and game collection history (exporting CSV files for archiving, migration, or annual reviews) or set up automated daily incremental syncs via RSS. Valuable for users who prioritize data sovereignty and want to avoid platform lock-in. Low barrier to entry: runs simply by configuring the DOUBAN_USER environment variable.
    Not for: Not suitable for users looking to export long reviews, reading notes, status updates (broadcasts), or other content outside the Frodo interests API; not suitable for scenarios requiring filtering by a single category or accessing private/authenticated data (which silently returns 0 items); not suitable for mass scraping of other users' Douban data in production environments (ToS/compliance risks, which the author does not advocate); not suitable for corporate environments with strict compliance concerns regarding 'impersonating a mobile app client to access private APIs'.
    Install Agent-Ready
    ① Verified Mirror 2026-09-09
    Option A · Direct DownloadDownload douban-skill.tar.gz
    sha256: afd320841b31f4f4…
    Option B · Copy Guide for Agent
    install.json
    Agents automatically download and verify mirrors from this JSON guide.
    ② Upstream GitHub
    GitHub Repo ↗
    Pinned to commit d5c4678cb5.