175

Does anybody know if Selenium (WebDriver preferably) is able to communicate with and act through a browser that is already running before launching a Selenium Client?

I mean if Selenium is able to comunicate with a browser without using the Selenium Server (with could be an Internet Explorer launched manually for example).

Tomasz Stanczak
  • 12,796
  • 1
  • 30
  • 32
Angel Romero
  • 2,089
  • 2
  • 14
  • 17

15 Answers15

90

This is a duplicate answer **Reconnect to a driver in python selenium ** This is applicable on all drivers and for java api.

  1. open a driver
driver = webdriver.Firefox()  #python
  1. extract to session_id and _url from driver object.
url = driver.command_executor._url       #"http://127.0.0.1:60622/hub"
session_id = driver.session_id            #'4e167f26-dc1d-4f51-a207-f761eaf73c31'
  1. Use these two parameter to connect to your driver.
driver = webdriver.Remote(command_executor=url,desired_capabilities={})
driver.close()   # this prevents the dummy browser
driver.session_id = session_id

And you are connected to your driver again.

driver.get("http://www.mrsmart.in")
ftoyoshima
  • 363
  • 5
  • 10
Manoj Sahu
  • 2,774
  • 20
  • 18
  • 8
    It works for me except a duplicate dummy browser is raising each time. – Pavel Vlasov Jan 10 '18 at 18:56
  • 1
    I am getting the dummy window also, it's not that big of a deal, but during debugging it is annoying. Any ideas on how to get rid of? – Steve Gon May 03 '18 at 19:22
  • 1
    +1. Works for my purpose of avoiding 2-factor auth logins however duplicate dummy browsers are present. I can live with that. – Sam Mar 14 '19 at 10:45
  • 2
    If you need to close the dummy browser window, simply call `driver.close()` before updating the session id. – Amr Awad Mar 24 '20 at 07:39
  • 1
    I tried this using a Chrome webdriver in Python but I didn't manage to connect and to sign in to Gmail unfortunately. – lazarea Jun 15 '20 at 09:48
  • 14
    `selenium.common.exceptions.SessionNotCreatedException: Message: Session is already started` – Cerin Jun 16 '20 at 21:28
  • 2
    I tried this solution, but it does not work and I get an error stating selenium.common.exceptions.SessionNotCreatedException: Message: Session is already started. – Vishwanath Heddoori Aug 25 '21 at 06:06
  • 1
    I don't get this answer- if I have multiple chrome browsers opened, how does selenium will know to which one to connect? – Moran Reznik Jun 05 '22 at 13:56
  • With this solution, I'm facing the following error: `Caused by NewConnectionError(': Failed to establish a new connection:` – Gustavo Louis G. Montańo Jan 15 '23 at 19:56
52

This is a pretty old feature request: Allow webdriver to attach to a running browser . So it's officially not supported.

However, there is some working code which claims to support this: https://web.archive.org/web/20171214043703/http://tarunlalwani.com/post/reusing-existing-browser-session-selenium-java/.

Robert Munteanu
  • 67,031
  • 36
  • 206
  • 278
  • Thank you very much because in that link I have found a class which allow to do that, but unfortunately I cant use that solution with IE (only with Firefox). I'm going to launch a regular IEDriver and comunicate with it from other proccesses using a middleware. If you have an idea why the class isn't working on IE I would appreciate it. Thank you. – Angel Romero Dec 02 '11 at 11:51
  • Robert, its 2018 now. Could you please update your answer ? – MasterJoe Jun 06 '18 at 02:08
  • In case anyone needs it, I have tried and tested some Java code to make selenium use an existing browser session - https://stackoverflow.com/a/51145789/6648326. – MasterJoe Jul 09 '18 at 01:40
  • @AngelRomero How about choosing a new answer. A lot of functionality has been developed since this question was asked. – Mugen Feb 21 '21 at 04:39
  • Just in case someone found this article first, it doesn't work. But this worked for me: https://stackoverflow.com/questions/51214668/python-selenium-how-to-use-debugger-address-option-in-chrome-driver-for-remote – Frank Buss May 07 '22 at 04:20
48

This snippet successfully allows to reuse existing browser instance yet avoiding raising the duplicate browser. Found at Tarun Lalwani's blog.

from selenium import webdriver
from selenium.webdriver.remote.webdriver import WebDriver

# executor_url = driver.command_executor._url
# session_id = driver.session_id

def attach_to_session(executor_url, session_id):
    original_execute = WebDriver.execute
    def new_command_execute(self, command, params=None):
        if command == "newSession":
            # Mock the response
            return {'success': 0, 'value': None, 'sessionId': session_id}
        else:
            return original_execute(self, command, params)
    # Patch the function before creating the driver object
    WebDriver.execute = new_command_execute
    driver = webdriver.Remote(command_executor=executor_url, desired_capabilities={})
    driver.session_id = session_id
    # Replace the patched function with original function
    WebDriver.execute = original_execute
    return driver

bro = attach_to_session('http://127.0.0.1:64092', '8de24f3bfbec01ba0d82a7946df1d1c3')
bro.get('http://ya.ru/')
ccpizza
  • 28,968
  • 18
  • 162
  • 169
Pavel Vlasov
  • 4,206
  • 6
  • 41
  • 54
  • 3
    Is there a way to find the existing session id and executor URL through automation? In my case, another application opened a browser session and I want to use that. Can you please recommend, how to find the browser session id of that? – Sun Shine Dec 03 '19 at 20:50
  • Probably you can dump the executor_command url & session id into a file when the script starts and read it from the file when do you want to hook the browser session again. – S.K. Venkat Dec 22 '19 at 16:04
  • @S.K.Venkat how can I get session id of chrome window, I opened it using pywinauto and now want to run selenuim on it, is there a python way to get session id of chrome tab – Tayyab Nasir Feb 11 '20 at 16:43
  • 1
    @TayyabNasir, kindly look out the above answer. The fifth line which was commented out `# session_id = driver.session_id` is the way you can retrieve the session id of a chrome window using python selenium api. I guess that each tab in a chrome session doesn't have unique ID. – S.K. Venkat Feb 11 '20 at 18:09
  • 17
    @S.K. I want session Id of the chrome window that I opened manually, I didn’t open that window using selenium – Tayyab Nasir Feb 12 '20 at 21:11
  • 2
    `driver.service.service_url` also works for the URL, and doesn't require access to a protected filed. – Spencer Connaughton Jan 29 '21 at 21:25
  • This worked brilliantly ! – Kira Sep 24 '22 at 03:57
