stanislav-belichenko
@stanislav-belichenko
Backend PHP Developer

Selenium: Как узнать, не открыто ли уже окно браузера в конкретном профиле кем-то другим?

Имеем:

Код, работающий с библиотекой facebook-php-webdriver. Работаем в много потоков, потоки друг о друге кое-что знают, но пока что предполагаем, что они не знают ничего.
Виртуальные машины, на которых запущен Selenium (на Java, последняя версия) + chrome-webdriver (нужная для текущей версии браузера версия) и на которые наш код ходит с запросами посетить те или иные страницы и сделать там те или иные действия.
Профили для браузера Google Chrome, настроенные для тех или иных специфичных задач.

Ситуация:

Есть вариант, что на одну виртуальную машину в один и тот же браузер в один и тот же профиль (это важно!) придет сначала один экземпляр нашего кода с тем или иным запросом. И он там что-то попытается сделать. В этот момент может произойти две вещи: либо произошла некая ошибка работы браузера (или чего угодно еще), либо просто наш браузер просто еще не выполнил некую задачу, которую мы ему поставили.

И так или иначе мы получаем одну и ту же ситуацию - у нас есть уже открытый профиль браузера, с открытым в нем неким окном, а в нем некоей страницей. И тут к нам приходит второй экземпляр кода, который хочет в том же профиле открыть некую страницу и что-то там сделать.

Проблема:

При описанной ситуации, webdriver не понимает, что делать, и ведет себя деструктивно, а именно открывает три раза пустую вкладку, после чего наш php-экземпляр кода сыпется с ошибкой, что не удалось запустить сессию и все такое. В итоге, как только у нас случается такая ситуация, работа с профилем просто замораживается, до вмешательства живого человека.

Уточнение:

Нам не нужно пробовать решить описанную проблему php-кодом. Понятно, что можно сделать балансировщик, который будет ограничивать работу с профилями на уровне запуска экземпляров кода, выдавая право на тот или иной "по-одному", но пока что интересны только нативные решения.

Что ищется:

Вариант, когда можно указать Selenium'у (webdriver'у?), что нужно подвешивать очередной запрос к профилю браузера для того, чтобы он успел его обработать, и только тогда посылать очередной запрос в дело.

Получить список активных профилей / сессий, чтобы потом их как-то обработать. Сейчас мы можем получить сессию (sessionId) только после того, как у нас прошел момент создания вебдрайвера, а он не создается как раз в том случае, если в профиле уже открыто то или иное окно.

Пример кода:

который итоге не умеет работать дважды (если его запустят дважды разные процессы):

$caps           = DesiredCapabilities::chrome();
$chrome_options = new ChromeOptions();

$chrome_options->addArguments([
        "--user-data-dir=$user_data_dir",
        "--profile-directory=$profile",
]);

$caps->setCapability(ChromeOptions::CAPABILITY, $chrome_options);

// Вот здесь, если у нас уже как и написано выше в $caps установлено 
// использование определенного профиля браузера, мы не сможем еще раз 
// подключиться к нему, все это вызовет описанное выше поведение
// браузера и вебдрайвера

$this->webdriver = RemoteWebDriver::create(
    $service_url,
    $caps,
    $connection_timeout * 1000,
    $request_timeout * 1000
);

return $this->webdriver->getSessionID();


PS: да, я знаю, что подобный функционал уже когда-то запрашивался в seleniumhq и был отклонен. Но, возможно, есть какие-то обходные пути решить эту проблему. Заодно, если кому-то не слишком понятен вопрос и есть желание углубиться, по ссылке можно найти недостающую информацию.
  • Вопрос задан
  • 498 просмотров
Решения вопроса 1
stanislav-belichenko
@stanislav-belichenko Автор вопроса
Backend PHP Developer
По факту, никак. Решилось все балансировкой запросов, когда мы не посылаем новый запрос, пока не уверены (почти, за счет избыточного таймаута), что предыдущий не отработал и окно не закрылось, как и процесс не завершился.

При этом тут стоит понимать, что если мы посылаем к Селениуму запрос например для перехода на некий url (webdriver->get(url)), то Селениум ждет, когда это реально случится, и потом только нам возвращается управление (конечно, можно и асинхронно это попытаться сделать, но php-либа от ФБ это делает именно так). А вот когда мы посылаем запрос драйверу на закрытие (не помню как точно уже звучит, типа close() или quit(), наверное), то никакого ожидания мы не получаем, запрос улетает к вебдрайверу, и тот посылает запрос на закрытие браузеру, и соответственно при большой нагрузке на машину у нас этот запрос уже якобы отработал, но в реальности еще только закрывается окно браузера, а потом и тушатся его процесс(ы). И этот временной лаг может достигать десятков секунд.
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы