Чи може Selenium взаємодіяти з існуючим сеансом браузера?


104

Хтось знає, чи може Selenium (бажано WebDriver) спілкуватися та діяти через браузер, який вже запущений до запуску клієнта Selenium?

Я маю на увазі, якщо Selenium зможе спілкуватися з браузером, не використовуючи Selenium Server (наприклад, Internet Explorer може бути запущений вручну).

Відповіді:


35

Це досить старий запит на функцію: Дозволити webdriver підключатися до запущеного браузера . Тож це офіційно не підтримується.

Однак існує деякий робочий код, який стверджує, що це підтримує: https://web.archive.org/web/20171214043703/http://tarunlalwani.com/post/reusing-existing-browser-session-selenium-java/ .


Щиро дякую, бо в цьому посиланні я знайшов клас, який дозволяє це робити, але, на жаль, я не можу використовувати це рішення з IE (лише з Firefox). Я збираюся запустити звичайний IEDriver і спілкуватися з ним з інших процесів за допомогою проміжного програмного забезпечення. Якщо ви маєте уявлення, чому клас не працює над IE, я був би вдячний. Дякую.
Angel Romero

Роберт, зараз 2018 рік. Не могли б ви оновити свою відповідь?
MasterJoe

На випадок, якщо комусь він потрібен, я спробував і протестував якийсь Java-код, щоб селен використовував існуючий сеанс браузера - stackoverflow.com/a/51145789/6648326 .
MasterJoe

56

Це дубльована відповідь ** Повторне підключення до драйвера в python selenium ** Це стосується всіх драйверів та Java api.

  1. відкрити драйвер
driver = webdriver.Firefox()  #python
  1. витяг до 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'
  1. Використовуйте ці два параметри для підключення до драйвера.
driver = webdriver.Remote(command_executor=url,desired_capabilities={})
driver.close()   # this prevents the dummy browser
driver.session_id = session_id

І ви знову підключені до драйвера.

driver.get("http://www.mrsmart.in")

2
Це саме те, що я шукав. Дякую.
milso

6
Це працює для мене, за винятком того, що дублікат фіктивного браузера піднімається кожного разу.
Павло Власов

Я також отримую фіктивне вікно, це не така вже велика справа, але під час налагодження це дратує. Будь-які ідеї, як позбутися?
Стів Гон,

1
+1. Працює з моєю метою, щоб уникнути 2-факторного входу в систему, проте є дублікати фіктивних браузерів. Я можу жити з цим.
Сем

1
selenium.common.exceptions.SessionNotCreatedException: Message: Session is already started
Черін,

23

Цей фрагмент успішно дозволяє повторно використовувати наявний екземпляр браузера, уникаючи збільшення дублікатів браузера. Знайдено в блозі Таруна Лалвані .

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/')

2
Чи є спосіб знайти існуючий ідентифікатор сеансу та URL-адресу виконавця за допомогою автоматизації? У моєму випадку інша програма відкрила сеанс браузера, і я хочу цим скористатися. Чи можете ви, будь ласка, порекомендувати, як знайти ідентифікатор сеансу браузера цього?
Sun Shine

Можливо, ви можете скинути url & id сеансу executor_command у файл під час запуску сценарію та прочитати його з файлу, коли ви хочете знову підключити сеанс браузера.
SK Venkat

@SKVenkat, як я можу отримати ідентифікатор сеансу chrome window, я відкрив його за допомогою pywinauto і тепер хочу запустити на ньому selenuim, чи є спосіб python отримати ідентифікатор сеансу на вкладці chrome
Tayyab Nasir,

@TayyabNasir, будь ласка, зверніть увагу на наведену вище відповідь. П’ятий рядок, який було прокоментовано, # session_id = driver.session_id- це спосіб отримання ідентифікатора сеансу хромованого вікна за допомогою python selenium api. Я думаю, що кожна вкладка в сеансі chrome не має унікального ідентифікатора.
SK Venkat

3
@SK Я хочу ідентифікатор сеансу хромованого вікна, яке я відкрив вручну, я не відкривав це вікно за допомогою селену
Tayyab Nasir

