Selenium C/C++, Webdriver на плюсах - возможно
Автоматизированные веб тесты на C++ - так, конечно, мало кто делает. Наиболее подходящий для этой задачи язык - это, конечно, Java. Однако, бывают такие случаи когда все же необходимо реализовать подобный функционал на плюсах. Скорее всего, подобные задачи никак не относятся к тестированию и скорее всего это задачи парсинга сайтов и майнинг информации. Но даже в этом случае, лучше всего подойдет Java.
Возможность реализовать эту задачу на C++ есть, с помощью JsonWireProtocol, который предоставляет нам selenium-server.
Все реализации WebDriver, которые взаимодействуют с браузером или удаленным сервером WebDriver, используют
common wire protocol. Этот протокол определяет RESTful веб сервисы, с использованием JSON поверх HTTP.
Протокол допускает что WebDriver API может быть размазано (то есть отличаться в разных версиях WebDriver),
но ожидает, что реализация на стороне WebDriver имеет хороший ООП подход, как демонстрируется в Java API.
Wire протокол реализует пару запрос-ответ для взаимодействия с WebDriver.
В общем-то все понятно. Необходимо реализовать запрос-ответ JSON объектов, поверх HTTP. Это все просто реализуется с помощью того же CURL. Однако, набор команда для работы с браузерами не такой маленький и поэтому это немного накладно будет по времени реализовывать это все с нуля.
Поэтому давайте воспользуемся готовой библиотекой, которую я поддерживаю - Webdriver++. Решая подобную задачу я на гитхабе нашел один репозиторий, последний коммит в котором был 3 года назад, но большинство функций в этом проекте уже было реализовано. Я немного доработал этот проект, исправил пару багов и сделал его как Shared Library. Теперь есть возможность использовать Webdriver++ в любом вашем C++ проекте.
Как использовать
- Скачать selenium-server с сайта Selenium.
- Клонировать проект Webdriver++ себе на компьютер
- Собрать проект
mkdir build cd build && cmake .. make && sudo make install
- Запустить selenium-server
java -jar selenium-server-standalone-3.5.0.jar
- Создать свой проект на C++ и можете использовать этот пример:
Советы по оптимизации быстродействия
- Не запускайте каждый раз новую сессию WebDriver, при обращении к новым URL, если в этом нет особой необходимости. Запускайте только одну сессию WebDriver в одном потоке и используйте ее для всех задач. Таким образом сократиться очень много времени на инициализацию сессии WebDriver.
- Поймать исключение можное с помощью
webdriverexception
, и если такое случилось, то освободите все ресурсы, удалите сессии WebDriver, запустите новую. - Используйте HtmlUnit. Я провел эксперименты, использовал Firefox WebDriver, Chrome WebDriver, PhantomJS, HtmlUnit. Наиболее быстрым и менее глючным для моих задач оказался HtmlUnit. Конечно, Chrome WebDriver так же показал хорошие результаты по стабильной работе, но все же Chrome потребляет больше ресурсов и мне так и не удалось запустить его без GUI (пытался использовать параметры –headless, не помогло).
Альтернативные решения
Я использую WebDriver для майнинга данных, в коммерческом проекте и поэтому вопрос производительности и работы с памятью стоит очень критично. Грубо говоря, чем быстрее я обработаю/смайню данные, тем больше будет профит. Поэтому вариант c selenium мне не особо нравится, потому что этот процесс занимает ресурсы, особенно оперативную память. В идеале было бы работать с браузером на прямую, но пока такого варианта нет.
Поэтому я собираюсь провести еще ряд экспериментов по этому вопросы и возможно сделаю новый open source проект по работе с WebDriver на C++, однако, от работы через Java никуда не деться.
Какие есть вараинты
- Реализовать полностью все на Java. Такой вариант подойдет, если у вас, кроме использования WebDriver никаких других функций в софте не предусмотрено.
- Вызывать напрямую методы из Java библиотеки, с помощью JNI. Ну то есть генерировать, с помощью javah header файл и далее вызывать методы Java, напрямую из C++. Кажется это более чем разумный вариант.
- Реализовать небольшую Java программу и передавать в нее команды из C++, по сути аналог selenium-server, но уже более оптимизированный и без лишних наворотов. Общение между приложениям возможно реализовать как через сокеты, так и воспользоваться менее болезненным способом и взять ZeroMQ для решения задачи коммуникаций между приложениями.
- Инвертировать проблему, то есть вызывать C++ методы из Java. Если у вас есть функционал, который работает только на C++, вы можете создать библиотеку и с помощью механизма JNI вызывать необходимые методы библиотеки.
В моем приложении есть множество функций, который необходимо выполнять именно на C++, поскольку быстродействие конечной программы и контроль над
ресурсами, лучше чем на других языках. Доходит даже до отказа от типов данных double
, long
и прочих, потому что они
громоздкие и не нужны в некоторых областях проекта. То есть все, вплоть до типов данных, максимально оптимизировать
приходится, чтобы сэкономить ресурсы.
Поэтому я пожалуй реализую свой велосипед и сделаю второй вариант C++ <-> JNI <-> Java
, чтобы выжать из этого максимум.
Тогда это будет быстрее, с точки зрения написания кода. Осталось провести эксперименты.
Удачи мне.