Может ли Selenium взаимодействовать с существующим сеансом браузера?
Кто-нибудь знает, может ли Selenium (предпочтительно WebDriver) взаимодействовать и действовать через браузер, который уже запущен перед запуском клиента Selenium?
Я имею в виду, если Selenium может взаимодействовать с браузером без использования сервера Selenium (например, с помощью Internet Explorer, запущенного вручную).
11 ответов:
Это довольно старый запрос функции: разрешить webdriver подключаться к работающему браузеру. Так что официально это не поддерживается.
Однако существует некоторый рабочий код, который утверждает, что поддерживает это: https://web.archive.org/web/20171214043703/http://tarunlalwani.com/post/reusing-existing-browser-session-selenium-java/.
Это дубликат ответа. ** Повторное подключение к драйверу в python selenium * * это применимо для всех драйверов и для java api.
Откройте драйвер
driver = webdriver.Firefox() #python
Извлечение в session_id и _url из объекта драйвера.
url = driver.command_executor._url #"http://127.0.0.1:60622/hub" session_id = driver.session_id #'4e167f26-dc1d-4f51-a207-f761eaf73c31'
Используйте эти два параметра для подключения к драйверу.
driver = webdriver.Remote(command_executor=url,desired_capabilities={}) driver.session_id = session_id
И вы снова подключены к вашему водителю.
driver.get("http://www.mrsmart.in")
Это возможно. Но вы должны взломать его немного, есть код То, что вам нужно сделать, это запустить автономный сервер и" исправить " 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; } } }
Этот фрагмент кода успешно позволяет повторно использовать существующий экземпляр браузера, избегая при этом создания дубликата браузера. Найдено в блоге Tarun Lalwani .
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/')
Все решения до сих пор были лишены определенной функциональности. Вот мое решение:
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()); } }
Решение Javascript:
Я успешно подключился к существующей сессии браузера, используя эту функцию
webdriver.WebDriver.attachToSession(executor, session_id);
Документацию можно найтиздесь .
Это довольно просто, используя JavaScript
selenium-webdriver
Клиент:Во-первых, убедитесь, что у вас работает сервер WebDriver. Например, загрузите ChromeDriver , затем запустите
chromedriver --port=9515
.Во-вторых, создайте драйвер следующим образом :
var driver = new webdriver.Builder() .withCapabilities(webdriver.Capabilities.chrome()) .usingServer('http://localhost:9515') // <- this .build();
Вот полный пример:
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();
Я получил решение в python, я модифицировал класс webdriver, основанный на классе PersistenBrowser, который я нашел.
Https://github.com/axelPalmerin/personal/commit/fabddb38a39f378aa113b0cb8d33391d5f91dca5
Заменить модуль webdriver /usr/local/lib/python2.7/dist-packages/selenium/webdriver/remote/webdriver.py
Ej. для использования:
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
Я использую Rails + Cucumber + Selenium Webdriver + PhantomJS, и я использую исправленную версию Selenium Webdriver, которая держит браузер PhantomJS открытым между тестовыми запусками. Смотрите этот пост в блоге: http://blog.sharetribe.com/2014/04/07/faster-cucumber-startup-keep-phantomjs-browser-open-between-tests/
Смотрите также мой ответ на этот пост: Как выполнить команду на уже открытом браузере из файла ruby
Похоже, что эта функция официально не поддерживается selenium. Но Тарун Лалвани создал рабочий Java-код, чтобы обеспечить эту функцию. См. - http://tarunlalwani.com/post/reusing-existing-browser-session-selenium-java/
Вот рабочий пример кода, скопированный из приведенной выше ссылки:
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"); }
Ваш тест должен иметь RemoteWebDriver, созданный из существующего сеанса браузера. Чтобы создать этот драйвер, вам нужно только знать "информацию о сеансе", то есть адрес сервера (в нашем случае локального), на котором запущен браузер, и идентификатора сеанса браузера. Чтобы получить эти сведения, мы можем создать один сеанс браузера с selenium, открыть нужную страницу, а затем, наконец, запустить фактический тестовый сценарий.
Я не знаю, есть ли способ получить информацию о сеансе для сеанса, который не был создан selenium.
Вот пример информации о сеансе:
Адрес удаленного сервера: http://localhost:24266 . Номер порта отличается для каждого из них сессия. Идентификатор сеанса: 534c7b561aacdd6dc319f60fed27d9d6.
Вдохновленный ответом Эрика, вот мое решение этой проблемы для selenium 3.7.0. По сравнению с решением в http://tarunlalwani.com/post/reusing-existing-browser-session-selenium / , преимущество заключается в том, что при каждом подключении к существующей сессии не будет пустого окна браузера.
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']
Чтобы использовать его:
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))