Playwright使用Firefox如何简便加载扩展?是否有对应Python实现方案?
Playwright Python目前没有内置的类似Selenium load_extension的快捷方法加载Firefox扩展,也无法仅通过firefox_user_args参数直接实现(Firefox本身没有类似Chrome的--load-extension启动参数),你可以通过以下两种方案实现:
方案1:和JS版逻辑一致的web-ext调用方案
需要先全局安装web-ext工具:npm install -g web-ext
import asyncio import subprocess import re from pathlib import Path from playwright.async_api import async_playwright async def main(): # 替换为你自己的扩展目录路径 extension_path = Path("./webextension").absolute() async with async_playwright() as p: # 调用web-ext启动内置Firefox并开启Juggler调试端口 proc = subprocess.Popen( [ "web-ext", "run", "--source-dir", str(extension_path), "--firefox", p.firefox.executable_path, "--args", "-juggler=1234" ], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True ) # 从输出日志提取WebSocket连接端点 ws_endpoint = None juggler_pattern = re.compile(r"Juggler listening on (ws://.+:\d+)") for line in iter(proc.stdout.readline, ""): match = juggler_pattern.search(line) if match: ws_endpoint = match.group(1) break if not ws_endpoint: raise RuntimeError("未获取到Juggler调试端点,启动失败") # 连接已启动的Firefox实例 browser = await p.firefox.connect(ws_endpoint=ws_endpoint) page = await browser.new_page() await page.goto("https://mozilla.org") # 此处编写你的业务逻辑 # ... # 资源释放 await browser.close() proc.terminate() if __name__ == "__main__": asyncio.run(main())
方案2:自定义Firefox Profile方案(无Node.js依赖)
不需要安装web-ext,直接构造Firefox配置文件加载扩展,更适合纯Python环境:
import asyncio import tempfile import shutil import json from pathlib import Path from playwright.async_api import async_playwright async def main(): # 替换为你自己的扩展目录路径 extension_path = Path("./webextension").absolute() # 读取manifest获取扩展ID,也可以手动指定 with open(extension_path / "manifest.json", "r", encoding="utf-8") as f: manifest = json.load(f) ext_id = manifest.get("browser_specific_settings", {}).get("gecko", {}).get("id", "custom-extension@example.com") # 创建临时Firefox配置目录 with tempfile.TemporaryDirectory() as temp_profile_dir: temp_profile = Path(temp_profile_dir) # 创建扩展存放目录 ext_dir = temp_profile / "extensions" ext_dir.mkdir() # 复制扩展到对应目录,目录名必须为扩展ID target_ext_path = ext_dir / ext_id shutil.copytree(extension_path, target_ext_path) # 写入配置启用扩展,关闭安全限制 prefs_config = [ f'user_pref("extensions.webextensions.uuids", "{{\\"{ext_id}\\":\\"{ext_id}\\"}}");', f'user_pref("extensions.enabledAddons", "{ext_id}:{manifest.get("version", "1.0")}");', 'user_pref("extensions.autoDisableScopes", 0);', 'user_pref("extensions.enabledScopes", 15);' ] with open(temp_profile / "prefs.js", "a", encoding="utf-8") as f: f.write("\n".join(prefs_config)) # 启动带自定义配置的Firefox async with async_playwright() as p: context = await p.firefox.launch_persistent_context( user_data_dir=temp_profile_dir, headless=False, # 若要使用无头模式,Firefox版本≥112时可开启以下参数 # args=["--headless=new"] ) page = await context.new_page() await page.goto("https://mozilla.org") # 此处编写你的业务逻辑 # ... await context.close() if __name__ == "__main__": asyncio.run(main())
注意:如果使用打包好的xpi格式扩展,直接将xpi文件重命名为扩展ID.xpi放到extensions目录下即可,无需解压
内容的提问来源于stack exchange,提问作者BunnyHoppin
相关产品推荐
相关产品推荐