17

From here, if the browser was manually opened, then remote debugging can be used:

  1. Start chrome with

    chrome --remote-debugging-port=9222
    

Or with optional profile

chrome.exe --remote-debugging-port=9222 --user-data-dir="C:\selenium\ChromeProfile"
  1. Then: Java:
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
    
//Change chrome driver path accordingly
System.setProperty("webdriver.chrome.driver", "C:\\selenium\\chromedriver.exe");
ChromeOptions options = new ChromeOptions();
options.setExperimentalOption("debuggerAddress", "127.0.0.1:9222");
WebDriver driver = new ChromeDriver(options);
System.out.println(driver.getTitle());

Python:

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
   
chrome_options = Options()
chrome_options.add_experimental_option("debuggerAddress", "127.0.0.1:9222")
#Change chrome driver path accordingly
chrome_driver = "C:\chromedriver.exe"
driver = webdriver.Chrome(chrome_driver, chrome_options=chrome_options)
print driver.title
Ahmed Ashour
  • 5,179
  • 10
  • 35
  • 56
  • 3
    Underrated! Simple and easy solution. I firstly had a problem that selenium opened another browser window. I used a [driver manager](https://www.selenium.dev/documentation/webdriver/getting_started/install_drivers/#1-driver-management-software) in place of chrome_driver and I forgot to use the chrome_options second parameter. – Ashark Apr 12 '22 at 18:32
  • 1
    Ashark, could you provide more info how you did that? – vlatko606 Nov 15 '22 at 10:45
14

It is possible. But you have to hack it a little, there is a code What you have to do is to run stand alone server and "patch" RemoteWebDriver

public class CustomRemoteWebDriver : RemoteWebDriver
{
    public static bool newSession;
    public static string capPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "TestFiles", "tmp", "sessionCap");
    public static string sessiodIdPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "TestFiles", "tmp", "sessionid");

    public CustomRemoteWebDriver(Uri remoteAddress) 
        : base(remoteAddress, new DesiredCapabilities())
    {
    }

    protected override Response Execute(DriverCommand driverCommandToExecute, Dictionary<string, object> parameters)
    {
        if (driverCommandToExecute == DriverCommand.NewSession)
        {
            if (!newSession)
            {
                var capText = File.ReadAllText(capPath);
                var sidText = File.ReadAllText(sessiodIdPath);

                var cap = JsonConvert.DeserializeObject<Dictionary<string, object>>(capText);
                return new Response
                {
                    SessionId = sidText,
                    Value = cap
                };
            }
            else
            {
                var response = base.Execute(driverCommandToExecute, parameters);
                var dictionary = (Dictionary<string, object>) response.Value;
                File.WriteAllText(capPath, JsonConvert.SerializeObject(dictionary));
                File.WriteAllText(sessiodIdPath, response.SessionId);
                return response;
            }
        }
        else
        {
            var response = base.Execute(driverCommandToExecute, parameters);
            return response;
        }
    }
}
user202729
  • 3,358
  • 3
  • 25
  • 36
