# 浏览器使用规范 > 📅 创建日期:2026-02-13 > 📋 全局强制规范:所有技能中涉及浏览器操作时,必须遵守本文档 --- ## 一、核心原则 | 原则 | 说明 | |:---|:---| | **使用系统默认浏览器** | 不硬编码任何特定浏览器,用 `open` 命令自动调用 | | **复用已有会话** | 使用用户已登录的浏览器实例,保留 Cookie/登录态 | | **禁止新建实例** | 不创建无痕/隔离/Headless 浏览器窗口 | | **API 优先** | 能用 API 完成的,绝不启动浏览器 | --- ## 二、操作方式优先级 ### 优先级 1:命令行 API 调用(最优先) ```bash # 直接用 curl 调用 API,完全不需要浏览器 curl -X POST "https://api.example.com/endpoint" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"key": "value"}' ``` ```python # Python requests 直接调 API import requests resp = requests.post(url, headers=headers, json=data) ``` ### 优先级 2:系统默认浏览器打开 URL ```bash # macOS 用 open 命令(自动调用系统默认浏览器) open "https://example.com" # 如果需要指定应用(不推荐,仅特殊情况) # open -a "Safari" "https://example.com" ``` ```python import subprocess # 用系统默认浏览器打开 URL subprocess.run(['open', 'https://example.com']) ``` ### 优先级 3:AppleScript 控制已打开的浏览器 ```python import subprocess def get_default_browser_name(): """获取默认浏览器名称""" import json, os r = subprocess.run(['plutil', '-convert', 'json', '-o', '-', os.path.expanduser('~/Library/Preferences/com.apple.LaunchServices/com.apple.launchservices.secure.plist')], capture_output=True, text=True) if r.returncode == 0: data = json.loads(r.stdout) for h in data.get('LSHandlers', []): if h.get('LSHandlerURLScheme') == 'https': bundle_id = h.get('LSHandlerRoleAll', '') # bundle ID → 应用名映射 mapping = { 'com.google.chrome': 'Google Chrome', 'com.apple.safari': 'Safari', 'com.brave.browser': 'Brave Browser', 'com.microsoft.edgemac': 'Microsoft Edge', 'company.thebrowser.browser': 'Arc', 'com.bot.pc.doubao.browser': '豆包浏览器', 'org.mozilla.firefox': 'Firefox', } return mapping.get(bundle_id, bundle_id) return 'Safari' def open_url_in_default_browser(url): """用系统默认浏览器打开 URL(复用已有窗口)""" subprocess.run(['open', url]) def get_current_url(): """获取默认浏览器当前标签页 URL(AppleScript)""" browser = get_default_browser_name() if browser == 'Google Chrome': script = 'tell application "Google Chrome" to get URL of active tab of front window' elif browser == 'Safari': script = 'tell application "Safari" to get URL of current tab of front window' else: # 通用方案:通过 System Events script = f''' tell application "System Events" tell process "{browser}" -- 尝试获取地址栏内容 end tell end tell ''' r = subprocess.run(['osascript', '-e', script], capture_output=True, text=True) return r.stdout.strip() ``` ### 优先级 4:Cursor MCP Browser 工具 使用 Cursor 内置的 `cursor-ide-browser` MCP 服务进行浏览器交互。 ### 优先级 5:CDP 连接已运行浏览器(最后手段) 仅在必须进行 DOM 自动化操作时使用,且必须连接已运行的浏览器: ```python from playwright.sync_api import sync_playwright # ⚠️ 仅连接已运行的浏览器,不启动新实例 # 需要浏览器已开启远程调试端口 with sync_playwright() as p: browser = p.chromium.connect_over_cdp("http://localhost:9222") context = browser.contexts[0] # 使用已有的 context page = context.pages[0] # 使用已有的 page ``` --- ## 三、检测系统默认浏览器 ```python import subprocess, json, os def get_default_browser(): """获取 macOS 系统默认浏览器 bundle ID 和名称""" r = subprocess.run(['plutil', '-convert', 'json', '-o', '-', os.path.expanduser('~/Library/Preferences/com.apple.LaunchServices/com.apple.launchservices.secure.plist')], capture_output=True, text=True) bundle_id = 'com.apple.Safari' # 默认 Safari if r.returncode == 0: data = json.loads(r.stdout) for h in data.get('LSHandlers', []): if h.get('LSHandlerURLScheme') == 'https': bundle_id = h.get('LSHandlerRoleAll', 'com.apple.Safari') break # 常见浏览器 bundle ID → 名称 browser_names = { 'com.google.chrome': 'Google Chrome', 'com.apple.safari': 'Safari', 'com.brave.browser': 'Brave Browser', 'com.microsoft.edgemac': 'Microsoft Edge', 'company.thebrowser.browser': 'Arc', 'com.bot.pc.doubao.browser': '豆包浏览器', 'org.mozilla.firefox': 'Firefox', 'com.opera.opera': 'Opera', } return { 'bundle_id': bundle_id, 'name': browser_names.get(bundle_id, bundle_id), } # 当前系统默认浏览器:豆包浏览器 (com.bot.pc.doubao.browser) ``` --- ## 四、禁止行为清单 | 禁止行为 | 说明 | |:---|:---| | `playwright.chromium.launch()` | 会创建全新的隔离浏览器实例 | | `playwright.chromium.launch_persistent_context()` | 虽然复用数据目录,但会锁定 profile 导致冲突 | | `webdriver.Chrome()` | 创建新的 ChromeDriver 实例 | | `--incognito` / `--inprivate` | 无痕模式,丢失所有登录态 | | `headless=True` | 无界面模式,无法复用已有会话 | | 硬编码浏览器路径 | 如 `/Applications/Google Chrome.app/...` | --- ## 五、各技能适配说明 | 技能 | 原方案 | 新方案 | |:---|:---|:---| | 网站逆向分析 | Playwright launch + Stealth | API 调用优先;需要浏览器时用 `open` + AppleScript | | 流量自动化 | Selenium WebDriver | API 调用优先;需要浏览器时用 `open` + AppleScript | | 飞书管理 | Playwright 无痕窗口 | API 调用(飞书 Open API);需要浏览器时用 `open` | | 存客宝 | 无浏览器依赖 | 无需修改 | --- ## 六、常见场景处理 ### 场景1:需要用户登录后操作 ```bash # 直接用默认浏览器打开登录页(用户已有登录态则自动跳过) open "https://project.feishu.cn/settings" ``` ### 场景2:需要自动填表/点击 ```python # 优先用 API 完成 # 若必须用浏览器,用 AppleScript 操作已打开的页面 import subprocess script = ''' tell application "System Events" tell process "豆包浏览器" -- 模拟键盘/鼠标操作 keystroke "v" using command down -- 粘贴 delay 1 keystroke return -- 回车 end tell end tell ''' subprocess.run(['osascript', '-e', script]) ``` ### 场景3:需要获取浏览器中的数据 ```python # 用 API 获取(最佳) # 或用 AppleScript 获取当前页面信息 import subprocess script = ''' tell application "Google Chrome" set pageSource to execute active tab of front window javascript "document.title" return pageSource end tell ''' result = subprocess.run(['osascript', '-e', script], capture_output=True, text=True) print(result.stdout.strip()) ``` --- ## 七、版本记录 | 日期 | 版本 | 变更 | |:---|:---|:---| | 2026-02-13 | v1.0 | 初版,明确默认浏览器优先、禁止新建实例 |