Parsing / Сбор информации, Анализ данных

Автоматизация работы с браузером с помощью Selenium

Время прочтения: 4 мин.

Для задач по анализу данных необходимо большое количество информации, которая может быть недоступна или отсутствовать на внутренних ресурсах организации, и для их решения необходимо обратиться к другим источникам, например, внешним ресурсам данных. Как правило, внешние ресурсы не предоставляют возможностей для выгрузки информации одним списком, и для получения данных необходимо выполнить некоторое количество действий на сайте – заполнить форму, нажать кнопку, выбрать категорию, подкатегорию и т.д.

Такой способ не подходит для обработки больших массивов данных, например, получение данных об организациях по списку ИНН. Чтобы ускорить (процесс выгрузки) мы можем применить библиотеку Selenium — инструмент для автоматизации тестирования веб-приложений.

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

Библиотека поддерживает работу с различными браузерами: Firefox, Safari, Chrome, Edge, IE.

Для того чтобы библиотека могла взаимодействовать с браузером необходимо иметь на компьютере драйвер, соответствующий версии браузера.

Подробнее остановимся на основных возможностях библиотеки при работе с браузером Chrome.

При запуске экземпляра браузера есть возможность задать аргументы командной строки с помощью метода AddArgument() класса ChromeOptions, например отключить графический интерфейс или задать параметры для HttpRequest:

var opt = new ChromeOptions();
opt.AddArgument("--no-sandbox");
       opt.AddArgument("--disable-gpu");
       opt.AddArgument("--headless");
       opt.AddArgument("--disable-automation");
var walker = new ChromeDriver(path, opt);

Загрузка страницы и навигация осуществляются через интерфейс INavigation.

С помощью метода GoToUrl(string url) осуществляется переход на страницу, метод Back() возвращает предыдущую страницу браузера, а метод Forward() – следующую.

После того как будет осуществлен переход на страницу, с помощью объекта драйвера можно  вернуть html-код страницы через свойство PageSource, вернуть адрес страницы через свойство Url или найти элемент на странице.

Для поиска элемента на странице у класса ChromeDriver есть несколько специализированных методов, напимер, FindElementByClassName(string class) ищет на странице элемент с заданным классом.

Также можно воспользоваться общими методами FindElement(By by) и FindElements(By by).

Параметр этих методов – класс By предоставляет свои методы, определяющие по каким признакам будет производиться поиск элемента, например:

var paragraph = walker.FindElement(By.TagName(“h”));

вернет первый элемент <h> на странице,

var paragraphs = walker.FindElements(By.TagName(“h”));

вернет все элементы <h> в списке.

В некоторых случаях на странице может быть не обнаружен элемент, хотя при визуальном просмотре страницы он есть. Это означает что элемент был добавлен на страницу при помощи js-скрипта, который не успел отработать до того, как был вызван метод поиска элемента.

Чтобы избежать подобных случаев можно воспользоваться двумя способами:

  1. Установить свойство драйвера ImplicitWait, время, в течении которого драйвер будет бездействовать после перехода на страницу:
walker.Manage().timeouts().ImplicitWait = TimeSpan.FromSeconds(5);
  1. Использовать класс WebDriverWait. Класс позволяет с указанной периодичностью проверять страницу пока указанный элемент не будет найден:
var element = new WebDriverWait(walker, TimeSpan.FromSeconds(5)).until(x => x.FindElement(By.Id(“someID”))));

Для взаимодействия с элементом используются методы интерфейса IWebElement.

Нажатие на кнопку имитирует метод Click(), ввод пользователя – метод SendKeys()

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

var loginElem = new WebDriverWait(driver, 10).Until(
    x => x.FindElement(By.Id(“username”)));
var pwdElem = new WebDriverWait(driver, 10).Until(
    x => x.FindElement(By.Id(“password”)));
var submitElem = new WebDriverWait(driver, 10).Until(
    x => x.FindElement(By.Id(“submit”)));
loginElem.SendKeys(user);
pwdElem.SendKeys(pwd);
submitElem.Click();

C помощью класса Actions можно задавать и выполнять цепочки действий. В конструктор передается экземпляр драйвера, методы задают действия которые необходимо выполнить и затем запускается выполнение цепочки методом Perform():

New Actions(walker).SendKeys(loginElem, “username”).SendKeys(pwdElem, “password”).Click(submitElem).Perform();

Мы использовали эту библиотеку для получения информации о дате регистрации ОГРН для списка ИНН организации, ниже приведен код нашего решения:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;

using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;

namespace MyApp
{
    class Program
    {
        public static Dictionary<string, string> GetDateFromEGRUL(List<string> inns)
        {
            var path = "path/to/cromedriver";
            var url = "https://EGRUL.url";
            var innDates = new Dictionary<string, string>();
            foreach (var inn in inns)
            {
                var opt = new ChromeOptions();
                opt.AddArgument("--no-sandbox");
                opt.AddArgument("--disable-gpu");
                opt.AddArgument("--headless");
                opt.AddArgument("--disable-automation");
                var walker = new ChromeDriver(path, opt);

                walker.Navigate().GoToUrl(url);

                var innInput = new WebDriverWait(walker, TimeSpan.FromSeconds(5))
.Until(x => x.FindElement(By.Id("query")));
                var findBtn = new WebDriverWait(walker, TimeSpan.FromSeconds(5))
.Until(x => x.FindElement(By.Id("btnSearch")));

                new Actions(walker)
.SendKeys(innInput, inn)
.Click(findBtn)
.Perform();

                var date = walker
.FindElement(By.XPath("/html/body/div[1]/div[3]/div/div[1]/div[4]/div/div[3]/div"))
.Text
.Split("ОГРНИП: ")
.ToList()
.Last();
                innDates.Add(inn, date);
            }

            return innDates;
        }
        static void Main(string[] args)
        {
            List<string> data = LoadInnFromFile("path/to/inn/file.csv");
            SaveDatesToFile(GetDateFromEGRUL(data));
        }
    }
}

Преимущество библиотеки Selenium – в возможности полностью повторить и автоматизировать действия пользователя на любом сайте, недостаток – довольно медленная работа библиотеки, связанная с тем что при переходе на страницу необходимо дожидаться ее полной загрузки.

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

Советуем почитать