Alex Ilyin
  • 1,294
  • 1
  • 12
  • 22
  • 6
    Based on this excellent solution, I have written a complete blog post in which I have discussed how to connect to an already opened browser instance of chrome. Full source code is also attached on that blog post. http://binaryclips.com/2015/08/25/selenium-webdriver-in-c-how-to-use-the-existing-window-of-chrome-browser/ – joinsaad Aug 25 '15 at 11:32
  • Based on this excellent solution, this is the version for Python 3: https://github.com/kassi-blk/webdriver-transfer-driver – Kassi Jan 17 '23 at 19:41
7

Inspired by Eric's answer, here is my solution to this problem for selenium 3.7.0. Compared with the solution at http://tarunlalwani.com/post/reusing-existing-browser-session-selenium/, the advantage is that there won't be a blank browser window each time I connect to the existing session.

import warnings

from selenium.common.exceptions import WebDriverException
from selenium.webdriver.remote.errorhandler import ErrorHandler
from selenium.webdriver.remote.file_detector import LocalFileDetector
from selenium.webdriver.remote.mobile import Mobile
from selenium.webdriver.remote.remote_connection import RemoteConnection
from selenium.webdriver.remote.switch_to import SwitchTo
from selenium.webdriver.remote.webdriver import WebDriver


# This webdriver can directly attach to an existing session.
class AttachableWebDriver(WebDriver):
    def __init__(self, command_executor='http://127.0.0.1:4444/wd/hub',
                 desired_capabilities=None, browser_profile=None, proxy=None,
                 keep_alive=False, file_detector=None, session_id=None):
        """
        Create a new driver that will issue commands using the wire protocol.

        :Args:
         - command_executor - Either a string representing URL of the remote server or a custom
             remote_connection.RemoteConnection object. Defaults to 'http://127.0.0.1:4444/wd/hub'.
         - desired_capabilities - A dictionary of capabilities to request when
             starting the browser session. Required parameter.
         - browser_profile - A selenium.webdriver.firefox.firefox_profile.FirefoxProfile object.
             Only used if Firefox is requested. Optional.
         - proxy - A selenium.webdriver.common.proxy.Proxy object. The browser session will
             be started with given proxy settings, if possible. Optional.
         - keep_alive - Whether to configure remote_connection.RemoteConnection to use
             HTTP keep-alive. Defaults to False.
         - file_detector - Pass custom file detector object during instantiation. If None,
             then default LocalFileDetector() will be used.
        """
        if desired_capabilities is None:
            raise WebDriverException("Desired Capabilities can't be None")
        if not isinstance(desired_capabilities, dict):
            raise WebDriverException("Desired Capabilities must be a dictionary")
        if proxy is not None:
            warnings.warn("Please use FirefoxOptions to set proxy",
                          DeprecationWarning)
            proxy.add_to_capabilities(desired_capabilities)
        self.command_executor = command_executor
        if type(self.command_executor) is bytes or isinstance(self.command_executor, str):
            self.command_executor = RemoteConnection(command_executor, keep_alive=keep_alive)

        self.command_executor._commands['GET_SESSION'] = ('GET', '/session/$sessionId')  # added

        self._is_remote = True
        self.session_id = session_id  # added
        self.capabilities = {}
        self.error_handler = ErrorHandler()
        self.start_client()
        if browser_profile is not None:
            warnings.warn("Please use FirefoxOptions to set browser profile",
                          DeprecationWarning)

        if session_id:
            self.connect_to_session(desired_capabilities)  # added
        else:
            self.start_session(desired_capabilities, browser_profile)

        self._switch_to = SwitchTo(self)
        self._mobile = Mobile(self)
        self.file_detector = file_detector or LocalFileDetector()

        self.w3c = True  # added hardcoded

    def connect_to_session(self, desired_capabilities):
        response = self.execute('GET_SESSION', {
            'desiredCapabilities': desired_capabilities,
            'sessionId': self.session_id,
        })
        # self.session_id = response['sessionId']
        self.capabilities = response['value']

