3

I know with Pyppeteer (Puppeteer) or Selenium, I can simply add chrome/chromium extensions by including them in args like this:

args=[
     f'--disable-extensions-except={pathToExtension}',
     f'--load-extension={pathToExtension}'
]

I also know the selenium has the very useful load_extension fx.

I was wondering if there was a similarly easy way to load extensions/add ons in firefox for Playwright? Or perhaps just with the firefox_user_args

I've seen an example in JS using this:

const path = require('path');
const {firefox} = require('playwright');
const webExt = require('web-ext').default;

(async () => {
  // 1. Enable verbose logging and start capturing logs.
  webExt.util.logger.consoleStream.makeVerbose();
  webExt.util.logger.consoleStream.startCapturing();

  // 2. Launch firefox
  const runner = await webExt.cmd.run({
    sourceDir: path.join(__dirname, 'webextension'),
    firefox: firefox.executablePath(),
    args: [`-juggler=1234`],
  }, {
    shouldExitProgram: false,
  });

  // 3. Parse firefox logs and extract juggler endpoint.
  const JUGGLER_MESSAGE = `Juggler listening on`;
  const message = webExt.util.logger.consoleStream.capturedMessages.find(msg => msg.includes(JUGGLER_MESSAGE));
  const wsEndpoint = message.split(JUGGLER_MESSAGE).pop();

  // 4. Connect playwright and start driving browser.
  const browser = await firefox.connect({ wsEndpoint });
  const page = await browser.newPage();
  await page.goto('https://mozilla.org');
  // .... go on driving ....
})();

Is there anything similar for python?

BunnyHoppin
  • 39
  • 2
  • 5

1 Answers1

1

Tldr; Code at the end

After wasting too much time into this, I have found a way to install extensions in Firefox in Playwright, feature that I think it is not to be supported for now, since Chromium has that feature and works.

Since in firefox adding an extension requires user clicking a special popup that raises when you click to install the extension, I figured it was easier just to download the xpi file and then install it through the file.

To install a file as an extension, we need to get to the url 'about:debugging#/runtime/this-firefox', to install a temporary extension. But in that url you cannot use the console or the dom due to protection that firefox has and that I haven't been able to avoid.

However, we know that about:debugging runs in a special tab id, so whe can open a new tab 'about:devtools-toolbox' where we can fake user inputs to run commands in a GUI console. The code on how to run a file is to load the file as 'nsIFile'. To do that we make use of the already loaded packages in 'about:debugging' and we load the required packages.

The following code is Python, but I guess translating it into Javascript should be no big deal

# get the absolute path for all the xpi extensions
extensions = [os.path.abspath(f"Settings/Addons/{file}") for file in os.listdir("Settings/Addons") if file.endswith(".xpi")]
if(not len(extensions)):
    return

c1 = "const { AddonManager } = require('resource://gre/modules/AddonManager.jsm');"
c2 = "const { FileUtils } = require('resource://gre/modules/FileUtils.jsm');"
c3 = "AddonManager.installTemporaryAddon(new FileUtils.File('{}'));"

context = await browser.new_context()
page = await context.new_page()
page2 = await context.new_page()
await page.goto("about:debugging#/runtime/this-firefox", wait_until="domcontentloaded")
await page2.goto("about:devtools-toolbox?id=9&type=tab", wait_until="domcontentloaded")
await asyncio.sleep(1)
await page2.keyboard.press("Tab")
await page2.keyboard.down("Shift")
await page2.keyboard.press("Tab")
await page2.keyboard.press("Tab")
await page2.keyboard.up("Shift")
await page2.keyboard.press("ArrowRight")
await page2.keyboard.press("Enter")

await page2.keyboard.type(f"{' '*10}{c1}{c2}")
await page2.keyboard.press("Enter")

for extension in extensions:
    print(f"Adding extension: {extension}")
    await asyncio.sleep(0.2)
    await page2.keyboard.type(f"{' '*10}{c3.format(extension)}")
    await page2.keyboard.press("Enter")
    #await asyncio.sleep(0.2)
    await page2.bring_to_front()

Note that there are some sleep because the page needs to load but Playwright cannot detect it

I needed to add some whitespaces because for some reason, playwright or firefox were missing some of the first characters in the commands

Also, if you want to install more than one addon, I suggest you try to find the amount of sleep before bringing to front in case the addon opens a new tab

Saisua
  • 11
  • 1