"知乎收藏夹与文章内容抓取:API/Playwright 多级降级、Cookie 持久化与保活、批量正文与图片、断点续传、可选写入 Obsidian。| Zhihu collection scraping, batch article fetch, Obsidian export."
Resources
5Install
npx skillscat add handsomestwei/zhihu-fetch-skill Install via the SkillsCat registry.
This skill enables reliable scraping of Zhihu collections and article content with automatic fallback between API and Playwright, cookie persistence, and optional Obsidian export. It solves problems caused by Zhihu’s anti-scraping measures and session expiration. Use it when you need to batch download articles or collections for offline storage or knowledge base integration.
知乎数据抓取
从知乎获取收藏夹文章列表与正文 Markdown(含图片本地化),支持写入 Obsidian 知识库。命令与路径约定见下文;可视化说明见仓库根目录 `README.md`。
环境与约定
- 语言:默认与用户语种一致。
- 技能根目录:下文
${CLAUDE_SKILL_DIR}表示本 skill 仓库根目录(部分宿主 UI 中写作{baseDir},含义相同)。脚本均在scripts/下。 - 工作区目录:脚本默认将 Cookie、浏览器用户数据、默认文章输出等放在
OPENCLAW_WORKSPACE环境变量指定的目录;未设置时为~/.openclaw/workspace/。 - 依赖:在
scripts/下执行pip install -r requirements.txt,并playwright install chromium。
登录与可选页面验证
zhihu_login.py:打开浏览器等待登录,默认以检测到z_c0为成功条件即可结束(不要求额外跳转)。- 可选二次校验:若用户希望登录后再确认「某一内需登录页」是否可访问(如某收藏夹页、专栏后台、关注动态等),属可选项,不设则不执行:
- 环境变量
ZHIHU_VERIFY_URL:值为完整http://或https://URL; - 或命令行第一个参数传入同一完整 URL:
python "${CLAUDE_SKILL_DIR}/scripts/zhihu_login.py" "https://www.zhihu.com/..."。 - 脚本会访问该 URL,若正文仍出现知乎通用提示「请登录后查看」,则提示可能未登录完成;否则认为当前会话可访问该页。不限定于收藏夹,任意知乎链接均可(只要登录态相关)。
- 环境变量
zhihu_relogin.py:Cookie 失效、需重新登录并写回zhihu_cookies.json时使用(会打开浏览器)。
触发条件
在用户使用以下任一方式时启用本技能:
- 明确提及:知乎、Zhihu、专栏、收藏夹、文章抓取、批量下载、Cookie、验证码、Obsidian、知识库同步等
- 粘贴 zhihu.com / zhuanlan.zhihu.com 链接并希望获取正文或列表
- 需要 断点续传、图片落盘、反爬 / Stealth 相关协助
工具与脚本路由
按任务选用能力;具体工具名以当前 Agent 环境为准。
常见任务与建议方式
| 任务 | 建议方式 |
|---|---|
| 获取收藏夹 JSON 列表 | Bash → python "${CLAUDE_SKILL_DIR}/scripts/fetch_zhihu_collection.py" <收藏夹URL或ID>;优先 API,失败降级 Playwright DOM |
| 获取个人主页点赞/收藏历史 | Bash → python "${CLAUDE_SKILL_DIR}/scripts/fetch_zhihu_history.py" <people URL 或 slug> <起始时间ISO> <输出.json> [--until <结束时间ISO>];按活动时间保留 interaction_* 元数据,支持断点续跑 |
| 批量抓取正文与图片 | Bash → python "${CLAUDE_SKILL_DIR}/scripts/fetch_zhihu_batch.py" <列表.json> [输出目录] [图片目录];默认输出目录见「路径约定」 |
| 写入 Obsidian Vault | Bash → python "${CLAUDE_SKILL_DIR}/scripts/write_to_obsidian.py" <文章目录> [Vault路径];Vault:命令行优先,否则环境变量 OBSIDIAN_VAULT;会先找 <文章目录>/images,否则兼容同级 zhihu_images |
| 写入个人历史到 Obsidian | Bash → python "${CLAUDE_SKILL_DIR}/scripts/write_zhihu_history_to_obsidian.py" <文章目录> <Vault路径> [.];默认写入 {Vault}/知乎收藏/{分类}/,按 URL 去重更新 |
| 写入失败项清单 | Bash → python "${CLAUDE_SKILL_DIR}/scripts/write_zhihu_failures.py" <Vault路径> <标签>:<progress.json> ...;生成 {Vault}/知乎收藏/抓取失败.md |
| Cookie 失效需人工登录 | Bash → python "${CLAUDE_SKILL_DIR}/scripts/zhihu_relogin.py"(会打开浏览器窗口) |
| 首次登录辅助(可选验证页) | Bash → zhihu_login.py;可选 ZHIHU_VERIFY_URL 或首个参数传入完整 http(s) 链接,见「登录与可选页面验证」 |
| 单篇快速验证 | Bash → fetch_zhihu_api.py / fetch_zhihu_stealth.py / fetch_zhihu_interactive.py / 汇总 fetch_zhihu.py(自动多策略),按场景选用 |
读本地已抓取 Markdown、排查 _progress.json |
Read / Grep |
脚本一览
| 脚本 | 用途 | 典型场景 |
|---|---|---|
fetch_zhihu_collection.py |
收藏夹列表,智能版 | 输出 zhihu_collection_{id}.json |
fetch_zhihu_history.py |
个人历史列表 | 点赞/收藏动态,支持 --until、--fresh、断点续跑 |
fetch_zhihu_batch.py |
批量抓取,推荐 | 大量文章、图片、images/、_progress.json,失败自动重试,DOM 不足时 API 回退 |
fetch_zhihu.py |
自动降级抓取 | 单篇、多策略串联 |
fetch_zhihu_api.py |
API 直连 | 快速测试 |
fetch_zhihu_stealth.py |
Playwright 隐身 | 绕过常见自动化检测 |
fetch_zhihu_interactive.py |
交互式浏览器 | 登录页、验证码 |
write_to_obsidian.py |
写入 Obsidian | 自动检测 Vault、智能分类、知乎收藏/ |
write_zhihu_history_to_obsidian.py |
写入个人历史到 Obsidian | 智能分类、互动元数据、按 URL 去重 |
write_zhihu_failures.py |
写入失败项清单 | 生成 抓取失败.md 方便人工重试 |
zhihu_relogin.py |
重新登录 | Cookie 不可用 |
zhihu_login.py |
登录辅助 | 检测 z_c0;可选访问 ZHIHU_VERIFY_URL / 命令行 URL 做页面级验证 |
zhihu_login_save.py |
登录并保存 | 按需配合 Cookie 流程 |
主流程(推荐执行顺序)
- 安装依赖:
scripts/requirements.txt+ Chromium。 fetch_zhihu_collection.py→ 得到收藏夹 JSON 列表。fetch_zhihu_batch.py→ 生成zhihu_articles_{collectionId}/(含_progress.json、images/、编号*.md)。- (可选)
write_to_obsidian.py→ 同步到{Vault}/知乎收藏/{分类}/。
中断批量任务时:重新运行同一条 fetch_zhihu_batch.py 命令即可续跑(已完成 URL 记录在 _progress.json)。
个人历史流程(点赞 / 收藏)
适用于个人主页动态中的 赞同了回答 / 赞同了文章 / 收藏了回答 / 收藏了文章。时间采用 ISO 格式,建议显式带时区(如 +08:00);若省略时区,默认按 Asia/Shanghai 解释,可用环境变量 ZHIHU_TIMEZONE 或 TZ 覆盖。
# 1. 收集活动列表(起始时间含,结束时间不含)
python scripts/fetch_zhihu_history.py \
https://www.zhihu.com/people/<slug> \
2026-01-01T00:00:00+08:00 \
/path/to/runtime/zhihu_history_2026-01-01_to_2026-04-05.json \
--until 2026-04-05T00:00:00+08:00
# 2. 抓取正文与图片;失败默认自动重试 3 次
python scripts/fetch_zhihu_batch.py \
/path/to/runtime/zhihu_history_2026-01-01_to_2026-04-05.json \
/path/to/runtime/zhihu_articles_history_2026-01-01_to_2026-04-05
# 3. 写入 Obsidian 的知乎收藏根目录分类文件夹
python scripts/write_zhihu_history_to_obsidian.py \
/path/to/runtime/zhihu_articles_history_2026-01-01_to_2026-04-05 \
/path/to/ObsidianVault \
.历史笔记会保留:
interaction_action: "赞同了回答"
interaction_time: 2026-03-20T10:17:57.235000+00:00
interaction_date: 2026-03-20
tags: [zhihu, 编程与开发, 赞同了回答]历史列表中断时重新运行同一条命令即可续跑;加 --fresh 可忽略现有 checkpoint 重建。写入 Obsidian 时会扫描已有笔记的 url 并按 URL 更新,避免重复导入。
路径与输出约定
批量抓取命令格式
python fetch_zhihu_batch.py <列表文件> [输出目录] [图片目录]| 参数 | 说明 |
|---|---|
| 列表文件 | fetch_zhihu_collection.py 产出的 JSON |
| 输出目录 | 可选;省略时默认为 {workspace}/zhihu_articles_{collectionId}/(collectionId 由列表文件名推导) |
| 图片目录 | 可选;省略时默认为 {输出目录}/images/ |
目录结构示例
zhihu_articles_{collectionId}/
├── _progress.json # 断点续传
├── images/ # 默认图片目录
│ └── ...
├── 0001_文章标题.md
└── ...单篇文章格式要点
- YAML frontmatter:
title、author、source、url、voteup、images等 - 正文为 Markdown;图片引用指向本地
images/下文件名(或脚本生成的相对路径)
示例结构:
---
title: "文章标题"
author: "作者"
source: zhihu
url: "https://..."
voteup: 123
images: 5
---
# 文章标题
> 作者: xxx | 原文: [知乎链接](https://...)
正文...持久化文件(默认 workspace)
| 用途 | 路径 |
|---|---|
| Cookie | {workspace}/zhihu_cookies.json |
| Playwright 用户数据 | {workspace}/chrome_user_data/ |
| 默认文章目录 | {workspace}/zhihu_articles_{collectionId}/ |
| 默认图片目录 | {文章输出目录}/images/ |
Obsidian 写入要点
- Vault:① 命令行第二个参数(优先让用户直接写出 Vault 根路径);② 未传时使用环境变量
OBSIDIAN_VAULT(单个路径);③ 仍无时脚本按常见目录扫描,多个命中时再交互选择。 - 分类:优先对齐已有
知乎收藏/子目录;否则按内容关键词;无法归类则 「未分类」。 - 落盘:
{Vault}/知乎收藏/{分类}/{文章标题}.md;图片同步规则见write_to_obsidian.py(目标侧常有集中images目录)。
已知问题与对策
| # | 现象 / 原因 | 处理 |
|---|---|---|
| 1 | Cookie 失效:标题「安全验证」、/account/unhuman |
自动恢复:脚本内置 3 次重试(激进保活:访问文章页+模拟阅读);仍失败则 zhihu_relogin.py |
| 2 | 收藏夹 API 分页:带 include 时列表可能被截断 |
fetch_zhihu_collection.py 已内置 API ↔ DOM 切换;必要时减少 include 或走浏览器分页 |
| 3 | 反爬:Headless 被识别 | Stealth、UA、间隔;必要时 fetch_zhihu_interactive.py |
| 4 | API 正文不完整:include 只给摘要 |
批量与单篇流程中已优先 页面 DOM 拉全文 |
| 5 | 图片下载失败 | 正文仍保留原 URL;排查网络、Referer、过期链接 |
| 6 | Windows 控制台 GBK | 脚本已 sys.stdout.reconfigure(encoding='utf-8') |
| 7 | 批量中断 | 直接再次运行 fetch_zhihu_batch.py,依赖 _progress.json |
| 8 | 失败项累积 | 散发失败自动记录到 _progress.json(含 url/reason/title/timestamp);连续失败 ≥5 次中断并丢弃缓存;用 --retry-failed 参数可重试 |
Cookie 保活机制
脚本内置多层 Cookie 保活策略:
- 主动 TTL 检测(每篇文章):解析 z_c0 的
expires字段,剩余 < 30 分钟时自动触发激进刷新 - 常规保活(每 5-8 篇):访问知乎列表页 + 模拟滚动
- 激进保活(每 ~20 篇):访问实际文章页 + 模拟阅读(停留 2-5 秒 + 滚动)
- 被动检测:每次访问文章时检查是否被重定向到
/account/unhuman或/signin - 自动恢复:检测到失效时,自动尝试 3 次激进保活恢复
- Cookie 备份:每次保活后自动从浏览器提取最新 Cookie 保存到文件(扩展格式含 expires)
- 安全退出:脚本结束前保存最新 Cookie + 当前进度
失败处理策略
脚本采用两级失败处理,区分「文章本身问题」和「环境问题」:
| 场景 | 行为 | 说明 |
|---|---|---|
| 散发失败(中间有成功) | 记录到 _progress.json 的 failed 字段 |
视为文章本身问题(已删除/不可访问),后续跳过 |
| 连续失败 ≥ 5 次 | 中断抓取,丢弃缓存的失败记录 | 视为环境问题(Cookie/网络),下次重试仍可跑 |
工作原理:
- 失败先缓存在内存中,不立即写入进度文件
- 下一条成功时,将缓存的失败记录批量写入进度文件(确认是文章问题)
- 连续失败达到阈值(5 次)时,中断抓取,丢弃缓存(保留重试机会)
相关常量:
CONSECUTIVE_FAIL_THRESHOLD = 5:连续失败阈值CONSECUTIVE_FAIL_INTERRUPT = True:是否在连续失败时中断
重试模式:
python fetch_zhihu_batch.py <列表文件> [输出目录] [图片目录] --retry-failed此模式会清空 failed 列表,只重试之前记录为失败的文章。
故障排查流程
正文全空?
→ Cookie(含 z_c0)→ 是否跳转验证页 → zhihu_relogin.py
图片失败?
→ URL/网络/Referer → Markdown 中仍可保留链接
批量中途停止?
→ 确认 _progress.json → 原命令重跑Agent 自用工作流检查清单
□ 已确认 scripts 依赖与 playwright chromium 可用;必要时提示用户设置 OPENCLAW_WORKSPACE
□ 收藏夹任务:已运行 fetch_zhihu_collection.py 并得到合法 JSON,再执行 fetch_zhihu_batch.py
□ 批量输出路径:知悉默认 {workspace}/zhihu_articles_* 与 images/ 子目录;第三个参数仅在自定义图片目录时需要
□ Obsidian:`write_to_obsidian.py` 的文章目录含 *.md 与 images/;Vault 优先命令行路径或 **`OBSIDIAN_VAULT`**
□ 遇验证页或全文为空:优先 Cookie/重登录,而非重复盲目加大并发
□ 用户仅需单篇或调试:选用 fetch_zhihu_api / stealth / interactive / fetch_zhihu,避免不必要批量