# zreaderpy **Repository Path**: DavidMartinez12/zreaderpy ## Basic Information - **Project Name**: zreaderpy - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 4 - **Created**: 2026-10-14 - **Last Updated**: 2026-10-14 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # ZReader —— 知乎阅读器(收藏 + AI 摘要/分类 + 公式 + 导出) 基于 **Python + PySide6(Qt) + QtWebEngine** 的桌面软件:内置浏览器浏览知乎, **自动向页面注入「收藏」按钮**,一键把回答 / 文章 / 想法的**完整正文**保存到本地收藏库; 收藏时调用 **豆包(火山方舟)/ DeepSeek(或任意 OpenAI 兼容接口)** 自动生成摘要、自动分类、补充标签; 支持**行内 / 段间公式**渲染,并可导出 **PDF / HTML / Markdown**。 ## 功能 - **内嵌浏览器**:基于 `QWebEngineView`,独立的持久化 Profile,登录状态、Cookie、 缓存都会被保存,下次打开无需重新登录。 - **SPA 友好的前进/后退**:知乎站内跳转几乎全是 `history.pushState`(不刷新页面), Qt 自带的 `back()/forward()` 对这类同文档历史条目不可靠。程序改为优先调用页面自身的 `history.back()/forward()`(与真实浏览器一致,SPA 路由能正确响应 `popstate`), 仅在 URL 确实未变化时才退回 Qt 的会话历史。 - **自动注入「收藏」按钮**:页面加载后自动识别所有内容卡片 (`.ContentItem.AnswerItem` / `.ArticleItem` / `.PinItem` / `.List-item[data-zop]`), 在卡片操作栏插入「收藏」按钮;已收藏的内容显示为「已收藏」,再次点击可取消。 - 收藏的同时会把该内容(完整正文 + 公式)自动渲染成一份独立 HTML 文件存到 下载目录,点一次「收藏」即完成本地留存,可直接带走 / 分享(可在设置里关闭)。 - 使用 `MutationObserver` + 定时兜底扫描,兼容知乎的无限滚动、虚拟列表与前端路由; - 只在 `*.zhihu.com` 生效,不会污染其它网站; - **单页内容同样支持**:打开单篇文章(`zhuanlan.zhihu.com/p/xxx`)或单条回答 (`/question/xxx/answer/xxx`)时,右下角会出现悬浮「收藏」按钮,走同样的完整正文提取。 - **每条评论 / 楼中楼回复都支持**:评论区展开后,会在每条评论操作栏的 **「喜欢 / 回复」前面**补一个「**收藏评论**」按钮(收藏后变「已收藏」); 外形与正文里的「收藏」按钮完全一致(同书签图标 / 同高度内边距圆角 / 同悬停与已收藏配色), 只有文案区分,一眼能看出收藏的是评论而不是整篇; - 识别方式:先按 `.CommentItem` / CSS Module 类名扫描;**如果一个都没匹配到** (知乎整站改类名),再用每条评论的「回复」按钮反推评论节点,因此不依赖类名; - 正文节点认不出时取「文字最多的子节点」当正文,保证照样能拿到完整评论内容; - 排版跟随原生操作栏(有 flex gap 用 gap,否则沿用锚点外边距): - 收藏后以「评论」类型入库,标题为「作者 + 正文摘要」,并记录所属回答 / 文章 作为「问题」字段,点开可跳回原文上下文;作者区若有「IP 属地」也会一并记下, 本地列表显示为「作者 · 属地」(如 `void · 北京`); - 收藏时和文章一样把该条评论(含图片与公式)自动存成**独立 HTML 文件**到下载目录, 同时另存一份原文 `.txt`,一步完成本地留存; - **连同上下文一起收藏**(默认开启,可用设置里的同名开关关闭): - 收藏某条**评论** → 连同它所属的**回答 / 文章**同步收藏; - 收藏某条**楼中楼回复** → 连同它所在的那条**评论**和**整篇原文**同步收藏; - 每一层都单独入库(记录自己的标题、作者、完整正文),并各自生成一个 HTML 与 `.txt`,取消收藏时也只影响那一条; - 已经在收藏库里的层级会自动跳过,不会重复下载、也不会反复保存同一篇文章; - 收藏完成后页面上父评论 / 原文卡片的「收藏」按钮会一起变成「已收藏」。 - 评论编号依次尝试节点属性、React props、内容指纹,保证「已收藏」状态可回填、 再次点击可取消。 - **原生「更多」菜单也已接入**:点击评论 / 回答右上角的「更多(⋯)」弹出的菜单里, 原生「收藏」项会被接管为「收藏到 ZReader 本地」,因此回答与评论都能从原生菜单 直接完成「收藏 + 自动落盘」(完整正文提取与内联按钮一致)。 - **完整正文提取**:收藏时先自动点掉「阅读全文」展开折叠内容,再用站内接口 (`/api/v4/answers|articles/{id}?include=content`)取回完整正文; 接口不可用时静默回退到页面 DOM,不会因为长回答只保存一半。 - **AI 摘要与自动分类**(豆包 / DeepSeek / 免费接口 / OpenAI 兼容): - 收藏后后台自动生成中文摘要(字数可配),并写入收藏库; - 根据**摘要 + 标签**从分类体系中挑选最合适的分类(只会输出候选分类之一,避免分类爆炸); - 同时提炼 3-6 个标签;摘要、分类、标签一次请求完成,省 token; - 可在「AI → AI 与公式设置…」里配置 Key / 模型 / 温度 / 提示词 / 分类体系,并一键测试连接; - 也可以对历史收藏批量补处理(`AI → 批量处理尚未摘要的内容…`)。 - **本地关键词兜底分类**:未启用 AI、请求失败或模型返回「未分类」时, 按 **标签 > 标题 > 正文** 的加权关键词规则自动归类(离线可用,可在设置里关闭)。 - **公式支持(行内 / 段间)**:知乎把公式渲染成图片或 `data-tex` 节点,保存时会还原成 LaTeX: - **行内公式**输出 `\( ... \)`(Markdown 为 `$...$`),**段间公式**输出 `\[ ... \]`(`$$ ... $$`); - 阅读视图与 HTML / PDF 导出用 **MathJax** 排版,离线时自动降级为等宽 LaTeX 源码; - 正文里的公式数量会记录到数据库(`has_math`),列表与详情都会标记「含公式」。 - **本地收藏库(SQLite)**:保存标题、问题、作者、作者简介、头像、原文链接、 正文 HTML/纯文本、AI 摘要、分类、标签、赞同数、评论数、发布时间、收藏时间、收藏夹、备注等字段。 - **图片本地化**:收藏时后台线程下载正文图片到本地,断网也能看图(可关闭)。 - **原文另存本地**(默认开启):收藏时把完整正文纯文本另存为 `.txt` (目录为数据目录下的 `raw_text`,可在设置里关闭或自定义)。 - **收藏即落盘 HTML**(默认开启):收藏成功后自动把该条内容(完整正文 + 公式 + AI 摘要) 渲染成独立 HTML 存到下载目录,因此页面上不再有单独的「下载」按钮; 收藏评论 / 回复时,同步收藏的父评论与原文也各自生成一份 HTML。 - **整页快照**(可选):额外保存收藏时的整页 HTML。 - **阅读视图**:用 WebEngine 渲染收藏正文(支持 MathJax 公式),顶部展示 AI 摘要、 分类与标签,可就地修改分类、重新生成摘要、导出当前条。 - **收藏库面板**:关键词搜索(含摘要)、按收藏夹 / 类型 / **分类**筛选(另有「只看评论」 一键查看收藏的评论)、**「导出评论」一键把收藏的评论合并导出为一个 HTML**(落到下载目录)、 查看详情、移动收藏夹、删除、复制链接、在内置浏览器打开原文, 作者列显示「作者 · 属地/简介」;右键菜单可直接「生成 AI 摘要与分类」「修改分类」 「导出收藏评论为 HTML」。 - **导出**:所选(或全部筛选结果)导出为 **Markdown / HTML / PDF**,单条一个文件或合并成合集, 已本地化的图片会一起复制到导出目录;PDF 走 WebEngine 打印,公式先排版再打印。 - **下载保存**:内置下载队列(进度 / 大小 / 取消 / 清除已完成),保存位置可固定为 下载目录或每次询问;右键菜单提供「图片另存为…」「链接另存为…」「复制图片/链接地址」 「用系统浏览器打开链接」「保存本页为 HTML…」。 ## 环境要求 - Python 3.9+(推荐 3.10+) - [uv](https://docs.astral.sh/uv/)(用于管理虚拟环境与依赖) - Windows / macOS / Linux 桌面环境 安装 uv(任选其一): ```bash powershell -c "irm https://astral.sh/uv/install.ps1 | iex" # Windows curl -LsSf https://astral.sh/uv/install.sh | sh # macOS / Linux ``` ## 安装与运行(uv) ```bash uv sync # 创建 .venv 并按 uv.lock 精确安装依赖(含 dev 分组) uv run zreader # 启动程序 ``` ### Windows 一键启动 双击项目根目录的 **`run.bat`** 即可(也可在命令行调用,参数会原样传给程序): | 场景 | 命令 | | --- | --- | | 启动 | `run.bat` | | 白屏 / 无 GPU | `run.bat --software-render` | | 自定义数据目录 | `run.bat --data-dir D:\Data` | | 查看全部参数 | `run.bat --help` | | 环境变量开启软件渲染 | `set ZREADER_SOFTWARE_RENDER=1` 后执行 `run.bat` | 脚本行为:自动切换到自身所在目录 → 检测 `uv`(首次运行自动执行 `uv sync` 安装依赖)→ 启动程序;若机器上没有 uv,会依次尝试 `.venv` 中的 Python、 系统 Python 运行;启动失败时保留窗口并给出提示。 等价的其它启动方式: ```bash uv run python -m zreader # 以模块方式启动 uv run main.py # 运行源码入口 ``` 无 GPU 的虚拟机 / 远程桌面环境下若出现白屏,使用软件渲染启动: ```bash uv run zreader --software-render ``` 其它参数: ```bash uv run zreader --data-dir D:\ZReaderData # 自定义数据目录 uv run zreader --url https://www.zhihu.com/question/621836265 uv run zreader --force-gpu # 虚拟机/黑名单显卡:强制硬件加速,改善滑动流畅度 # Windows PowerShell 设置环境变量后打开开发者工具窗口 $env:ZREADER_DEBUG_TOOLS=1; uv run zreader ``` ## 开发环境(uv) | 场景 | 命令 | | --- | --- | | 同步/更新环境 | `uv sync` | | 添加运行时依赖 | `uv add httpx` | | 添加开发依赖 | `uv add --dev pytest` | | 升级锁定版本 | `uv lock --upgrade` | | 执行任意命令 | `uv run python -c "import zreader"` | | 代码检查 | `uv run ruff check .` | | 代码格式化 | `uv run ruff format .` | | 导出传统 requirements.txt | `uv export --no-dev -o requirements.txt` | | 构建发行包 | `uv build` | 依赖声明集中在 `pyproject.toml`,锁定结果在 `uv.lock`(应提交到版本库); 虚拟环境位于 `.venv/`(已加入 `.gitignore`)。 > 依赖源:`pyproject.toml` 中的 `[[tool.uv.index]]` 默认指向清华 PyPI 镜像, > 网络可直连 PyPI 时删除该段即可。 ## 使用说明 1. 启动后在地址栏打开知乎(首次建议点「首页」后登录一次,登录状态会持久保存)。 2. 打开问题页 / 专栏页,等待页面渲染完成,每条回答右下角操作栏会出现蓝色的「收藏」按钮。 3. 点击即可保存(会自动展开「阅读全文」并取回完整正文,同时把这份内容自动存成 HTML 落到下载目录);按钮显示「已收藏」时,再点一次会询问是否取消收藏。 4. 评论区展开后每条评论 / 回复前面都有「收藏评论」(样式与正文的「收藏」按钮一致),点一下即把该条连同它的父评论 与所属回答 / 文章一起收藏并落盘(可在 **设置 → 常规** 里关闭「收藏评论 / 回复时, 连同它的父评论与所属文章一起收藏」)。 5. 右侧「收藏库」面板可以搜索、按分类筛选、打开阅读视图、导出 PDF / HTML、删除。 6. 配置好豆包 / DeepSeek 的 API Key 后,收藏会自动补齐摘要与分类。 ### AI 摘要与自动分类(豆包 / DeepSeek / 免费接口 / OpenAI 兼容) 1. 打开 **设置 → AI 摘要与分类**(或菜单 **AI → AI 与公式设置…**): - 勾选「启用 AI」; - 服务商四选一(切换时会自动填充对应的 API 地址与模型): - **DeepSeek**(默认 `https://api.deepseek.com`,模型 `deepseek-chat`); - **豆包(火山方舟 Ark)**(默认 `https://ark.cn-beijing.volces.com/api/v3`, 模型可填控制台的**推理接入点 ID**(`ep-xxxxxx`)或官方模型名如 `doubao-1-5-pro-32k-250115`); - **免费接口(OpenAI 兼容)**:填任意兼容接口的 `base_url` / 模型,**可不填 API Key**; - **自定义(OpenAI 兼容)**:填自己的 `base_url` / 模型; - 填入 **API Key**(免费接口可选),点「测试连接」确认可用; - 需要时修改摘要字数、温度、超时、送入模型的最大字数; - 「分类体系」每行一个分类,AI 只会从中挑选(默认 16 类,含兜底「未分类」)。 2. 勾选「收藏后自动生成摘要 / 自动分类 / 自动补充标签」后,收藏动作会触发后台任务, 完成后自动写回数据库并刷新列表(鼠标悬停标题可预览摘要)。 3. 手动处理:选中若干条 → 右键「生成 AI 摘要与分类」,或菜单 **AI → 为所选生成摘要 / 分类**;历史数据可用 **AI → 批量处理尚未摘要的内容…** 补齐。 4. 失败会在状态栏提示,并把该条标记为 `ai_status = error`,可随时重试。 5. 不接 AI 也能分类:勾选「AI 不可用时用关键词规则自动分类」后, 未启用 AI / 请求失败 / 模型给出「未分类」时,会按**标签 > 标题 > 正文** 的加权关键词匹配自动归类(关键词表见 `zreader/config.py` 的 `CATEGORY_KEYWORDS`, 可随分类体系一起改)。 > 请求走标准库 `urllib`,不引入额外依赖;接口协议与 OpenAI `/chat/completions` 一致。 > 模型只需返回 `{"summary": "...", "category": "...", "tags": [...]}` 的 JSON, > 程序对代码块、前后废话都有容错解析。 ### 公式(行内 / 段间) | 场景 | 表现 | | --- | --- | | 收藏保存 | 公式图片(`equation?tex=`)/ `data-tex` 节点还原成 LaTeX,行内 `\(…\)`、段间 `\[…\]` | | 阅读视图 | MathJax 排版(同时支持 `\(…\)`/`$…$` 与 `\[…\]`/`$$…$$`);离线时降级为等宽字体显示的 LaTeX 源码 | | Markdown 导出 | 行内 `$…$`、段间 `$$ … $$` | | HTML / PDF 导出 | 内嵌 MathJax(可配置 CDN 或本地目录),PDF 会等排版完成后再打印 | > 正文里如果**原本就写着** `$x^2$` / `$$y''=y$$`(作者手写的 LaTeX),阅读视图与 > HTML / PDF 导出会按行内 / 段间公式渲染。为避免把「价格 $5」这类金额当成公式, > 排版前会自动保护:单个 `$` 必须「紧跟非空白、收尾前非空白、不跨行」才当作公式, > 否则会被转义成 `\$` 原样显示(也可自己写 `\$` 表示字面量)。 **段间公式的判定依据**(按优先级,命中任一即为段间;否则按行内处理): 1. LaTeX 自带段间分隔符(`$$…$$` / `\[…\]`); 2. 内联样式 `display:block`;`display:inline-block` 且带居中提示(`margin:auto` / `text-align:center`); 3. 知乎公式图片的 `eeimg="2"`(1 = 行内,2 = 段间); 4. 独占一个 `
` / `