To use it:

if use_existing_session:
    browser = AttachableWebDriver(command_executor=('http://%s:4444/wd/hub' % ip),
                                  desired_capabilities=(DesiredCapabilities.INTERNETEXPLORER),
                                  session_id=session_id)
    self.logger.info("Using existing browser with session id {}".format(session_id))
else:
    browser = AttachableWebDriver(command_executor=('http://%s:4444/wd/hub' % ip),
                                  desired_capabilities=(DesiredCapabilities.INTERNETEXPLORER))
    self.logger.info('New session_id  : {}'.format(browser.session_id))
ccpizza
  • 28,968
  • 18
  • 162
  • 169
Big Pumpkin
  • 3,907
  • 1
  • 27
  • 18
4

It appears that this feature is not officially supported by selenium. But, Tarun Lalwani has created working Java code to provide the feature. Refer - http://tarunlalwani.com/post/reusing-existing-browser-session-selenium-java/

Here is the working sample code, copied from the above link:

import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.remote.*;
import org.openqa.selenium.remote.http.W3CHttpCommandCodec;
import org.openqa.selenium.remote.http.W3CHttpResponseCodec;

import java.io.IOException;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.Collections;

public class TestClass {
    public static RemoteWebDriver createDriverFromSession(final SessionId sessionId, URL command_executor){
        CommandExecutor executor = new HttpCommandExecutor(command_executor) {

            @Override
            public Response execute(Command command) throws IOException {
                Response response = null;
                if (command.getName() == "newSession") {
                    response = new Response();
                    response.setSessionId(sessionId.toString());
                    response.setStatus(0);
                    response.setValue(Collections.<String, String>emptyMap());

                    try {
                        Field commandCodec = null;
                        commandCodec = this.getClass().getSuperclass().getDeclaredField("commandCodec");
                        commandCodec.setAccessible(true);
                        commandCodec.set(this, new W3CHttpCommandCodec());

                        Field responseCodec = null;
                        responseCodec = this.getClass().getSuperclass().getDeclaredField("responseCodec");
                        responseCodec.setAccessible(true);
                        responseCodec.set(this, new W3CHttpResponseCodec());
                    } catch (NoSuchFieldException e) {
                        e.printStackTrace();
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }

                } else {
                    response = super.execute(command);
                }
                return response;
            }
        };

        return new RemoteWebDriver(executor, new DesiredCapabilities());
    }

    public static void main(String [] args) {

        ChromeDriver driver = new ChromeDriver();
        HttpCommandExecutor executor = (HttpCommandExecutor) driver.getCommandExecutor();
        URL url = executor.getAddressOfRemoteServer();
        SessionId session_id = driver.getSessionId();


        RemoteWebDriver driver2 = createDriverFromSession(session_id, url);
        driver2.get("http://tarunlalwani.com");
    }
}

