how do I use an existing profile in-place with Selenium Webdriver?
Asked Answered
G

1

7

I am trying to do what the title says, using Python's Selenium Webdriver, with an existing Firefox profile living in <PROFILE-DIR>.

What I've tried

#!/usr/bin/env python

from selenium.webdriver.firefox.firefox_profile import FirefoxProfile
from selenium.webdriver import Firefox, DesiredCapabilities
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.firefox.options import Options

options = Options()
options.profile = '<PROFILE_DIR>'
webdriver = Firefox(options=options)

This copies the existing profile to a temporary location. I can see it works because the new session I start has access to the profile's old cookies, etc. But it is not what I am after: I want to use the profile in-place.

  • tried to pass the profile as '--profile ' to the args capability: change the code above to
capabilities = DesiredCapabilities.FIREFOX.copy()
capabilities['args'] = '--profile <PROFILE-DIR>'
webdriver = Firefox(desired_capabilities=capabilities)

Nothing doing: viewing the geckodriver.log after closing the session still shows me something like Running command: "/usr/bin/firefox" "--marionette" "-foreground" "-no-remote" "-profile" "/tmp/rust_mozprofileOFKY46", i.e. still using a temporary profile (which is not even a copy of the existing one; the old cookies are not there).

  • tried the same with capabilities['args'] = ['-profile', '<PROFILE-DIR>'] instead (i.e. a list of strings instead of a single string); same result.

  • read a bunch of other SO posts, none of which do it. This is mostly because they're specific to Chrome (to whose driver you can apparently pass command-line options; I haven't seen something like this for geckodriver), or because they fall back to copies of existing profiles.

The most relevant answer in this direction implements essentially the same hack I'd thought of, in a pinch:

  1. start the driver with a copy of your existing profile using options.profile as described above;

  2. close the driver instance manually when done (e.g. with a Ctrl+C, or SIGINT) so that the temp-profile directory isn't deleted;

  3. copy over all of the stuff that's left on top of the existing profile, giving you access to whatever leftovers you wanted from the automated session.

This is ugly and feels unnecessary. Besides, geckodriver's failure to remove temporary profiles (which I'd be relying on) is considered a bug..

Surely I'm misunderstanding how to pass those capability options mentioned above, or some such thing. But the docs could do a better job of giving examples.

Glace answered 13/5, 2021 at 1:56 Comment(0)
S
1

I've come up with a solution that allows the user to use a Firefox profile in place, by passing the profile path dynamically via an environment variable to Geckodriver.

I start by downloading Geckodriver 0.32.0 and made it so that you simply need to provide the Firefox profile directory via the environment variable FIREFOX_PROFILE_DIR.

The code change is in src/browser.rs, line 88, replacing:

    let mut profile = match options.profile {
        ProfileType::Named => None,
        ProfileType::Path(x) => Some(x),
        ProfileType::Temporary => Some(Profile::new(profile_root)?),
    };

with:

    let mut profile = if let Ok(profile_dir) = std::env::var("FIREFOX_PROFILE_DIR") {
        Some(Profile::new_from_path(Path::new(&profile_dir))?)
    } else {
        match options.profile {
            ProfileType::Named => None,
            ProfileType::Path(x) => Some(x),
            ProfileType::Temporary => Some(Profile::new(profile_root)?),
        }
    };

You may refer to my Git commit to see the diff against the original Geckodriver code.

Servitude answered 14/1, 2023 at 6:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.