12

Можливо. Але вам потрібно це трохи зламати, є код. Що вам потрібно зробити, це запустити автономний сервер і "виправити" 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;
        }
    }
}

4
На основі цього чудового рішення я написав повний допис у блозі, де обговорив, як підключитися до вже відкритого екземпляра браузера chrome. Повний вихідний код також додається до цього повідомлення в блозі. binaryclips.com/2015/08/25/…
joinsaad

4

Схоже, що ця функція офіційно не підтримується селеном. Але Тарун Лалвані створив діючий код 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, створений із існуючого сеансу браузера. Щоб створити цей драйвер, вам потрібно знати лише "інформацію про сеанс", тобто адресу сервера (локальний у нашому випадку), де працює браузер, та ідентифікатор сеансу браузера. Щоб отримати ці деталі, ми можемо створити один сеанс браузера з селеном, відкрити потрібну сторінку, а потім, нарешті, запустити власне тестовий скрипт.

Я не знаю, чи є спосіб отримати інформацію про сеанс для сеансу, який не був створений селеном.

Ось приклад інформації про сеанс:

Адреса віддаленого сервера: http: // localhost: 24266 . Номер порту різний для кожного сеансу. Ідентифікатор сесії: 534c7b561aacdd6dc319f60fed27d9d6.


"Я не знаю, чи є спосіб отримати інформацію про сеанс для сеансу, який не був створений селеном." це насправді проблема, яку я намагався вже пару днів ... поки що успіху немає
slesh

@slesh - Я пропоную вам створити для цього нове запитання і, можливо, запропонувати 100 своїх балів, якщо це не привертає достатньої уваги.
MasterJoe

Дякую за посилання на роботу Таруна Лалвані. Між його сторінкою та вашою відповіддю я зміг це зрозуміти. Імпорт був би непоганий, як і коментарі, що пояснюють мету деяких заяв. Але все і все, дуже корисно.
Тіхамер

4

Натхненний відповіддю Еріка, ось моє рішення цієї проблеми для селену 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))

3

У всіх рішеннях на сьогодні відсутні певні функціональні можливості. Ось моє рішення:

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());
    }
}

Яку функціональність це додає (а інші відсутні)?
jalanb

1
Внутрішньо лише метод startSession (...) ініціалізує об’єкт можливостей. Об'єкт можливостей необхідний для багатьох методів, таких як takeScreenshot, executeScript та багато іншого. Але пройшовши startSession, вам доведеться створити нове створення сеансу. Це перевантаження пропускає створення нового сеансу, але все одно призводить до ініціалізації об’єкта можливостей.
Янір

чувак, не порівнюй рядки з ==
Norill Tempest

3

Рішення Javascript:

Я успішно підключився до існуючого сеансу браузера за допомогою цієї функції

webdriver.WebDriver.attachToSession(executor, session_id);

Документацію можна знайти тут .


3
Цього немає у версії 4.0.0!
googamanga

1

Я отримав рішення в 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

0

Я використовую Rails + Cucumber + Selenium Webdriver + PhantomJS, і я використовую виправлену мавпою версію Selenium Webdriver, яка тримає браузер PhantomJS відкритим між тестовими запусками. Дивіться це повідомлення в блозі: http://blog.sharetribe.com/2014/04/07/faster-cucumber-startup-keep-phantomjs-browser-open-between-tests/

Дивіться також мою відповідь на цю публікацію: Як мені виконати команду на вже відкритому браузері з рубінового файлу


-1

За допомогою selenium-webdriverклієнта JavaScript це досить просто :

Спочатку переконайтеся, що у вас запущений сервер 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();

4
Він не використовує ІСНУЮЧИЙ сеанс браузера. Він створює новий сеанс chromedriver і відкриває нове вікно браузера. І getAllWindowHandles () не відображатиме дескриптор вашого старого вікна браузера.
Дзенлі

Оновлення: є seleniumhq.github.io/selenium/docs/api/javascript/module/… Що дозволяє підключатися до існуючого відкритого вікна браузера.
Dzenly
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.