Your test needs to have a RemoteWebDriver created from an existing browser session. To create that Driver, you only need to know the "session info", i.e. address of the server (local in our case) where the browser is running and the browser session id. To get these details, we can create one browser session with selenium, open the desired page, and then finally run the actual test script.

I don't know if there is a way to get session info for a session which was not created by selenium.

Here is an example of session info:

Address of remote server : http://localhost:24266. The port number is different for each session. Session Id : 534c7b561aacdd6dc319f60fed27d9d6.

MasterJoe
  • 2,103
  • 5
  • 32
  • 58
  • 1
    "I don't know if there is a way to get session info for a session which was not created by selenium." it's actually a problem I have been trying for a couple of days already... no success yet – slesh Sep 09 '18 at 19:49
  • @slesh - I suggest you create a new question for that and maybe offer 100 of your points if it does not get enough attention. – MasterJoe Nov 18 '19 at 00:52
  • 1
    Thanks for the reference to Tarun Lalwani's work. Between his page and your answer, I was able to figure it out. The imports would have been nice, as well as comments explaining the purpose of some of the statements. But all and all, very helpful. – Tihamer Oct 14 '20 at 23:53
3

All the solutions so far were lacking of certain functionality. Here is my solution:

public class AttachedWebDriver extends RemoteWebDriver {

    public AttachedWebDriver(URL url, String sessionId) {
        super();
        setSessionId(sessionId);
        setCommandExecutor(new HttpCommandExecutor(url) {
            @Override
            public Response execute(Command command) throws IOException {
                if (command.getName() != "newSession") {
                    return super.execute(command);
                }
                return super.execute(new Command(getSessionId(), "getCapabilities"));
            }
        });
        startSession(new DesiredCapabilities());
    }
}
Yanir
  • 73
  • 1
  • 8
  • What functionality does this add (that the others are missing)? – jalanb Aug 08 '16 at 13:25
  • 1
    Internally, just the startSession(...) method will initialize the capabilities object. The capabilities object is required for many methods such as takeScreenshot, executeScript and more. But by going through startSession you will have to create a new session creation. This overload skips the creation of a new session but still leads to capabilities object initialization. – Yanir Aug 11 '16 at 18:04
  • 2
    dude, don't compare strings with == – Norill Tempest Jul 15 '19 at 15:35
3

Javascript solution:

I have successfully attached to existing browser session using this function

webdriver.WebDriver.attachToSession(executor, session_id);

Documentation can be found here.

gm2008
  • 4,245
  • 1
  • 36
  • 38
1

I got a solution in python, I modified the webdriver class bassed on PersistenBrowser class that I found.

https://github.com/axelPalmerin/personal/commit/fabddb38a39f378aa113b0cb8d33391d5f91dca5

replace the webdriver module /usr/local/lib/python2.7/dist-packages/selenium/webdriver/remote/webdriver.py

Ej. to use:

from selenium.webdriver.common.desired_capabilities import DesiredCapabilities

runDriver = sys.argv[1]
sessionId = sys.argv[2]

def setBrowser():
    if eval(runDriver):
        webdriver = w.Remote(command_executor='http://localhost:4444/wd/hub',
                     desired_capabilities=DesiredCapabilities.CHROME,
                     )
    else:
        webdriver = w.Remote(command_executor='http://localhost:4444/wd/hub',
                             desired_capabilities=DesiredCapabilities.CHROME,
                             session_id=sessionId)

    url = webdriver.command_executor._url
    session_id = webdriver.session_id
    print url
    print session_id
    return webdriver
Eric Axel
  • 21
  • 1
  • 3
1

Use Chrome's built in remote debugging. Launch Chrome with remote debugging port open. I did this on OS X:

sudo nohup /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --remote-debugging-port=9222 &

Tell Selenium to use the remote debugging port:

from selenium import webdriver

options = webdriver.ChromeOptions()
options.add_argument('--remote-debugging-port=9222')
driver = webdriver.Chrome("./chromedriver", chrome_options=options)
Joshua Cook
  • 12,495
  • 2
  • 35
  • 31
0

I'm using Rails + Cucumber + Selenium Webdriver + PhantomJS, and I've been using a monkey-patched version of Selenium Webdriver, which keeps PhantomJS browser open between test runs. See this blog post: http://blog.sharetribe.com/2014/04/07/faster-cucumber-startup-keep-phantomjs-browser-open-between-tests/

