# ck2 **Repository Path**: huguoling/ck2 ## Basic Information - **Project Name**: ck2 - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-09-28 - **Last Updated**: 2026-09-28 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 知乎本地收藏夹(ZhihuSaver) 一个用 **Python + PySide6 + QtWebEngine** 写的桌面软件:内嵌浏览器浏览知乎, 在页面上**自动注入「收藏到本地」按钮**,把回答 / 文章 / 问题 / 想法的正文、 作者、赞同数、配图等结构化数据全部存到本机,并支持离线预览与导出。 ## 功能 - **内嵌浏览器**:多标签、前进后退、地址栏、持久化登录态(Cookie / 缓存都落在本地)。 页面里的 `window.open`(**第三方登录**、分享等)会开成独立小窗口,`target=_blank` 链接则开新标签页 —— 两者按 `QWebEnginePage.WebWindowType` 分流。 - **自动注入**:页面加载后,在每个 `.ContentItem`(回答 / 文章 / 想法)的操作栏里 插入「收藏到本地」按钮。知乎是 SPA,脚本用 `MutationObserver` + `history` 钩子 + 兜底轮询保证翻页、无限滚动后新出现的卡片同样有按钮。 - **页面顶部导航条**:知乎页面本身没有返回键和回首页的入口,脚本在页面**最顶部**注入 一条固定导航栏,横向排列按钮:**返回 / 前进 / 刷新 / 首页 / 收藏本页**。 展开时给 `body` 补 `padding-top`,不会遮住知乎自己的顶栏;右侧按钮可整体收起为 右上角一个小标签,折叠状态记在 `localStorage` 里,刷新后保持。 - **看得见的工具栏**:应用工具栏的导航按钮一律「图标 + 文字」(返回 / 前进 / 刷新 / 停止 / 首页),不会出现只有图标认不出来的情况。 - **不打扰登录与风控**:`/signin`、`/signup`、`/account/unhuman` 等登录 / 注册 / 安全验证页面**完全不注入任何 UI**(不插样式、不插顶部条、不动 `body` 布局), 让验证码和风控流程跑在原生页面里;登录弹窗、验证码浮层出现时顶部条也会自动让位。 另外,验证码 / 风控相关请求会被强制 `no-cache`,避免拿到缓存里的旧验证码。 - **结构化解析**:从 `data-zop`、`meta[itemprop=*]`、`.AuthorInfo`、`.RichContent-inner` 中抽取标题、问题、作者与主页、赞同 / 评论数、发布时间、原文链接、正文 HTML 与纯文本。 - **本地收藏夹**:SQLite 存储,支持关键词搜索(标题 / 作者 / 正文 / 标签 / 备注)、 类型筛选、多种排序、离线预览、备注与标签、删除。 - **图片本地化**:保存时自动把正文配图下载到 `data/images/`,导出时自动改写为本地路径。 - **导出**:一键导出为 **Markdown**(含目录、元信息、HTML→Markdown 转换)或 **单文件 HTML**(自带样式,可直接分享)。 - **去重**:按 `类型:ID` 归一化主键,同一回答重复收藏只会更新,不会产生副本。 ## 安装 ```powershell python -m pip install -r requirements.txt ``` 需要 Python 3.9+ 与 `PySide6 >= 6.5`(含 `PySide6-Addons`,其中才有 QtWebEngine)。 ## 运行 ### Windows 一键启动 直接双击 `run.bat`,或带参数调用: ```powershell run.bat # 启动应用 run.bat https://www.zhihu.com/question/621836265 # 启动并直接打开指定链接 run.bat --check # 只检查 Python / PySide6 环境,不启动 run.bat --install # 升级依赖后退出 ``` `run.bat` 会自动完成:优先使用项目内 `.venv`,否则依次尝试 `py -3` / `python` / `python3`; 把控制台切到 UTF-8;检测 `PySide6` 与 `PySide6.QtWebEngineWidgets`,缺失时自动 `pip install -r requirements.txt`;最后把多余参数透传给 `main.py`。 ### 直接运行 ```powershell python main.py # 也可以直接带一个知乎链接启动 python main.py https://www.zhihu.com/question/621836265 ``` 首次使用建议在应用内登录知乎(登录态会持久保存),这样时间线、关注流等内容才能正常浏览。 ## 快捷键 | 快捷键 | 功能 | | --- | --- | | `Ctrl+S` | 收藏当前页面 | | `Ctrl+L` | 聚焦地址栏 | | `Ctrl+T` / `Ctrl+W` | 新建 / 关闭标签页 | | `F5` / `Ctrl+R` | 刷新 | | `Alt+←` / `Alt+→` | 后退 / 前进 | ## 数据目录 默认在项目下的 `data/`,可用环境变量 `ZHIHU_SAVER_HOME` 覆盖。 ``` data/ ├── zhihu_saver.db # SQLite:items 收藏内容表 + images 配图索引表 ├── images/ # 正文配图 ├── preview/ # 离线预览生成的 HTML ├── exports/ # 默认导出目录 ├── downloads/ # 浏览器内触发的下载 ├── webprofile/ # QtWebEngine 持久化存储(Cookie、LocalStorage) └── webcache/ # HTTP 缓存 ``` ## 代码结构 ``` main.py 程序入口(QApplication + 主窗口) zhihu_saver/ ├── config.py 路径与常量 ├── storage.py SQLite 持久化层(items / images) ├── inject.js 注入到页面的核心脚本(按钮、解析、桥接) ├── inject.py 把 qwebchannel.js 与 inject.js 安装到 Profile ├── browser.py Profile、QWebEnginePage、多标签 WebView、下载处理 ├── bridge.py QWebChannel 桥接对象(JS ↔ Python) ├── downloader.py 配图下载队列(QNetworkAccessManager,带并发上限) ├── exporter.py Markdown / HTML 导出 + 内置 HTML→Markdown 转换器 ├── panel.py 右侧收藏面板 └── window.py 主窗口(工具栏、菜单、标签页、面板编排) ``` ## 工作原理 1. `inject.py` 向 `QWebEngineProfile` 注册两个脚本: `:/qtwebchannel/qwebchannel.js`(DocumentCreation)与 `inject.js`(DocumentReady), 都运行在 **MainWorld**,因此 `QWebEnginePage.setWebChannel()` 暴露的 `qt.webChannelTransport` 可以被子脚本使用。 2. `inject.js` 建立 `QWebChannel` 连接拿到 `bridge` 对象,并向 Python 拉取已收藏 ID 集合。 3. 扫描 `.ContentItem`,在 `.ContentItem-actions` 末尾追加收藏按钮;未被收藏的显示 「收藏到本地」,已收藏的显示「已收藏」并高亮。 4. 点击按钮 → 抽取卡片数据 → `bridge.saveItem(JSON)` → Python 写入 SQLite → 回传结果 → 按钮切到已收藏态(同时广播新的 ID 集合,所有标签页同步)。 5. `on_saved` 回调把正文图片交给 `ImageDownloader` 异步下载,结果记入 `images` 表。 ## 排查 - **页面上没有出现按钮** 1. 视图菜单 →「重新注入脚本并刷新当前页」; 2. 打开开发者工具确认:地址栏输入 `http://127.0.0.1:1` 打开新标签,再手动导航; 或在「重新注入」后于页面控制台执行 `window.__ZSV_STATE__()`, 应返回 `{loaded: true, bridged: true, saved: [...]}`; 3. `bridged: false` 说明 WebChannel 未连通,检查 `qt.webChannelTransport` 是否存在; 4. `loaded` 为 `undefined` 说明脚本没注入,确认 `inject.js` 文件存在且未被杀软拦截。 - **知乎提示浏览器不受支持**:`browser.py` 会自动把 User-Agent 里的 `QtWebEngine/x.y.z` 标记去掉,得到一个标准 Chrome UA。 - **选择器失效**:知乎改版后,只需调整 `zhihu_saver/inject.js` 里的 `.ContentItem`、`.ContentItem-actions`、`.RichContent-inner` 等选择器, 然后「重新注入脚本并刷新」即可,无需重启。 - **本地调试注入脚本**:设置 `ZHIHU_SAVER_EXTRA_HOSTS=127.0.0.1,localhost`, 脚本就会在本地页面上也生效,方便用假页面联调。 - **安全验证 / 图形验证码「输入正确却一直报错」** 按顺序试这几步: 1. 视图菜单 →「清除网页缓存(保留登录)」——最常见的原因是拿到了缓存里的旧验证码图片, 服务端校验的却是新会话的答案,于是怎么输都不对;这一步不会让你退出登录。 2. 视图菜单 → 勾选「暂停页面注入(登录/验证排查用)」——把本工具对页面的所有改动去掉, 刷新后页面与原生浏览器完全一致,用来确认问题是否由注入引起。排查完取消勾选即可。 3. 还不行的,视图菜单 →「清除 Cookie 与缓存(会退出登录)」,然后重新登录。 4. 若怀疑是运行时数据损坏,直接删除 `data/webprofile/` 与 `data/webcache/` 两个目录 (收藏数据在 `data/zhihu_saver.db`,不受影响)。 ## 已知限制 - 只处理页面 DOM 里已经渲染出来的内容;「展开阅读全文」之前被折叠的正文需要先展开。 - 图片按原始 URL 下载,不做去水印或格式转换。 - 未实现收藏夹分组(用标签 + 备注代替)。