使用Python跨浏览器通用获取Cookie的解决方案求助
需求背景
需用Python以明文格式打印浏览器Cookie,已知Chrome的Cookie为加密状态。尝试多个脚本后,要么出现权限拒绝提示(已尝试管理员运行仍无效),要么找不到目标文件/数据表。需要支持Edge、Chrome、Firefox、Brave及所有Chromium内核浏览器。
原脚本问题分析
- 直接访问正在运行的浏览器Cookie数据库会被文件锁定,导致权限拒绝(即使管理员运行也无法绕过)
- 未处理Chromium内核浏览器的Cookie值加密逻辑(Windows环境下采用DPAPI加密)
- 仅适配Chrome默认用户目录,未覆盖Edge、Brave等其他Chromium浏览器路径
- 未支持Firefox浏览器的Cookie提取
完整实现方案
依赖安装
先安装所需第三方库:
pip install pycryptodome pywin32
代码实现
import os import sqlite3 import shutil import tempfile from datetime import datetime, timedelta import win32crypt from Crypto.Cipher import AES import json # 处理Chromium内核浏览器通用函数 def get_chromium_cookies(browser_name, db_path_template): cookies = [] user_profile = os.environ["USERPROFILE"] db_path = os.path.join(user_profile, db_path_template) if not os.path.isfile(db_path): print(f"{browser_name} Cookie数据库未找到: {db_path}") return cookies # 复制数据库到临时文件,避免浏览器锁定 with tempfile.NamedTemporaryFile(mode='w+b', delete=False, suffix='.sqlite') as tmp_db: shutil.copyfile(db_path, tmp_db.name) tmp_db_path = tmp_db.name try: # 连接临时数据库 conn = sqlite3.connect(tmp_db_path) cursor = conn.cursor() # 获取加密密钥(从Local State文件读取) local_state_path = os.path.join(os.path.dirname(os.path.dirname(db_path)), "Local State") with open(local_state_path, 'r', encoding='utf-8') as f: local_state = json.load(f) encrypted_key = local_state['os_crypt']['encrypted_key'] # 解密密钥(去除DPAPI前缀) encrypted_key = bytes.fromhex(encrypted_key[5:]) key = win32crypt.CryptUnprotectData(encrypted_key, None, None, None, 0)[1] # 查询Cookie数据 cursor.execute(""" SELECT host_key, name, value, encrypted_value, creation_utc, last_access_utc, expires_utc FROM cookies """) for row in cursor.fetchall(): host_key, name, value, encrypted_value, creation_utc, last_access_utc, expires_utc = row # 解密Cookie值 if encrypted_value: try: # AES-GCM模式解密 nonce = encrypted_value[3:15] ciphertext = encrypted_value[15:-16] tag = encrypted_value[-16:] cipher = AES.new(key, AES.MODE_GCM, nonce=nonce) decrypted_value = cipher.decrypt_and_verify(ciphertext, tag).decode('utf-8') except: decrypted_value = "解密失败" else: decrypted_value = value # 转换UTC时间为可读格式 def convert_utc(utc): if utc == 0: return "永久有效" return (datetime(1601, 1, 1) + timedelta(microseconds=utc)).strftime('%Y-%m-%d %H:%M:%S UTC') cookies.append({ '浏览器': browser_name, '域名': host_key, 'Cookie名称': name, '明文值': decrypted_value, '创建时间': convert_utc(creation_utc), '最后访问时间': convert_utc(last_access_utc), '过期时间': convert_utc(expires_utc) }) conn.close() except Exception as e: print(f"{browser_name}处理出错: {str(e)}") finally: # 删除临时文件 os.unlink(tmp_db_path) return cookies # 处理Firefox浏览器函数 def get_firefox_cookies(): cookies = [] firefox_paths = [ os.path.join(os.environ["USERPROFILE"], "AppData", "Roaming", "Mozilla", "Firefox", "Profiles"), os.path.join(os.environ["USERPROFILE"], "AppData", "Local", "Mozilla", "Firefox", "Profiles") ] profile_found = False for base_path in firefox_paths: if not os.path.exists(base_path): continue for profile_dir in os.listdir(base_path): profile_path = os.path.join(base_path, profile_dir) db_path = os.path.join(profile_path, "cookies.sqlite") if not os.path.isfile(db_path): continue profile_found = True # 复制到临时文件 with tempfile.NamedTemporaryFile(mode='w+b', delete=False, suffix='.sqlite') as tmp_db: shutil.copyfile(db_path, tmp_db.name) tmp_db_path = tmp_db.name try: conn = sqlite3.connect(tmp_db_path) cursor = conn.cursor() cursor.execute("PRAGMA key = '';") # 默认无主密码时直接读取 cursor.execute(""" SELECT host, name, value, creationTime, lastAccessed, expiry FROM moz_cookies """) for row in cursor.fetchall(): host, name, value, creationTime, lastAccessed, expiry = row def convert_firefox_time(timestamp): if timestamp == 0: return "永久有效" return (datetime(1970, 1, 1) + timedelta(microseconds=timestamp)).strftime('%Y-%m-%d %H:%M:%S UTC') cookies.append({ '浏览器': 'Firefox', '域名': host, 'Cookie名称': name, '明文值': value, '创建时间': convert_firefox_time(creationTime), '最后访问时间': convert_firefox_time(lastAccessed), '过期时间': convert_firefox_time(expiry) }) conn.close() except Exception as e: print(f"Firefox处理出错: {str(e)}") finally: os.unlink(tmp_db_path) if not profile_found: print("Firefox配置文件未找到") return cookies # 主函数 if __name__ == "__main__": # 定义各Chromium浏览器路径模板,可自行添加其他浏览器 chromium_browsers = [ ("Chrome", r"AppData\Local\Google\Chrome\User Data\Default\Cookies"), ("Edge", r"AppData\Local\Microsoft\Edge\User Data\Default\Cookies"), ("Brave", r"AppData\Local\BraveSoftware\Brave-Browser\User Data\Default\Cookies"), # Opera示例: ("Opera", r"AppData\Roaming\Opera Software\Opera Stable\Cookies") ] all_cookies = [] for browser_name, path_template in chromium_browsers: all_cookies.extend(get_chromium_cookies(browser_name, path_template)) all_cookies.extend(get_firefox_cookies()) # 打印明文Cookie for idx, cookie in enumerate(all_cookies, 1): print(f"===== Cookie [{idx}] =====") print(f"浏览器: {cookie['浏览器']}") print(f"域名: {cookie['域名']}") print(f"名称: {cookie['Cookie名称']}") print(f"明文值: {cookie['明文值']}") print(f"创建时间: {cookie['创建时间']}") print(f"最后访问时间: {cookie['最后访问时间']}") print(f"过期时间: {cookie['过期时间']}\n")
关键说明
- 文件锁定解决:通过复制Cookie数据库到临时文件再访问,避免浏览器占用导致的权限问题
- Chromium加密解密:读取
Local State文件中的加密密钥,用DPAPI解密后再通过AES-GCM解密Cookie值 - 多浏览器支持:适配Chrome、Edge、Brave等Chromium浏览器的默认路径,可自行扩展其他Chromium内核浏览器路径
- Firefox处理:默认无主密码时可直接读取明文Cookie;若设置了主密码,需额外添加解密逻辑
内容的提问来源于stack exchange,提问作者crazky
相关产品推荐
相关产品推荐

