# zreaderpy02 **Repository Path**: Dinomorphia/zreaderpy02 ## Basic Information - **Project Name**: zreaderpy02 - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 1 - **Created**: 2026-09-28 - **Last Updated**: 2026-10-10 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # ZReader · 知乎内容浏览器 基于 **PySide6 + QtWebEngine** 的桌面软件:内嵌浏览器浏览知乎,自动在每张回答/文章卡片上注入「保存」按钮, 一键把结构化内容抓取到本地 SQLite,支持图片本地化、离线阅读、全文检索与 Markdown/HTML/PDF 导出。 技术方案详见 [`知乎内容浏览器-技术实现方案.md`](知乎内容浏览器-技术实现方案.md)。 ## 环境管理(uv) 本项目使用 [uv](https://docs.astral.sh/uv/) 管理虚拟环境与依赖,Python 版本固定为 3.12(见 `.python-version`)。 ```bash # 1) 安装 uv(已安装可跳过) powershell -c "irm https://astral.sh/uv/install.ps1 | iex" # 2) 创建 .venv 并安装全部依赖(含 PySide6 6.8) uv sync # 3) 运行 uv run python main.py ``` Windows 下也可以直接跑启动脚本(会自动定位 uv 并在首次运行时装依赖): ```powershell .\run.bat # 正常启动 .\run.bat --debug # 启动并开放 9222 调试端口 .\run.bat --sync # 先重新安装依赖再启动 ``` 常用命令: | 命令 | 说明 | |---|---| | `uv sync` | 按 `pyproject.toml` 同步虚拟环境 | | `uv add ` | 新增依赖并写入 `pyproject.toml` | | `uv run python main.py` | 在虚拟环境中运行 | | `uv run python -c "import PySide6; print(PySide6.__version__)"` | 校验环境 | ## 功能 | 功能 | 入口 | |---|---| | 浏览知乎(登录态持久化) | 主窗口左侧浏览器,Cookie 存于 `~/.zreader/profile` | | 保存当前卡片 | 页面卡片操作栏的「保存」按钮 / `Ctrl+S`(视口内最大卡片) | | 收藏评论 | 评论操作栏的「收藏」按钮(正文评论区与「评论回复」弹窗里都有) | | AI 摘要 | 收藏时自动用豆包生成摘要,显示在离线页/导出正文上方;右侧选条目点「摘要」可重新生成 | | 本地收藏列表 + 全文检索 | 主窗口右侧面板(SQLite FTS5,trigram 中文分词) | | 离线阅读 | 双击列表条目,加载 `~/.zreader/offline/.html`(正文上方 AI 摘要、下方已收藏评论) | | 导出 | 阅读窗口的「导出 Markdown / 单文件 HTML / PDF」 | 关于「AI 摘要」的几点行为: - **收藏即入队**:正文有变化的条目在落库时标记为待摘要,由后台线程调用豆包生成; 重存且正文没变时不会重复消耗接口,正文变了则旧摘要作废并重新生成。 - **摘要结构**:要求模型只回 JSON(`summary` 一句话 + `points` 3~5 条要点), 解析失败时退化为纯文本摘要,不会因为模型多说一句话就报错。 - **失败可见可重试**:连不上网关会退避重试(默认最多 3 次),仍失败则记下错误; 右侧列表会显示「AI摘要失败」,悬停可看原因,选中后点「摘要」重试。 - **关闭方式**:`set ZREADER_AI=0`,收藏将不再生成摘要。 ### 豆包网关配置(环境变量) 默认指向本机运行的豆包网关,接口为 OpenAI 兼容协议(`/v1/models`、`/v1/chat/completions`): | 变量 | 默认值 | 说明 | |---|---|---| | `DOUBAO_BASE_URL` | `http://127.0.0.1:9090/v1` | API Base URL | | `DOUBAO_API_KEY` | `sk-doubao` | 网关未设密钥时任意非空字符串 | | `DOUBAO_MODEL` | 空 | 留空则自动从 `/v1/models` 取第一个可用模型 | | `DOUBAO_TIMEOUT` / `DOUBAO_MAX_INPUT` / `DOUBAO_MAX_TOKENS` | `90` / `8000` / `800` | 超时、正文截断长度、输出上限 | | `DOUBAO_INTERVAL` / `DOUBAO_BACKOFF` / `DOUBAO_RETRY` | `1` / `15` / `3` | 请求间隔、连不上时的退避、单条最大尝试次数 | | `ZREADER_AI` | `1` | `0` 关闭 AI 摘要 | 关于「收藏评论」的几点行为: - **评论操作栏多一个「收藏」**:正文评论区和「评论回复」弹窗里的每条评论都会注入一个轻量的 「收藏」按钮,与知乎自带的「回复 / 喜欢」同排。 - **自动带上所属回答/文章**:若这条评论所属的回答/文章**还没有收藏**,点「收藏」会先把它 整条抓下来(折叠的先展开)再保存评论 —— 评论表对 `items` 有外键,父级缺失时无法单独存在; 成功后会提示「并已自动收藏所属回答/文章」。父级已收藏时只增量保存评论,不会覆盖正文。 - **同一条评论只存一份**:评论 id 由「所属内容 + 作者 + 时间 + 正文」的内容指纹生成, 所以同一条评论在正文内联列表与回复弹窗里收藏,命中的是同一条记录(不会重复)。 - **弹窗里的评论靠上下文定位**:评论弹窗是挂在 `body` 下的 portal,不在任何 `.ContentItem` 里, 注入脚本会记住「打开弹窗时点击的那张卡片」作为评论归属;因此请在内容页点击评论后再收藏。 关于「保存」的几点行为: - **折叠的回答会自动展开**:知乎折叠卡片在 DOM 里只有服务端下发的截断预览(纯文本 + 省略号), 点保存时会先自动点「阅读全文」,等 React 渲染出完整段落再抓取;万一没展开成功,会提示 「未能展开全文,内容可能不完整」,不会静默存半截。 - **重存即覆盖**:按 `item_id` upsert,对同一条内容再点一次即可刷新为最新/完整版本,离线页会一并重建。 - **不弹新窗口**:点问题卡片、QQ/微信登录等 `target=_blank` 请求一律在当前视图打开, 历史正常累加,前进/后退全程可用。 - **每个操作栏都有按钮**:展开正文后知乎会把操作栏挪到底部并重建,注入脚本会跟着补按钮, 所以折叠态(操作栏在正文中间)和展开态(底部 sticky 操作栏)都能点到。 - **公式离线可读**:知乎公式是 MathJax 生成的内联 SVG(字形定义在文档别处,片段一脱离页面就失效), 保存时会转成**原生 MathML 并保留 LaTeX**:离线阅读直接显示公式(Chromium 内建支持,零依赖), Markdown 导出还原为 `$…$` / `$$…$$`。 ## 快捷键 | 快捷键 | 行为 | |---|---| | `Ctrl+S` | 保存视口内最大的内容卡片(折叠回答先展开再抓取) | | `Ctrl+K` | 聚焦本地收藏搜索框 | | `Ctrl+L` | 聚焦地址栏 | | `Ctrl+=` / `Ctrl+-` / `Ctrl+0` | 放大 / 缩小 / 重置缩放 | | `Ctrl+Shift+D` | 打印注入脚本自检信息(卡片数 / 按钮数 / 桥接状态)到控制台 | | `Alt+←` / `Alt+→` / `F5` | 后退 / 前进 / 刷新 | ## 数据目录 ```text ~/.zreader/ ├─ profile/ QWebEngineProfile 持久化(Cookie / LocalStorage / IndexedDB) ├─ cache/ HTTP 磁盘缓存 ├─ zreader.db SQLite(items / comments / assets / folders / tags / items_fts) ├─ assets//.jpg 本地化图片 ├─ offline/.html 离线阅读页面 └─ exports/ 导出产物 ``` 可用环境变量 `ZREADER_HOME` 重定向整个数据目录。 ## 调试 ```powershell $env:ZREADER_DEBUG_PORT = "9222" uv run python main.py ``` 然后用 Chrome 打开 `http://127.0.0.1:9222`,在 DevTools 里直接调试 `window.__ZREADER__`。 终端默认只输出页面的 warning / error 级日志,以及 ZReader 自己的日志 (第三方脚本的 info 级 `console.log` 会淹没终端,例如 QQ 登录探测本机客户端端口失败的输出)。 需要看全部时: ```powershell $env:ZREADER_VERBOSE_JS = "1" ``` > QQ 网页登录会尝试连接本机 QQ 客户端的本地端口(`localhost.ptlogin2.qq.com:4301/4303/...`), > 没装或没启动 QQ 客户端时必然全部失败,随后自动降级为扫码登录。这是腾讯登录页自身的行为, > Chrome/Edge 上同样会出现,与本软件无关。 ## 知乎改版时的维护点 所有 DOM 选择器集中在 `app/resources/injector.js` 顶部的 `SEL` 常量对象中, 知乎改版只需改这一处,Python 侧零改动。 ## 打包(可选) ```powershell uv run pyinstaller --noconfirm --windowed --name ZReader ` --collect-all PySide6 --collect-all shiboken6 ` --add-data "app/resources;app/resources" ` main.py ```