From 14434df4eb7231a2c7bd938cd4249e5ade76f2c9 Mon Sep 17 00:00:00 2001 From: starmen1265 Date: Tue, 17 Mar 2026 17:15:30 +0800 Subject: [PATCH] docs(07): create phase 7 login auth plans --- .planning/ROADMAP.md | 10 +- .planning/phases/07-login-auth/07-01-PLAN.md | 203 +++++++++++ .planning/phases/07-login-auth/07-02-PLAN.md | 299 ++++++++++++++++ .planning/phases/07-login-auth/07-03-PLAN.md | 341 +++++++++++++++++++ 4 files changed, 848 insertions(+), 5 deletions(-) create mode 100644 .planning/phases/07-login-auth/07-01-PLAN.md create mode 100644 .planning/phases/07-login-auth/07-02-PLAN.md create mode 100644 .planning/phases/07-login-auth/07-03-PLAN.md diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md index b5c4188..2ccbf75 100644 --- a/.planning/ROADMAP.md +++ b/.planning/ROADMAP.md @@ -90,12 +90,12 @@ Plans: 2. 扫码失败时用户可以手动设置 Cookie 进行认证 3. Cookie 自动保存到本地文件,下次运行自动复用 4. Cookie 过期时系统自动检测并提示用户重新登录 -**Plans**: TBD +**Plans**: 3 plans Plans: -- [ ] 07-01: 二维码扫码登录实现 (AUTH-01) -- [ ] 07-02: 手动 Cookie 设置和持久化 (AUTH-02, AUTH-03) -- [ ] 07-03: Cookie 过期检测机制 (AUTH-04) +- [ ] 07-01-PLAN.md — 二维码扫码登录核心逻辑 (AUTH-01) + Wave 0 测试脚手架 +- [ ] 07-02-PLAN.md — Cookie 导入和持久化管理 (AUTH-02, AUTH-03) +- [ ] 07-03-PLAN.md — Cookie 验证 + CLI login 子命令 (AUTH-04) #### Phase 8: 内容爬取实现 **Goal**: 实现知乎问答、专栏/文章、评论的完整爬取功能,包含网络反爬措施 @@ -140,6 +140,6 @@ Phases execute in numeric order: 1 → 2 → 3 → 4 → 5 → 6 → 7 → 8 → | 4. Pipeline | v1.0 | 2/2 | Complete | 2026-03-15 | | 5. 归档与目录优化 | v1.1 | 3/3 | Complete | 2026-03-16 | | 6. 代码整合 | v1.1 | 3/3 | Complete | 2026-03-16 | -| 7. 登录认证体系 | v1.2 | 0/3 | Not started | - | +| 7. 登录认证体系 | v1.2 | 0/3 | Ready to execute | - | | 8. 内容爬取实现 | v1.2 | 0/3 | Not started | - | | 9. Pipeline 整合 | v1.2 | 0/1 | Not started | - | diff --git a/.planning/phases/07-login-auth/07-01-PLAN.md b/.planning/phases/07-login-auth/07-01-PLAN.md new file mode 100644 index 0000000..948c93a --- /dev/null +++ b/.planning/phases/07-login-auth/07-01-PLAN.md @@ -0,0 +1,203 @@ +--- +phase: 07-login-auth +plan: 01 +type: execute +wave: 1 +depends_on: [] +files_modified: + - kb_workflow/auth/__init__.py + - kb_workflow/auth/zhihu_login.py + - tests/test_auth/__init__.py + - tests/test_auth/conftest.py + - tests/test_auth/test_qrcode_login.py +autonomous: true +requirements: + - AUTH-01 +user_setup: [] + +must_haves: + truths: + - "用户可以访问知乎登录页面" + - "系统可以从 Canvas 元素截取二维码图片" + - "二维码图片保存到中间目录" + - "系统可以轮询检测 z_c0 Cookie 判断登录状态" + artifacts: + - path: "kb_workflow/auth/zhihu_login.py" + provides: "二维码登录核心逻辑" + min_lines: 100 + exports: ["ZhihuLogin", "ZhihuLoginResult"] + - path: "tests/test_auth/test_qrcode_login.py" + provides: "登录逻辑单元测试" + exports: ["test_login_page_access", "test_qrcode_screenshot", "test_cookie_detection"] + key_links: + - from: "kb_workflow/auth/zhihu_login.py" + to: "PlaywrightBrowser" + via: "import from kb_workflow.metadata.zhihu_extractor" + pattern: "from kb_workflow.metadata.zhihu_extractor import PlaywrightBrowser" + - from: "ZhihuLogin.login_by_qrcode()" + to: "canvas.screenshot()" + via: "Playwright element screenshot API" + pattern: "canvas.*screenshot" +--- + + +实现知乎二维码扫码登录核心逻辑。 + +Purpose: 提供二维码登录能力,访问登录页 → Canvas 截图 → 轮询检测 Cookie +Output: kb_workflow/auth/zhihu_login.py 模块 + Wave 0 测试脚手架 + + + +@/home/starmen1265/.claude/get-shit-done/workflows/execute-plan.md +@/home/starmen1265/.claude/get-shit-done/templates/summary.md + + + +@.planning/PROJECT.md +@.planning/ROADMAP.md +@.planning/STATE.md +@.planning/phases/07-login-auth/07-CONTEXT.md +@.planning/phases/07-login-auth/07-RESEARCH.md + + + + +From kb_workflow/metadata/zhihu_extractor.py: +```python +class PlaywrightBrowser: + def __init__(self, headless: bool = True, timeout: int = 30) + def start(self, cookie: str = None) + def close(self) + def goto(self, url: str, wait_until: str = "networkidle") + def wait_for_selector(self, selector: str, timeout: int = None) + def query_selector(self, selector: str) + def evaluate(self, script: str) + # context 属性可用于获取 cookies + self.context # BrowserContext + self.page # Page +``` + +From kb_workflow/pipeline/config.py: +```python +class KBSettings(BaseSettings): + intermediate_path: str # 中间目录路径 + zhihu_cookie: SecretStr # 知乎 Cookie +``` + +From kb_workflow/pipeline/schemas.py: +```python +class StepOutput(BaseModel): + success: bool + error_message: Optional[str] + completed_at: datetime +``` + + + + + + + Task 1: 创建测试模块和 fixtures + tests/test_auth/__init__.py, tests/test_auth/conftest.py + +创建 Wave 0 测试脚手架: + +1. 创建 `tests/test_auth/__init__.py` 空文件 + +2. 创建 `tests/test_auth/conftest.py` 包含: + - `mock_browser` fixture: 使用 unittest.mock 模拟 PlaywrightBrowser + - `mock_env_file` fixture: 使用 tmp_path 创建临时 ~/.kb_env + - `sample_cookies` fixture: 返回测试用 Cookie 数据 + +参考 pytest fixture 模式,确保 mock_browser 可以: +- 模拟 page.wait_for_selector() 返回 mock canvas +- 模拟 canvas.screenshot() 返回 bytes +- 模拟 context.cookies() 返回 Cookie 列表 + + + python -c "from tests.test_auth.conftest import *; print('fixtures loaded')" + + 测试模块和 fixtures 可被 pytest 加载 + + + + Task 2: 实现 ZhihuLogin 核心类 + kb_workflow/auth/__init__.py, kb_workflow/auth/zhihu_login.py, tests/test_auth/test_qrcode_login.py + + - Test 1: login_page_access - 访问登录页成功,URL 正确 + - Test 2: qrcode_screenshot - Canvas 截图返回 bytes,保存到正确路径 + - Test 3: cookie_detection - 检测 z_c0 Cookie 存在返回 True,不存在返回 False + - Test 4: login_timeout - 60秒超时后抛出 TimeoutError + - Test 5: cookie_extraction - 登录成功后提取 Cookie 字符串 + + +创建 `kb_workflow/auth/` 模块并实现 ZhihuLogin 类: + +1. 创建 `kb_workflow/auth/__init__.py`: + ```python + from .zhihu_login import ZhihuLogin, ZhihuLoginResult + __all__ = ["ZhihuLogin", "ZhihuLoginResult"] + ``` + +2. 创建 `kb_workflow/auth/zhihu_login.py`: + - `ZhihuLoginResult` Pydantic model: success, cookie_str, qrcode_path, error_message + - `ZhihuLogin` 类: + - `LOGIN_URL = "https://www.zhihu.com/signin"` + - `CANVAS_SELECTORS = ["canvas.SignIn-qrcode", "canvas[class*='qrcode']", "canvas"]` + - `__init__(self, intermediate_path: str, headless: bool = True, timeout: int = 60)` + - `async def _find_qrcode_canvas(self) -> ElementHandle` - 尝试多个选择器 + - `async def _save_qrcode_image(self, screenshot: bytes) -> Path` - 保存到中间目录 + - `async def check_login_cookie(self) -> bool` - 检测 z_c0 Cookie + - `async def get_cookies_str(self) -> str` - 提取 Cookie 字符串 + - `async def login_by_qrcode(self) -> ZhihuLoginResult` - 主流程 + +使用 tenacity 的 @retry 装饰器实现 60 秒轮询: +```python +from tenacity import retry, stop_after_delay, wait_fixed, RetryError + +@retry(stop=stop_after_delay(60), wait=wait_fixed(1), reraise=True) +async def _wait_for_login(self): + if not await self.check_login_cookie(): + raise Exception("Not logged in yet") +``` + +二维码图片路径格式: `~/work/intermediate/zhihu_qrcode_{timestamp}.png` + +3. 创建 `tests/test_auth/test_qrcode_login.py`: + - test_login_page_access: mock browser.goto 验证 URL + - test_qrcode_screenshot: mock canvas.screenshot 验证保存 + - test_cookie_detection: mock context.cookies 验证检测逻辑 + - test_login_timeout: mock check_login_cookie 始终返回 False + - test_cookie_extraction: 验证 Cookie 字符串格式 + +安装依赖: pip install tenacity + + + pytest tests/test_auth/test_qrcode_login.py -x -v + + + - ZhihuLogin 类可实例化 + - 所有单元测试通过 + - 二维码截图功能可用 + - Cookie 检测功能可用 + + + + + + +1. 单元测试全部通过: `pytest tests/test_auth/test_qrcode_login.py -v` +2. ZhihuLogin 类可导入: `python -c "from kb_workflow.auth import ZhihuLogin; print(ZhihuLogin)"` +3. tenacity 依赖已安装: `pip show tenacity` + + + +- Wave 0 测试脚手架就绪 (tests/test_auth/) +- ZhihuLogin 类实现二维码截图和 Cookie 检测 +- 5 个单元测试全部通过 +- 代码符合现有项目模式 (pydantic, Playwright) + + + +After completion, create `.planning/phases/07-login-auth/07-01-SUMMARY.md` + diff --git a/.planning/phases/07-login-auth/07-02-PLAN.md b/.planning/phases/07-login-auth/07-02-PLAN.md new file mode 100644 index 0000000..9b04a64 --- /dev/null +++ b/.planning/phases/07-login-auth/07-02-PLAN.md @@ -0,0 +1,299 @@ +--- +phase: 07-login-auth +plan: 02 +type: execute +wave: 1 +depends_on: [] +files_modified: + - kb_workflow/auth/cookie_manager.py + - tests/test_auth/test_cookie_import.py + - tests/test_auth/test_cookie_persistence.py +autonomous: true +requirements: + - AUTH-02 + - AUTH-03 +user_setup: [] + +must_haves: + truths: + - "用户可以从 JSON 文件导入 Cookie" + - "Cookie 可以保存到 ~/.kb_env 文件" + - "保存的 Cookie 下次运行时可以自动加载" + - "JSON Cookie 格式被正确解析为字符串格式" + artifacts: + - path: "kb_workflow/auth/cookie_manager.py" + provides: "Cookie 导入和持久化" + min_lines: 80 + exports: ["CookieManager", "parse_json_cookies"] + - path: "tests/test_auth/test_cookie_import.py" + provides: "Cookie 导入测试" + - path: "tests/test_auth/test_cookie_persistence.py" + provides: "Cookie 持久化测试" + key_links: + - from: "CookieManager.save_cookie()" + to: "~/.kb_env" + via: "文件写入" + pattern: "Path\\.home\\(\\).*\\.kb_env" + - from: "parse_json_cookies()" + to: "Chrome Cookie Editor JSON" + via: "json.load + 过滤 zhihu.com" + pattern: "zhihu\\.com.*domain" +--- + + +实现 Cookie 导入和持久化管理。 + +Purpose: 支持 JSON Cookie 导入和 ~/.kb_env 文件持久化 +Output: kb_workflow/auth/cookie_manager.py 模块 + 单元测试 + + + +@/home/starmen1265/.claude/get-shit-done/workflows/execute-plan.md +@/home/starmen1265/.claude/get-shit-done/templates/summary.md + + + +@.planning/PROJECT.md +@.planning/ROADMAP.md +@.planning/STATE.md +@.planning/phases/07-login-auth/07-CONTEXT.md +@.planning/phases/07-login-auth/07-RESEARCH.md + + + + +From kb_workflow/pipeline/config.py: +```python +class KBSettings(BaseSettings): + zhihu_cookie: SecretStr = Field(default=SecretStr(""), description="知乎 Cookie") + + model_config = SettingsConfigDict( + env_file=str(Path.home() / ".kb_env"), + env_file_encoding="utf-8", + env_prefix="KB_", + extra="ignore", + ) + +@lru_cache +def get_settings() -> KBSettings: + return KBSettings() +``` + +Chrome Cookie Editor JSON 格式示例: +```json +[ + {"name": "z_c0", "value": "xxx", "domain": ".zhihu.com"}, + {"name": "_zap", "value": "yyy", "domain": ".zhihu.com"} +] +``` + +目标存储格式 (~/.kb_env): +``` +ZHIHU_COOKIE="z_c0=xxx; _zap=yyy" +``` + + + + + + + Task 1: 实现 Cookie JSON 解析功能 + kb_workflow/auth/cookie_manager.py, tests/test_auth/test_cookie_import.py + + - Test 1: parse_json_cookies - 解析 Chrome Cookie Editor JSON 格式 + - Test 2: parse_json_cookies_filters_domain - 只保留 zhihu.com 域名 + - Test 3: parse_json_cookies_empty - 空数组返回空字符串 + - Test 4: parse_json_cookies_malformed - 格式错误抛出 ValueError + + +在 `kb_workflow/auth/cookie_manager.py` 中实现 Cookie 解析功能: + +1. 创建 `kb_workflow/auth/cookie_manager.py`: + +```python +"""Cookie 管理模块 + +处理 Cookie 的导入、转换和持久化。 +""" +import json +from pathlib import Path +from typing import List, Dict, Any + +def parse_json_cookies(json_path: str) -> str: + """从 JSON 文件解析 Cookie 为字符串格式 + + 支持 Chrome Cookie Editor 导出的 JSON 格式: + [{"name": "z_c0", "value": "xxx", "domain": ".zhihu.com"}, ...] + + Args: + json_path: JSON 文件路径 + + Returns: + Cookie 字符串,格式: "name1=value1; name2=value2" + + Raises: + ValueError: JSON 格式无效或文件不存在 + """ + path = Path(json_path) + if not path.exists(): + raise ValueError(f"Cookie file not found: {json_path}") + + try: + with open(path, 'r', encoding='utf-8') as f: + cookies = json.load(f) + except json.JSONDecodeError as e: + raise ValueError(f"Invalid JSON format: {e}") + + if not isinstance(cookies, list): + raise ValueError("Expected JSON array") + + # 过滤知乎域名,转换为 name=value 格式 + zhihu_cookies = [] + for c in cookies: + if not isinstance(c, dict): + continue + domain = c.get('domain', '') + if 'zhihu.com' in domain: + name = c.get('name', '') + value = c.get('value', '') + if name and value: + zhihu_cookies.append(f"{name}={value}") + + return '; '.join(zhihu_cookies) +``` + +2. 创建 `tests/test_auth/test_cookie_import.py`: + - 使用 tmp_path fixture 创建临时 JSON 文件 + - 测试正常解析、域名过滤、空数组、格式错误等情况 + + + pytest tests/test_auth/test_cookie_import.py -x -v + + + - parse_json_cookies 函数可用 + - 4 个单元测试全部通过 + - 正确过滤 zhihu.com 域名 + + + + + Task 2: 实现 Cookie 持久化管理器 + kb_workflow/auth/cookie_manager.py, tests/test_auth/test_cookie_persistence.py + + - Test 1: save_cookie_creates_file - 保存 Cookie 创建 ~/.kb_env 文件 + - Test 2: save_cookie_updates_existing - 更新现有 ZHIHU_COOKIE 行 + - Test 3: save_cookie_appends_new - 不存在时追加新行 + - Test 4: save_cookie_preserves_other_lines - 保留其他配置行 + - Test 5: load_cookie_returns_saved - 加载已保存的 Cookie + - Test 6: load_cookie_empty_if_not_exists - 文件不存在返回空字符串 + + +扩展 `kb_workflow/auth/cookie_manager.py` 添加 CookieManager 类: + +```python +from functools import lru_cache + +class CookieManager: + """Cookie 持久化管理器 + + 管理 Cookie 在 ~/.kb_env 文件中的存储和读取。 + """ + + ENV_FILE_NAME = ".kb_env" + COOKIE_KEY = "ZHIHU_COOKIE" + + def __init__(self, env_path: Path = None): + """初始化管理器 + + Args: + env_path: 环境文件路径,默认 ~/.kb_env + """ + self.env_path = env_path or (Path.home() / self.ENV_FILE_NAME) + + def save_cookie(self, cookie_str: str) -> None: + """保存 Cookie 到环境文件 + + 格式: ZHIHU_COOKIE="name1=value1; name2=value2" + + Args: + cookie_str: Cookie 字符串 + """ + # 读取现有内容 + lines = [] + if self.env_path.exists(): + lines = self.env_path.read_text(encoding='utf-8').splitlines() + + # 更新或添加 ZHIHU_COOKIE 行 + cookie_line = f'{self.COOKIE_KEY}="{cookie_str}"' + found = False + for i, line in enumerate(lines): + if line.startswith(f"{self.COOKIE_KEY}="): + lines[i] = cookie_line + found = True + break + if not found: + lines.append(cookie_line) + + # 写回文件,设置权限 600 + self.env_path.write_text('\n'.join(lines) + '\n', encoding='utf-8') + self.env_path.chmod(0o600) + + # 清除配置缓存 + from kb_workflow.pipeline.config import get_settings + get_settings.cache_clear() + + def load_cookie(self) -> str: + """从环境文件加载 Cookie + + Returns: + Cookie 字符串,不存在时返回空字符串 + """ + if not self.env_path.exists(): + return "" + + content = self.env_path.read_text(encoding='utf-8') + for line in content.splitlines(): + if line.startswith(f"{self.COOKIE_KEY}="): + # 提取引号内的值 + value = line[len(f"{self.COOKIE_KEY}="):] + if value.startswith('"') and value.endswith('"'): + value = value[1:-1] + return value + return "" +``` + +创建 `tests/test_auth/test_cookie_persistence.py`: +- 使用 tmp_path fixture 创建临时环境文件 +- 测试保存、更新、追加、加载等功能 +- 测试文件权限设置 + + + pytest tests/test_auth/test_cookie_persistence.py -x -v + + + - CookieManager 类可用 + - 6 个单元测试全部通过 + - Cookie 可正确保存到 ~/.kb_env + - 保存后自动清除配置缓存 + + + + + + +1. Cookie 导入测试通过: `pytest tests/test_auth/test_cookie_import.py -v` +2. Cookie 持久化测试通过: `pytest tests/test_auth/test_cookie_persistence.py -v` +3. 模块可导入: `python -c "from kb_workflow.auth.cookie_manager import CookieManager, parse_json_cookies; print('OK')"` + + + +- parse_json_cookies 函数支持 Chrome Cookie Editor 格式 +- CookieManager 类支持保存和加载 Cookie +- ~/.kb_env 文件权限正确设置为 600 +- 保存后自动清除 get_settings 缓存 +- 10 个单元测试全部通过 + + + +After completion, create `.planning/phases/07-login-auth/07-02-SUMMARY.md` + diff --git a/.planning/phases/07-login-auth/07-03-PLAN.md b/.planning/phases/07-login-auth/07-03-PLAN.md new file mode 100644 index 0000000..66191b4 --- /dev/null +++ b/.planning/phases/07-login-auth/07-03-PLAN.md @@ -0,0 +1,341 @@ +--- +phase: 07-login-auth +plan: 03 +type: execute +wave: 2 +depends_on: + - 07-01 + - 07-02 +files_modified: + - kb_workflow/auth/zhihu_login.py + - kb_workflow/auth/cookie_manager.py + - kb_workflow/kb_workflow.py + - tests/test_auth/test_cookie_validation.py + - tests/test_auth/test_cli_login.py +autonomous: false +requirements: + - AUTH-04 +user_setup: [] + +must_haves: + truths: + - "用户可以通过 python3 kb-workflow/kb_workflow.py login 启动登录流程" + - "登录成功后 Cookie 自动保存到 ~/.kb_env" + - "Cookie 过期时系统自动检测并提示用户" + - "用户可以手动导入 Cookie 文件" + - "用户可以查看当前 Cookie 状态" + artifacts: + - path: "kb_workflow/auth/zhihu_login.py" + provides: "Cookie 验证方法" + exports: ["validate_cookie"] + - path: "kb_workflow/kb_workflow.py" + provides: "login CLI 子命令" + contains: "subparsers.add_parser('login')" + key_links: + - from: "kb_workflow.py login" + to: "ZhihuLogin.login_by_qrcode()" + via: "asyncio.run()" + pattern: "login_by_qrcode" + - from: "ZhihuLogin.login_by_qrcode()" + to: "CookieManager.save_cookie()" + via: "登录成功后保存" + pattern: "save_cookie" + - from: "validate_cookie()" + to: "/api/v4/me" + via: "Playwright request API" + pattern: "api/v4/me" +--- + + +实现 Cookie 验证机制和 CLI login 子命令。 + +Purpose: 整合登录功能到 CLI,支持 Cookie 验证和状态查询 +Output: 完整的 login 命令 + Cookie 验证 + 端到端测试 + + + +@/home/starmen1265/.claude/get-shit-done/workflows/execute-plan.md +@/home/starmen1265/.claude/get-shit-done/templates/summary.md + + + +@.planning/PROJECT.md +@.planning/ROADMAP.md +@.planning/STATE.md +@.planning/phases/07-login-auth/07-CONTEXT.md +@.planning/phases/07-login-auth/07-RESEARCH.md +@.planning/phases/07-login-auth/07-01-PLAN.md +@.planning/phases/07-login-auth/07-02-PLAN.md + + + + +From kb_workflow/auth/zhihu_login.py (Plan 01): +```python +class ZhihuLogin: + async def login_by_qrcode(self) -> ZhihuLoginResult + async def check_login_cookie(self) -> bool + async def get_cookies_str(self) -> str +``` + +From kb_workflow/auth/cookie_manager.py (Plan 02): +```python +def parse_json_cookies(json_path: str) -> str + +class CookieManager: + def save_cookie(self, cookie_str: str) -> None + def load_cookie(self) -> str +``` + +From kb_workflow/kb_workflow.py (existing): +```python +def process_command(url: str, ...) -> Dict[str, Any] + +def main(): + subparsers = parser.add_subparsers(dest='command') + # 添加 login 子命令到此处 +``` + +知乎 API: +- 验证接口: GET https://www.zhihu.com/api/v4/me +- 成功返回: {"id": 123, "name": "用户名", ...} +- 失败返回: 401 状态码 + + + + + + + Task 1: 实现 Cookie 验证功能 + kb_workflow/auth/zhihu_login.py, tests/test_auth/test_cookie_validation.py + + - Test 1: validate_cookie_valid - 有效 Cookie 返回 valid=True 和用户信息 + - Test 2: validate_cookie_expired - 过期 Cookie 返回 valid=False + - Test 3: validate_cookie_empty - 空 Cookie 返回 valid=False + - Test 4: validate_cookie_malformed - 格式错误 Cookie 返回 valid=False + + +扩展 `kb_workflow/auth/zhihu_login.py` 添加 Cookie 验证功能: + +1. 添加 `CookieValidationResult` Pydantic model: +```python +from pydantic import BaseModel +from typing import Optional + +class CookieValidationResult(BaseModel): + """Cookie 验证结果""" + valid: bool + username: Optional[str] = None + user_id: Optional[str] = None + reason: Optional[str] = None +``` + +2. 在 `ZhihuLogin` 类中添加验证方法: +```python +VALIDATION_URL = "https://www.zhihu.com/api/v4/me" + +async def validate_cookie(self, cookie_str: str = None) -> CookieValidationResult: + """验证 Cookie 有效性 + + 通过请求知乎用户信息接口检测 Cookie 是否有效。 + + Args: + cookie_str: 要验证的 Cookie 字符串,为空时使用已加载的 Cookie + + Returns: + CookieValidationResult 包含验证状态和用户信息 + """ + # 如果提供了 cookie_str,需要重新启动浏览器并设置 Cookie + if cookie_str: + if self.browser.browser: + self.browser.close() + self.browser.start(cookie=cookie_str) + elif not self.browser.page: + return CookieValidationResult(valid=False, reason="No cookie provided") + + try: + # 使用 Playwright 的 request API + response = await self.browser.page.request.get(self.VALIDATION_URL) + + if response.status == 200: + user_info = await response.json() + return CookieValidationResult( + valid=True, + username=user_info.get("name", ""), + user_id=str(user_info.get("id", "")) + ) + elif response.status == 401: + return CookieValidationResult(valid=False, reason="Cookie expired") + else: + return CookieValidationResult( + valid=False, + reason=f"Validation failed with status {response.status}" + ) + except Exception as e: + return CookieValidationResult(valid=False, reason=str(e)) +``` + +3. 创建 `tests/test_auth/test_cookie_validation.py`: +- 使用 mock 模拟 page.request.get() 返回不同状态码 +- 测试有效、过期、空、格式错误等场景 + + + pytest tests/test_auth/test_cookie_validation.py -x -v + + + - validate_cookie 方法可用 + - 4 个单元测试全部通过 + - 返回 CookieValidationResult 结构 + + + + + Task 2: 实现 login CLI 子命令 + kb_workflow/kb_workflow.py, tests/test_auth/test_cli_login.py + + - Test 1: login_default_mode - 默认启动二维码登录 + - Test 2: login_import_cookie - --import-cookie 参数导入 JSON + - Test 3: login_status - --status 参数检查 Cookie 状态 + - Test 4: login_integration - 登录成功后 Cookie 保存到文件 + + +扩展 `kb_workflow/kb_workflow.py` 添加 login 子命令: + +1. 添加 login_command 函数: +```python +def login_command( + import_cookie: Optional[str] = None, + status: bool = False +) -> Dict[str, Any]: + """Execute login command + + Args: + import_cookie: Path to JSON cookie file + status: Check current cookie status + + Returns: + Dictionary with login result + """ + try: + from kb_workflow.auth import ZhihuLogin + from kb_workflow.auth.cookie_manager import CookieManager, parse_json_cookies + from kb_workflow.pipeline.config import get_settings + + settings = get_settings() + manager = CookieManager() + + # 检查 Cookie 状态 + if status: + current_cookie = settings.zhihu_cookie.get_secret_value() + if not current_cookie: + return {"valid": False, "reason": "No cookie found in ~/.kb_env"} + + async def check_status(): + login = ZhihuLogin(intermediate_path=settings.intermediate_path) + try: + login.browser.start(cookie=current_cookie) + return await login.validate_cookie(current_cookie) + finally: + login.browser.close() + + result = asyncio.run(check_status()) + return result.model_dump() + + # 导入 Cookie + if import_cookie: + cookie_str = parse_json_cookies(import_cookie) + manager.save_cookie(cookie_str) + return {"success": True, "message": f"Cookie imported from {import_cookie}"} + + # 二维码登录 + async def qrcode_login(): + login = ZhihuLogin(intermediate_path=settings.intermediate_path) + try: + result = await login.login_by_qrcode() + if result.success and result.cookie_str: + manager.save_cookie(result.cookie_str) + return result.model_dump() + finally: + if login.browser.browser: + login.browser.close() + + result = asyncio.run(qrcode_login()) + return result + + except Exception as e: + return {"success": False, "error": str(e)} +``` + +2. 在 main() 函数中添加 login 子命令: +```python +# Login subcommand +login_parser = subparsers.add_parser('login', help='Zhihu login authentication') +login_parser.add_argument('--import-cookie', '-i', type=str, + help='Import cookie from JSON file') +login_parser.add_argument('--status', action='store_true', + help='Check current cookie status') + +# Handle login subcommand +if args.command == 'login': + result = login_command( + import_cookie=args.import_cookie, + status=args.status + ) + print(json.dumps(result, ensure_ascii=False, indent=2)) +``` + +3. 创建 `tests/test_auth/test_cli_login.py`: +- 使用 mock 模拟 ZhihuLogin 和 CookieManager +- 测试各种命令行参数组合 + + + pytest tests/test_auth/test_cli_login.py -x -v + + + - login 子命令可用 + - 支持 --import-cookie 和 --status 参数 + - 4 个单元测试全部通过 + + + + + +完整的知乎登录认证系统: +- 二维码扫码登录 (python3 kb-workflow/kb_workflow.py login) +- JSON Cookie 导入 (python3 kb-workflow/kb_workflow.py login --import-cookie cookies.json) +- Cookie 状态检查 (python3 kb-workflow/kb_workflow.py login --status) +- Cookie 自动持久化到 ~/.kb_env + + +1. 运行 `python3 kb-workflow/kb_workflow.py login` +2. 验证二维码图片生成在 `~/work/intermediate/zhihu_qrcode_*.png` +3. 使用知乎 APP 扫码确认登录 +4. 验证命令返回 `{"success": true, "cookie_str": "..."}` +5. 检查 `~/.kb_env` 文件包含 `ZHIHU_COOKIE="..."` 行 +6. 运行 `python3 kb-workflow/kb_workflow.py login --status` +7. 验证返回用户信息 + + Type "approved" if login works, or describe issues + + + + + +1. 所有测试通过: `pytest tests/test_auth/ -v` +2. login 命令可用: `python3 kb-workflow/kb_workflow.py login --help` +3. Cookie 验证功能: `python3 -c "from kb_workflow.auth import ZhihuLogin; print(ZhihuLogin.validate_cookie)"` + + + +- 用户可以通过命令行扫码登录知乎 +- 扫码成功后 Cookie 自动保存 +- 用户可以手动导入 JSON Cookie +- 用户可以查看 Cookie 状态 +- Cookie 过期时系统提示重新登录 +- 所有单元测试通过 (18+ tests) +- 手动验证登录流程成功 + + + +After completion, create `.planning/phases/07-login-auth/07-03-SUMMARY.md` +