You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Python的Selenium读取Safari Web Extension的本地存储?

在macOS上用Safari WebDriver读取Web扩展本地存储的问题

Firefox WebDriver的实现方式

我可以通过以下代码读取Firefox扩展的本地存储:

extension_path = "/path/to/my/extension"
info = {
    "extension_id": "foobar",
    "uuid": uuid.uuid4(),
}

base_url = f"moz-extension://{info['uuid']}/"

opts = FirefoxOptions()
opts.set_preference('extensions.webextensions.uuids', '{"%s": "%s"}' % (
    info["extension_id"], info["uuid"]))
driver = webdriver.Firefox(options=opts)
driver.install_addon(extension_path, temporary=True)

driver.get(f"{base_url}_generated_background_page.html")
results = driver.execute_async_script((
    "let done = arguments[arguments.length - 1],"
    "  store_name = arguments[0];"
    "browser.storage.local.get([store_name], function (res) {"
    "  done(res[store_name]);"
    "});"
), "foo")

Safari WebDriver遇到的问题

我已经通过xcrun safari-web-extension-converter /path/to/my/extension完成扩展移植,构建并手动测试确认扩展可正常运行。通过Develop -> Web Extension Background Pages -> <my web extension>可以找到扩展ID,后台页面地址为safari-web-extension://<id>/_generated_background_page.html。

但运行以下代码时,Selenium会在driver.get(f"{base_url}_generated_background_page.html")处冻结:

base_url = f"safari-web-extension://<id>/"

driver = webdriver.Safari()
driver.get(f"{base_url}_generated_background_page.html")
results = driver.execute_async_script((
    "let done = arguments[arguments.length - 1],"
    "  store_name = arguments[0];"
    "browser.storage.local.get([store_name], function (res) {"
    "  done(res[store_name]);"
    "});"
), "foo")

2023年2月8日更新:尝试runtime.sendMessage的问题

我尝试用browser.runtime.sendMessage的方式实现,但读取到的是手动打开的Safari实例中的扩展存储,而非Selenium启动的实例存储:

Selenium代码

results = driver.execute_async_script((
    "let done = arguments[arguments.length - 1],"
    "  store_name = arguments[0];"
    "  browser.runtime.sendMessage('com.oskar.foo.Extension (Apple Team ID)', {}, function (res) {"
    "    done(res[store_name]);"
    "  });"
), "foo")

扩展background.js代码

browser.runtime.onMessageExternal.addListener(function (
  request,
  sender,
  sendResponse
) {
  browser.storage.local.get("foo").then((j) => {
    sendResponse(j);
  });
  return true;
});

manifest.json配置

"externally_connectable": {
    "ids": ["*"],
    "matches": ["https://example.org/*"]
}

解决方法

核心思路

Safari WebDriver直接访问扩展后台页面会触发沙箱限制导致冻结,且ids: ["*"]的配置会让消息被所有扩展实例接收。需要通过普通页面注入脚本+精准消息通信的方式,确保访问的是Selenium启动实例的扩展存储。

具体步骤

  1. 修改扩展的externally_connectable配置
    仅允许Selenium控制的页面(如空白页、本地测试页)通信,避免跨实例干扰:

    "externally_connectable": {
        "matches": ["about:blank", "http://localhost:*/*"]
    }
    
  2. 更新扩展background.js的消息监听逻辑
    增加操作标识,明确响应存储读取请求:

    browser.runtime.onMessageExternal.addListener((request, sender, sendResponse) => {
        // 仅处理指定的存储读取操作
        if (request.action === "fetchStorage") {
            browser.storage.local.get(request.key).then(result => {
                sendResponse({value: result[request.key]});
            });
            return true; // 保持端口开放,支持异步返回结果
        }
    });
    
  3. 调整Selenium代码,通过普通页面通信
    不要直接访问扩展后台页面,而是打开空白页后注入脚本发送消息:

    from selenium import webdriver
    
    # 替换为你的扩展ID(可从Xcode项目Info.plist或Safari Develop菜单获取)
    EXTENSION_ID = "com.yourteam.yourextension"
    
    driver = webdriver.Safari()
    # 打开空白页作为通信载体
    driver.get("about:blank")
    
    # 执行异步脚本发送消息并获取存储值
    results = driver.execute_async_script("""
        const done = arguments[arguments.length - 1];
        const targetKey = arguments[0];
        browser.runtime.sendMessage(
            "%s",
            {action: "fetchStorage", key: targetKey},
            (response) => {
                done(response.value);
            }
        );
    """ % EXTENSION_ID, "foo")
    
    print(results)
    driver.quit()
    

关键注意事项

  • Selenium启动的Safari是独立的沙箱实例,需确保该实例中已启用目标扩展:打开Selenium启动的Safari后,通过Develop -> Allow Unsigned Extensions,再在Safari设置 -> 扩展中开启你的扩展。
  • 不要使用ids: ["*"],否则消息可能被其他Safari实例的扩展接收,导致读取到错误的存储数据。
  • 禁止直接访问扩展内部页面(如_generated_background_page.html),Safari WebDriver对这类页面的访问有严格限制,会导致会话冻结。

内容的提问来源于stack exchange,提问作者Oskar Persson

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 04:20:21