See also my answer to this post: How do I execute a command on already opened browser from a ruby file

Community
  • 1
  • 1
rap1ds
  • 629
  • 1
  • 5
  • 10
0

Solution using Python programming language.

from selenium import webdriver
from selenium.webdriver.remote.webdriver import WebDriver
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities



executor_url = "http://localhost:4444/wd/hub"
# Create a desired capabilities object as a starting point.
capabilities = DesiredCapabilities.FIREFOX.copy()
capabilities['platform'] = "WINDOWS"
capabilities['version'] = "10"

# ------------------------ STEP 1 --------------------------------------------------


# driver1 = webdriver.Firefox()
driver1 = webdriver.Remote(command_executor=executor_url, desired_capabilities=capabilities)
driver1.get('http://google.com/')
url = driver1.command_executor._url       
print(driver1.command_executor._url)
print(driver1.session_id)
print(driver1.title)

# Serialize the session id in a file
session_id = driver1.session_id

# ------------------ END OF STEP 1 --------------------------------------------------

# Pass the session id from step 1 to step 2

# ------------------------ STEP 2 --------------------------------------------------
def attach_to_session(executor_url, session_id):
    original_execute = WebDriver.execute
    def new_command_execute(self, command, params=None):
        if command == "newSession":
            # Mock the response
            return {'success': 0, 'value': None, 'sessionId': session_id}
        else:
            return original_execute(self, command, params)
    
    # Patch the function before creating the driver object
    WebDriver.execute = new_command_execute

    temp_driver = webdriver.Remote(command_executor=executor_url)
    # Replace the patched function with original function
    WebDriver.execute = original_execute
    return temp_driver

# read the session id from the file
driver2 = attach_to_session(executor_url, existing_session_id)
driver2.get('http://msn.com/')

print(driver2.command_executor._url)
print(driver2.session_id)

print(driver2.title)
driver2.close()
# ------------------ END OF STEP 2 --------------------------------------------------
0

After trying most of these solutions, this solution has worked for me the best. Thanks to @Ahmed_Ashour.

For those who are struggling with this problem, here are a few tips to make your life a bit easier:

1- use a driver manager instead of a manually installed driver (to avoid compatibility issues)

from webdriver_manager.chrome import ChromeDriverManager

driver = webdriver.Chrome(ChromeDriverManager().install(),options=chrome_options)

2- Make sure to close the running chrome instance before starting the new one with the debugging port

chrome.exe --remote-debugging-port=9222 --user-data-dir="C:\selenum\ChromeProfile"
Kassab
  • 82
  • 1
  • 7
-1

This is pretty easy using the JavaScript selenium-webdriver client:

First, make sure you have a WebDriver server running. For example, download ChromeDriver, then run chromedriver --port=9515.

Second, create the driver like this:

var driver = new webdriver.Builder()
   .withCapabilities(webdriver.Capabilities.chrome())
   .usingServer('http://localhost:9515')  // <- this
   .build();

Here's a complete example:

var webdriver = require('selenium-webdriver');

var driver = new webdriver.Builder()
   .withCapabilities(webdriver.Capabilities.chrome())
   .usingServer('http://localhost:9515')
   .build();

driver.get('http://www.google.com');
driver.findElement(webdriver.By.name('q')).sendKeys('webdriver');
driver.findElement(webdriver.By.name('btnG')).click();
driver.getTitle().then(function(title) {
   console.log(title);
 });

driver.quit();
Dan Dascalescu
  • 143,271
  • 52
  • 317
  • 404
  • 4
    It does not use EXISTING browser session. It creates a new chromedriver session and opens a new browser window. And getAllWindowHandles() will not show your old browser window's handle. – Dzenly May 11 '16 at 06:14
  • Update: There is http://seleniumhq.github.io/selenium/docs/api/javascript/module/selenium-webdriver/lib/webdriver_exports_WebDriver.html#WebDriver.attachToSession Which allows to connect to existing opened browser window. – Dzenly Jul 08 '17 at 09:50