From 85797d0a8942ff3dc244eac3a4a27b0d91501690 Mon Sep 17 00:00:00 2001 From: starmen1265 Date: Fri, 27 Feb 2026 15:39:19 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20kb-zhihu-metadata=20=E6=94=AF=E6=8C=81?= =?UTF-8?q?=20ZHIHU=5FCOOKIE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 安装 markdownify 依赖 - PlaywrightBrowser 支持传入 Cookie - ZhihuPlaywrightExtractor 支持传入 Cookie - zhihu_metadata.py 读取 ZHIHU_COOKIE 环境变量 - 更新 SKILL.md 添加 Cookie 配置说明 --- kb-zhihu-metadata/SKILL.md | 18 ++++++++++++ kb-zhihu-metadata/zhihu_extractor.py | 42 +++++++++++++++++++++++----- kb-zhihu-metadata/zhihu_metadata.py | 38 +++++++++++++++---------- 3 files changed, 76 insertions(+), 22 deletions(-) diff --git a/kb-zhihu-metadata/SKILL.md b/kb-zhihu-metadata/SKILL.md index d4e77d7..9b1a9cb 100644 --- a/kb-zhihu-metadata/SKILL.md +++ b/kb-zhihu-metadata/SKILL.md @@ -9,6 +9,24 @@ - User information extraction - JSON output format - Markdown conversion support +- **Cookie 支持**:可配置 ZHIHU_COOKIE 访问需要登录的内容 + +## 环境变量 + +| 变量名 | 用途 | 必需 | +|--------|------|------| +| `ZHIHU_COOKIE` | 知乎登录 Cookie | 推荐(访问专栏等需要) | + +**获取 ZHIHU_COOKIE**: +1. 登录知乎网页版 +2. 打开开发者工具 (F12) → Application → Cookies → zhihu.com +3. 复制 Cookie 字符串 + +```bash +# 添加到 ~/.kb_env +echo 'export ZHIHU_COOKIE="你的知乎Cookie"' >> ~/.kb_env +source ~/.kb_env +``` ## Commands diff --git a/kb-zhihu-metadata/zhihu_extractor.py b/kb-zhihu-metadata/zhihu_extractor.py index 2ff509b..67af68f 100644 --- a/kb-zhihu-metadata/zhihu_extractor.py +++ b/kb-zhihu-metadata/zhihu_extractor.py @@ -30,16 +30,42 @@ class PlaywrightBrowser: self.context = None self.page = None - def start(self): + def start(self, cookie: str = None): """启动浏览器""" from playwright.sync_api import sync_playwright self.playwright = sync_playwright().start() self.browser = self.playwright.chromium.launch(headless=self.headless) - self.context = self.browser.new_context( - user_agent='Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36' - ) + + # 创建浏览器上下文 + context_options = { + 'user_agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36' + } + + # 如果提供了 Cookie,设置 Cookie + if cookie: + context_options['cookies'] = self._parse_cookie(cookie) + + self.context = self.browser.new_context(**context_options) self.page = self.context.new_page() self.page.set_default_timeout(self.timeout) + + def _parse_cookie(self, cookie_str: str) -> list: + """解析 Cookie 字符串为 Playwright 格式""" + cookies = [] + for item in cookie_str.split(';'): + item = item.strip() + if '=' in item: + name, value = item.split('=', 1) + cookies.append({ + 'name': name.strip(), + 'value': value.strip(), + 'domain': '.zhihu.com', + 'path': '/', + 'secure': True, + 'httpOnly': False, + 'sameSite': 'Lax' + }) + return cookies def close(self): """关闭浏览器""" @@ -84,14 +110,16 @@ class ZhihuPlaywrightExtractor: 'question': r'zhihu\.com/question/(\d+)', } - def __init__(self, headless: bool = True, timeout: int = 30): + def __init__(self, headless: bool = True, timeout: int = 30, cookie: str = None): """ 初始化提取器 Args: headless: 是否使用无头浏览器 timeout: 超时时间(秒) + cookie: 知乎 Cookie 字符串(可选) """ + self.cookie = cookie self.browser = PlaywrightBrowser(headless=headless, timeout=timeout) self.markdown_converter = MarkdownConverter() @@ -383,8 +411,8 @@ class ZhihuPlaywrightExtractor: print(f"URL 类型: {url_type}") print(f"启动浏览器...") - # 启动浏览器 - self.browser.start() + # 启动浏览器(传入 Cookie) + self.browser.start(cookie=self.cookie) print(f"访问页面: {url}") # 访问页面 diff --git a/kb-zhihu-metadata/zhihu_metadata.py b/kb-zhihu-metadata/zhihu_metadata.py index 8963aa9..7a13f91 100644 --- a/kb-zhihu-metadata/zhihu_metadata.py +++ b/kb-zhihu-metadata/zhihu_metadata.py @@ -23,43 +23,46 @@ if current_dir not in sys.path: from zhihu_extractor import ZhihuPlaywrightExtractor -def extract_zvideo(video_id: str, headless: bool = True) -> Dict[str, Any]: +def extract_zvideo(video_id: str, headless: bool = True, cookie: str = None) -> Dict[str, Any]: """ 获取知乎视频元数据 Args: video_id: 视频 ID (数字字符串) headless: 是否使用无头浏览器 + cookie: 知乎 Cookie(可选) Returns: 视频元数据字典 """ url = f"https://www.zhihu.com/zvideo/{video_id}" - return _extract_metadata(url, "zvideo", headless) + return _extract_metadata(url, "zvideo", headless, cookie) -def extract_zhuanlan(article_id: str, headless: bool = True) -> Dict[str, Any]: +def extract_zhuanlan(article_id: str, headless: bool = True, cookie: str = None) -> Dict[str, Any]: """ 获取知乎专栏文章元数据 Args: article_id: 文章 ID (数字字符串) headless: 是否使用无头浏览器 + cookie: 知乎 Cookie(可选) Returns: 文章元数据字典 """ url = f"https://zhuanlan.zhihu.com/p/{article_id}" - return _extract_metadata(url, "zhuanlan", headless) + return _extract_metadata(url, "zhuanlan", headless, cookie) -def extract_answer(answer_id: str, headless: bool = True) -> Dict[str, Any]: +def extract_answer(answer_id: str, headless: bool = True, cookie: str = None) -> Dict[str, Any]: """ 获取知乎回答元数据 Args: answer_id: 回答 ID (数字字符串) headless: 是否使用无头浏览器 + cookie: 知乎 Cookie(可选) Returns: 回答元数据字典 @@ -67,25 +70,26 @@ def extract_answer(answer_id: str, headless: bool = True) -> Dict[str, Any]: # 回答需要构建包含问题ID的URL,但answer_id本身足以识别 # 使用一个占位符问题ID,因为提取器会从URL中提取answer_id url = f"https://www.zhihu.com/question/0/answer/{answer_id}" - return _extract_metadata(url, "answer", headless) + return _extract_metadata(url, "answer", headless, cookie) -def extract_question(question_id: str, headless: bool = True) -> Dict[str, Any]: +def extract_question(question_id: str, headless: bool = True, cookie: str = None) -> Dict[str, Any]: """ 获取知乎问题元数据 Args: question_id: 问题 ID (数字字符串) headless: 是否使用无头浏览器 + cookie: 知乎 Cookie(可选) Returns: 问题元数据字典 """ url = f"https://www.zhihu.com/question/{question_id}" - return _extract_metadata(url, "question", headless) + return _extract_metadata(url, "question", headless, cookie) -def _extract_metadata(url: str, content_type: str, headless: bool) -> Dict[str, Any]: +def _extract_metadata(url: str, content_type: str, headless: bool, cookie: str = None) -> Dict[str, Any]: """ 内部函数:提取元数据 @@ -93,11 +97,12 @@ def _extract_metadata(url: str, content_type: str, headless: bool) -> Dict[str, url: 知乎 URL content_type: 内容类型 (zvideo/zhuanlan) headless: 是否使用无头浏览器 + cookie: 知乎 Cookie(可选) Returns: 元数据字典 """ - extractor = ZhihuPlaywrightExtractor(headless=headless) + extractor = ZhihuPlaywrightExtractor(headless=headless, cookie=cookie) result = extractor.extract(url) if result: @@ -170,15 +175,18 @@ def main(): args = parser.parse_args() - # 提取元数据 + # 获取知乎 Cookie(优先使用环境变量,其次使用参数) + cookie = os.environ.get('ZHIHU_COOKIE') + + # 提取元数据(传入 Cookie) if args.type == "zvideo": - result = extract_zvideo(args.id, headless=args.headless) + result = extract_zvideo(args.id, headless=args.headless, cookie=cookie) elif args.type == "zhuanlan": - result = extract_zhuanlan(args.id, headless=args.headless) + result = extract_zhuanlan(args.id, headless=args.headless, cookie=cookie) elif args.type == "answer": - result = extract_answer(args.id, headless=args.headless) + result = extract_answer(args.id, headless=args.headless, cookie=cookie) elif args.type == "question": - result = extract_question(args.id, headless=args.headless) + result = extract_question(args.id, headless=args.headless, cookie=cookie) else: print(f"不支持的类型: {args.type}") sys.exit(1)