How can I reconnect to the browser opened by webdriver with selenium?

前端 未结 3 571
暗喜
暗喜 2020-11-21 11:10

For some unknown reasons ,my browser open test pages of my remote server very slowly. So I am thinking if I can reconnect to the browser after quitting the script but don\'t

相关标签:
3条回答
  • 2020-11-21 11:35

    No, you can't reconnect to the previous Web Browsing Session after you quit the script. Even if you are able to extract the Session ID, Cookies and other session attributes from the previous Browsing Context still you won't be able to pass those attributes as a HOOK to the WebDriver.

    A cleaner way would be to call webdriver.quit() and then span a new Browsing Context.


    Deep Dive

    There had been a lot of discussions and attempts around to reconnect WebDriver to an existing running Browsing Context. In the discussion Allow webdriver to attach to a running browser Simon Stewart [Creator WebDriver] clearly mentioned:

    • Reconnecting to an existing Browsing Context is a browser specific feature, hence can't be implemented in a generic way.
    • With internet-explorer, it's possible to iterate over the open windows in the OS and find the right IE process to attach to.
    • firefox and google-chrome needs to be started in a specific mode and configuration, which effectively means that just attaching to a running instance isn't technically possible.

    tl; dr

    webdriver.firefox.useExisting not implemented

    0 讨论(0)
  • 2020-11-21 11:37

    Yes, that's actually quite easy to do.

    A selenium <-> webdriver session is represented by a connection url and session_id, you just reconnect to an existing one.

    Disclaimer - the approach is using selenium internal properties ("private", in a way), which may change in new releases; you'd better not use it for production code; it's better not to be used against remote SE (yours hub, or provider like BrowserStack/Sauce Labs), because of a caveat/resource drainage explained at the end.

    When a webdriver instance is initiated, you need to get the before-mentioned properties; sample:

    from selenium import webdriver
    
    driver = webdriver.Chrome()
    driver.get('https://www.google.com/')
    
    # now Google is opened, the browser is fully functional; print the two properties
    # command_executor._url (it's "private", not for a direct usage), and session_id
    
    print(f'driver.command_executor._url: {driver.command_executor._url}')
    print(f'driver.session_id: {driver.session_id}')
    

    With those two properties now known, another instance can connect; the "trick" is to initiate a Remote driver, and provide the _url above - thus it will connect to that running selenium process:

    driver2 = webdriver.Remote(command_executor=the_known_url)  
    # when the started selenium is a local one, the url is in the form 'http://127.0.0.1:62526'
    

    When that is ran, you'll see a new browser window being opened.
    That's because upon initiating the driver, the selenium library automatically starts a new session for it - and now you have 1 webdriver process with 2 sessions (browsers instances).

    If you navigate to an url, you'll see it is executed on that new browser instance, not the one that's left from the previous start - which is not the desired behavior.
    At this point, two things need to be done - a) close the current SE session ("the new one"), and b) switch this instance to the previous session:

    if driver2.session_id != the_known_session_id:   # this is pretty much guaranteed to be the case
        driver2.close()   # this closes the session's window - it is currently the only one, thus the session itself will be auto-killed, yet:
        driver2.quit()    # for remote connections (like ours), this deletes the session, but does not stop the SE server
    
    # take the session that's already running
    driver2.session_id = the_known_session_id
    
    # do something with the now hijacked session:
    driver.get('https://www.bing.com/')
    

    And, that is it - you're now connected to the previous/already existing session, with all its properties (cookies, LocalStorage, etc).

    By the way, you do not have to provide desired_capabilities when initiating the new remote driver - those are stored and inherited from the existing session you took over.


    Caveat - having a SE process running can lead to some resource drainage in the system.

    Whenever one is started and then not closed - like in the first piece of the code - it will stay there until you manually kill it. By this I mean - in Windows for example - you'll see a "chromedriver.exe" process, that you have to terminate manually once you are done with it. It cannot be closed by a driver that has connected to it as to a remote selenium process.
    The reason - whenever you initiate a local browser instance, and then call its quit() method, it has 2 parts in it - the first one is to delete the session from the Selenium instance (what's done in the second code piece up there), and the other is to stop the local service (the chrome/geckodriver) - which generally works ok.

    The thing is, for Remote sessions the second piece is missing - your local machine cannot control a remote process, that's the work of that remote's hub. So that 2nd part is literally a pass python statement - a no-op.

    If you start too many selenium services on a remote hub, and don't have a control over it - that'll lead to resource drainage from that server. Cloud providers like BrowserStack take measures against this - they are closing services with no activity for the last 60s, etc, yet - this is something you don't want to do.

    And as for local SE services - just don't forget to occasionally clean up the OS from orphaned selenium drivers you forgot about :)

    0 讨论(0)
  • 2020-11-21 11:39

    Without getting into why do you think that leaving an open browser windows will solve the problem of being slow, you don't really need a handle to do that. Just keep running the tests without closing the session or, in other words, without calling driver.quit() as you have mentioned yourself. The question here though framework that comes with its own runner? Like Cucumber?

    In any case, you must have some "setup" and "cleanup" code. So what you need to do is to ensure during the "cleanup" phase that the browser is back to its initial state. That means:

    • Blank page is displayed
    • Cookies are erased for the session
    0 讨论(0)
提交回复
热议问题