
Информации по автоматизации тестирования через браузер в русскоязычном сегменте интернета не так много как хотелось бы, поэтому я решил внести свою небольшую лепту, благо как раз понадобилось решить практическую задачу на эту тему. В этой небольшой статье мы рассмотрим простую задачу — как сделать полный скриншот вебстраницы, предварительно выполнив с ней некоторые действия, например, раскрыв свернутые блоки.
Из инструментария нам понадобится:
1. SeleniumHQ сервер — основной инструмент для автоматизации браузера. SeleniumHQ позволяет управлять любым существующим браузером – IE, Opera, Chrome, Firefox, Safari и даже PhantomJS. Как правило, управление происходит через драйвер браузера, но в случае с Safari версии 10 и выше (OS X El Capitan и macOS Sierra) драйвер уже встроен в браузер (Safari) и его нужно просто активировать. Поэтому я начал изучение используя Safari, но если у вас другой браузер, то это тоже не проблема. На странице загрузки SeleniumHQ вам нужно будет скачать Selenium Standalone Server (версия 3.13.0) на момент написания этого материала, и на этой же странице только ниже — драйвер браузера. Еще раз напомню — если вы используете Mac OS X и Safari 10+ не качайте никакой драйвер, он на этой странице есть, но только для старых версий Safari и объявлен как DEPRECATED. Здесь же, от разработчиков Selenium можно скачать библиотеки, чтобы подружить Selenuim с Java, C#, Ruby, Python, Javascript (Node). Но так как я работаю с PHP, мне нужна другая библиотека – Facebook WebDriver.
2. Facebook WebDriver. В принципе, Селениумом можно управлять по http, отправляя команды из другого браузера по порту 4444. Но это не так технологично как хотелось бы. Поэтому есть такие мощные библиотеки как Facebook WebDriver (от разработчиков Facebook, как не сложно догадаться) для интеграции с PHP, и множество других библиотек, для интеграции с другими языками программирования. Facebook WebDriver позволяет создавать PHP скрипты, проводящие посредством Selenium ряд сложных манипуляций с веб-страницей, и так как PHP это полноценнный язык программирования, вы можете сделать свою браузерную автоматизацию частью другого, более серьезного проекта. Проект Facebook WebDriver есть на GitHub, но мы не будем качать его с GitHub, а пойдем более цивилизованным путем, и установим его с Packagist через Composer.
Уже скачали SeleniumHQ сервер? SeleniumHQ сервер это java-приложение, поэтому чтобы он запустился вам нужна Java (установите при необходимости). Скачанный файл будет называться типа “selenium-server-standalone-3.13.0.jar”. Он не требует установки, этот файл это и есть сама программа. Чтобы запустить SeleniumHQ сервер выполните команду:
java -jar /Applications/Selenium/selenium-server-standalone-3.13.0.jar
Путь, конечно же, может отличаться, в зависимости от того в какой папке у вас будет размещаться selenium-server-standalone-3.13.0.jar.
Сервер запустится, но не в фоновом режиме, а как обычное приложение, соответственно командная строка в текущей сессии будет недоступна. Откройте другое окно Термнала, если нужна будет командная строка. Завершить работу программы можно как обычно по Ctrl+C. Проверить что SeleniumHQ сервер работает можно либо проверив 4444 порт (по умолчанию его занимает Selenium), либо пройдя по адресу http://localhost:4444.
Если вы пользуетесь Safari 10+, то достаточно выбрать в меню Develop > Allow Remote Automation. Также проверьте наличие драйвера, путь к исполняемому файлу “/usr/bin/safaridriver”. Если у вас другой браузер — скачайте и установите соответствующий драйвер.
Теперь нужно заполучить Facebook WebDriver. Для этого выполните в папке будущего проекта команду:
composer require facebook/webdriver
да, у вас должен быть установлен Composer.
Можно проверить, работает ли наша конфигурация, набрав какой-нибудь простой код:
//указываем используемое пространство имен: namespace Facebook\WebDriver; //указываем какие классы будем использовать: use Facebook\WebDriver\Remote\DesiredCapabilities; use Facebook\WebDriver\Remote\RemoteWebDriver; //подключаем autoloader, сгенерированный для нас composer’ом require_once('vendor/autoload.php'); //в нашем случае Selenium запущен на localhost, но вообще говоря он может работать где угодно: $host = 'http://localhost:4444/wd/hub'; //создаем объект управления браузером, в данном случае - safari $driver = RemoteWebDriver::create($host, DesiredCapabilities::safari()); //даем команду открыть URL $driver->navigate()->to('https://google.com'); //еще можно так: //$driver->get('https://google.com'); //даем время ограниченное 5сек и интервал проверки 1000мс пока не появится title страницы, //это позволяет дождаться загрузки и не начинать работать со страницей пока она полностью не загрузилась //конечно же, проверять лучше не на title, а на что-нибудь в конце страницы $driver->wait(5, 1000)->until( WebDriverExpectedCondition::titleContains('Google') ); //неправильный способ использования метода wait(). //так работать не будет. Правильный способ - выше. $driver->wait(5); //поэтому если нужно поставить задержку, то лучше сделать это стандартной ф-ей php. sleep(5); //выждав 5 сек закрываем окно браузера (и текущую сессию). $driver->close();
В принципе, ничего сложного. Единственное, из-за чего работа с Facebook WebDriver может показаться сложной, это обилие доступных к использованию классов и методов, в таком ассортименте, что не знаешь куда смотреть. Благо, есть документация. Но самым лучшим путем к изучению будет поставить перед собой реальную задачу и решать ее, параллельно подбирая нужные методы и находя возможности. Так, для примера рассмотрим более сложную задачу. Мне понадобилось сделать скриншот веб-страницы, предварительно развернув на ней скрытые блоки текста:
Чтобы блок текста раскрылся, нужно щелкнуть по нему мышкой. Это мы и будем эмулировать с помощью WebDriver и Selenium.
namespace Facebook\WebDriver; use Facebook\WebDriver\Remote\DesiredCapabilities; use Facebook\WebDriver\Remote\RemoteWebDriver; require_once('vendor/autoload.php'); $host = 'http://localhost:4444/wd/hub'; $driver = RemoteWebDriver::create($host, DesiredCapabilities::safari()); //мне нужно сделать скриншот этой страницы $driver->navigate()->to('https://php-academy.kiev.ua/php-developer'); //дадим скрипту время, пока заголовок не будет содержать фразу “Курс программирования”, //при чем именно содержать, так как titleContains проверяет на нестрогое совпадение $driver->wait(5, 1000)->until( WebDriverExpectedCondition::titleContains('Курс программирования:') ); sleep(1); //интересующий нас элемент мы находим по xpath, так как в данном случае других уникальных свойств у него нет, //но в общем искать можно по имени класса, по css селектору, id, name, link text, tag name… //когда элемент найден мы используем метод sendKeys('abc') для него, а потом делаем клик методом click(). //метод sendKeys() используется когда нужно ввести текст (буквы) в текстовое поле. но в данном случае мы его //используем чтобы навести фокус на нужный нам элемент, тогда гарантированно сработает click(). //если пытаться сразу сделать click() на найденном элементе, почему-то это срабатывает на одних элементах, но не срабатывает //на соседних точно таких же. $driver->findElement(WebDriverBy::xpath('//*[@id="panel1"]/div/div[3]/div/div[2]/a'))->sendKeys('abc')->click(); sleep(1); $driver->findElement(WebDriverBy::xpath('//*[@id="panel1"]/div/div[4]/div/div[2]/a'))->sendKeys('abc')->click(); sleep(1); $driver->findElement(WebDriverBy::xpath('//*[@id="panel1"]/div/div[5]/div/div[2]/a'))->sendKeys('abc')->click(); sleep(1); $driver->findElement(WebDriverBy::xpath('//*[@id="panel1"]/div/div[6]/div/div[2]/a'))->sendKeys('abc')->click(); sleep(1); //используя sendKeys() опять не по назначению, наводим фокус //на верхний элемент страницы, чтобы таким образом //заставить страницу прокрутиться в начало; $driver->findElement( WebDriverBy::xpath('/html/body/div[1]/div/div/div[1]/div/span[2]/a[3]')) ->sendKeys('abc'); sleep(1); //сохраняем скрин страницы в файл PNG. //PNG это стандартный формат для метода takeScreenshot, //с другими форматами он, кажется, и не умеет работать. $driver->takeScreenshot('scr.png'); sleep(1);
Пример мы рассмотрели далеко не самый сложный, но и здесь мне пришлось поэкспериментировать, пока я не пришел к выводу, что перед использованием click() надо сделать sendKeys(). Также обратите внимание, если findElement() не находит элемента по условию поиска, она генерирует исключение, поэтому очень желательно помещать findElement() в блок try-catch. В следующей статье рассмотрим задачу посерьезнее.
Ссылки для начала работы с Selenium:
Оставить комментарий
Для отправки комментария вам необходимо авторизоваться.