#!/usr/bin/env python3 """ 小红书Cookie管理器 用于管理Cookie的导入、验证和更新 """ import json import os import sys import time from datetime import datetime import subprocess class XiaohongshuCookieManager: """小红书Cookie管理器""" def __init__(self): self.cookie_dir = os.path.expanduser("~/.xiaohongshu-cli") self.cookie_file = os.path.join(self.cookie_dir, "cookies.json") self.backup_dir = os.path.join(self.cookie_dir, "backups") # 确保目录存在 os.makedirs(self.cookie_dir, exist_ok=True) os.makedirs(self.backup_dir, exist_ok=True) def backup_current_cookies(self): """备份当前Cookie""" if os.path.exists(self.cookie_file): timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") backup_file = os.path.join(self.backup_dir, f"cookies_{timestamp}.json") with open(self.cookie_file, 'r', encoding='utf-8') as f: cookies = json.load(f) with open(backup_file, 'w', encoding='utf-8') as f: json.dump(cookies, f, indent=2, ensure_ascii=False) print(f"✅ Cookie已备份到: {backup_file}") return backup_file return None def import_from_editthiscookie(self, editthis_file): """ 从EditThisCookie导出的文件导入Cookie EditThisCookie导出的是列表格式,需要转换为字典格式 """ print(f"📥 从EditThisCookie文件导入: {editthis_file}") try: with open(editthis_file, 'r', encoding='utf-8') as f: cookies_list = json.load(f) print(f" 原始Cookie数量: {len(cookies_list)}") # 转换为字典格式 cookies_dict = {} for cookie in cookies_list: name = cookie.get('name', '') value = cookie.get('value', '') if name and value: cookies_dict[name] = value print(f" 转换后Cookie数量: {len(cookies_dict)}") # 备份当前Cookie self.backup_current_cookies() # 保存新Cookie with open(self.cookie_file, 'w', encoding='utf-8') as f: json.dump(cookies_dict, f, indent=2, ensure_ascii=False) print(f"✅ Cookie已导入到: {self.cookie_file}") # 显示关键Cookie self.show_key_cookies(cookies_dict) return True except Exception as e: print(f"❌ 导入失败: {e}") import traceback traceback.print_exc() return False def import_from_browser_export(self, export_file): """ 从浏览器导出的Cookie文件导入 支持多种格式 """ print(f"📥 从浏览器导出文件导入: {export_file}") try: with open(export_file, 'r', encoding='utf-8') as f: content = f.read() cookies_dict = {} # 尝试解析不同格式 if content.strip().startswith('['): # JSON列表格式(EditThisCookie) cookies_list = json.loads(content) for cookie in cookies_list: name = cookie.get('name', '') value = cookie.get('value', '') if name and value: cookies_dict[name] = value elif '=' in content and '\n' in content: # Netscape格式(浏览器导出) for line in content.split('\n'): if line.strip() and not line.startswith('#'): parts = line.strip().split('\t') if len(parts) >= 7: name = parts[5] value = parts[6] cookies_dict[name] = value else: # 尝试作为JSON字典 try: cookies_dict = json.loads(content) except: print("❌ 无法识别的Cookie格式") return False print(f" 解析到Cookie数量: {len(cookies_dict)}") # 备份当前Cookie self.backup_current_cookies() # 保存新Cookie with open(self.cookie_file, 'w', encoding='utf-8') as f: json.dump(cookies_dict, f, indent=2, ensure_ascii=False) print(f"✅ Cookie已导入到: {self.cookie_file}") # 显示关键Cookie self.show_key_cookies(cookies_dict) return True except Exception as e: print(f"❌ 导入失败: {e}") return False def show_key_cookies(self, cookies_dict): """显示关键Cookie信息""" print("\n🔑 关键Cookie:") key_cookies = ['a1', 'webId', 'web_session', 'x-user-id-creator.xiaohongshu.com'] for key in key_cookies: if key in cookies_dict: value = cookies_dict[key] print(f" ✅ {key}: {value[:30]}...") else: print(f" ❌ {key}: 不存在") def check_cookie_validity(self): """检查Cookie有效性""" print("🔍 检查Cookie有效性...") if not os.path.exists(self.cookie_file): print("❌ Cookie文件不存在") return False try: # 使用xhs命令检查登录状态 result = subprocess.run( ['xhs', 'status', '--json'], capture_output=True, text=True, timeout=10 ) if result.returncode == 0: data = json.loads(result.stdout) if data.get('ok') and data.get('data', {}).get('authenticated'): user = data['data']['user'] print(f"✅ Cookie有效") print(f" 用户ID: {user.get('id')}") print(f" 用户名: {user.get('username')}") print(f" 昵称: {user.get('nickname')}") return True else: print(f"❌ Cookie无效: {data}") return False else: print(f"❌ 检查失败: {result.stderr}") return False except subprocess.TimeoutExpired: print("⏰ 检查超时") return False except Exception as e: print(f"❌ 检查异常: {e}") return False def get_cookie_info(self): """获取Cookie详细信息""" print("📋 Cookie信息:") if not os.path.exists(self.cookie_file): print("❌ Cookie文件不存在") return try: with open(self.cookie_file, 'r', encoding='utf-8') as f: cookies = json.load(f) print(f" 文件: {self.cookie_file}") print(f" 大小: {os.path.getsize(self.cookie_file)} 字节") print(f" Cookie数量: {len(cookies)}") print(f" 修改时间: {datetime.fromtimestamp(os.path.getmtime(self.cookie_file)).strftime('%Y-%m-%d %H:%M:%S')}") # 显示关键Cookie self.show_key_cookies(cookies) except Exception as e: print(f"❌ 读取失败: {e}") def list_backups(self): """列出所有备份""" print("📚 Cookie备份列表:") if not os.path.exists(self.backup_dir): print(" 无备份") return backups = [] for filename in os.listdir(self.backup_dir): if filename.startswith('cookies_') and filename.endswith('.json'): filepath = os.path.join(self.backup_dir, filename) mtime = os.path.getmtime(filepath) size = os.path.getsize(filepath) backups.append({ 'filename': filename, 'path': filepath, 'mtime': mtime, 'size': size }) if not backups: print(" 无备份") return backups.sort(key=lambda x: x['mtime'], reverse=True) for i, backup in enumerate(backups[:10], 1): time_str = datetime.fromtimestamp(backup['mtime']).strftime('%Y-%m-%d %H:%M:%S') print(f" {i}. {backup['filename']}") print(f" 时间: {time_str}, 大小: {backup['size']} 字节") def restore_backup(self, backup_filename): """从备份恢复Cookie""" backup_file = os.path.join(self.backup_dir, backup_filename) if not os.path.exists(backup_file): print(f"❌ 备份文件不存在: {backup_filename}") return False print(f"🔄 从备份恢复: {backup_filename}") try: # 备份当前Cookie self.backup_current_cookies() # 恢复备份 with open(backup_file, 'r', encoding='utf-8') as f: cookies = json.load(f) with open(self.cookie_file, 'w', encoding='utf-8') as f: json.dump(cookies, f, indent=2, ensure_ascii=False) print(f"✅ Cookie已从备份恢复") # 验证恢复的Cookie return self.check_cookie_validity() except Exception as e: print(f"❌ 恢复失败: {e}") return False def main(): """主函数""" import argparse parser = argparse.ArgumentParser(description='小红书Cookie管理器') subparsers = parser.add_subparsers(dest='command', help='命令') # import命令 import_parser = subparsers.add_parser('import', help='导入Cookie') import_parser.add_argument('file', help='Cookie文件路径') import_parser.add_argument('--type', choices=['editthis', 'browser'], default='editthis', help='文件类型 (editthis: EditThisCookie导出, browser: 浏览器导出)') # check命令 subparsers.add_parser('check', help='检查Cookie有效性') # info命令 subparsers.add_parser('info', help='显示Cookie信息') # backup命令 subparsers.add_parser('backup', help='备份当前Cookie') # list命令 subparsers.add_parser('list', help='列出备份') # restore命令 restore_parser = subparsers.add_parser('restore', help='从备份恢复') restore_parser.add_argument('backup', help='备份文件名') args = parser.parse_args() manager = XiaohongshuCookieManager() if args.command == 'import': if args.type == 'editthis': manager.import_from_editthiscookie(args.file) else: manager.import_from_browser_export(args.file) elif args.command == 'check': manager.check_cookie_validity() elif args.command == 'info': manager.get_cookie_info() elif args.command == 'backup': manager.backup_current_cookies() elif args.command == 'list': manager.list_backups() elif args.command == 'restore': manager.restore_backup(args.backup) else: parser.print_help() if __name__ == "__main__": main()