How can I reconnect to the browser opened by webdr

2018-12-31 07:08发布

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 execute webdriver.quit() this will leave the browser opened. It is probably kind of HOOK or webdriver handle. I have looked up the selenium API doc but didn't find any function. I'm using Chrome 62,x64,windows 7,selenium 3.8.0. I'll be very appreciated whether the question can be solved or not.

3条回答
不流泪的眼
2楼-- · 2018-12-31 07:44

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
查看更多
谁念西风独自凉
3楼-- · 2018-12-31 07:48

That's actually easy to do - a SE session is represented by a connection url, and session_id.

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.
E.g. don't use it in your particular case, if you are not really sure you need it :)

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 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 (that started sometime around Selenium3, though I am not sure for the exact time) - and now you have 1 process with 2 sessions.

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, 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). 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 :)

查看更多
忆尘夕之涩
4楼-- · 2018-12-31 08:00

No, you can't reconnect to the previous Web Browser session after quiting the script. Even if you are able to extract the Session ID, Cookies and other session attributes from the previous Browsing Session 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 Session.

History :

Previously there had been some discussions and attempts to reconnect WebDriver to an existing running browsing session. You can find the discussions in these QA :

查看更多
登录 后发表回答