Си шарп и селениум

Scraping HTML with Selenium and C#

In this post, we’ll be going over how we can use Selenium WebDriver and C# to scrape HTML from websites. I recently started working on a personal project that I plan to use for gathering English Premier League player statistics for my fantasy team. I had a fun time getting Selenium set up and working so I thought I’d share.

Aaron Bos | Wednesday, July 28, 2021

What is Selenium WebDriver?

Let’s start by discussing Selenium WebDriver at a high level. Selenium is a suite of browser automation tools and Selenium WebDriver specifically, is one of the tools that can be used to automate browser interactions. In the context of this post, we’ll be talking about using Selenium WebDriver to scrape HTML from web pages, but it is also commonly used for browser-based testing.

Selenium WebDriver communicates directly to the web browser via a «driver». This driver enables two-way communication between the browser and driver. So the driver is able to issue commands to the web browser and the browser is able to respond back to the driver. Drivers are browser-specific, for example, the Firefox driver (also known as GeckoDriver) will communicate with Mozilla Firefox, and the ChromeDriver will communicate with Google Chrome. This two-way communication allows Selenium to expose an API for performing actions in the browser like selecting and clicking on elements.

Читайте также:  Java applets sign in

If you would like to learn some more about Selenium WebDriver, head over to their documentation. I found the docs to be very thorough and helpful as I was working through this for the first time. Now that we have a basic understanding of Selenium WebDriver, let’s get into the details of setting up our environment.

Getting Started

First, you’ll need to download the driver for the browser you’d like to use. Personally, I would choose your daily browser, but you can choose any driver for a browser that you have installed on the machine that the driver will be running on. A list of browser drivers with download links can be found here. There is also an option to communicate with the driver and browser remotely (on a different machine) with the Selenium Server or Grid tools, but for the purpose of this post we’ll be running the driver and browser on our own machine.

Once you have the driver executable downloaded, you’ll need to add its location to your PATH variable. For example, I placed the GeckoDriver executable in this location on my Mac /opt/WebDriver/bin and added it to my PATH variable with the following command.

# I would recomended adding this to your .bash_profile or .zshrc so that the command gets ran in each new instance of a terminal export PATH=$PATH:/opt/WebDriver/bin 

With the driver installed and added to the PATH we’re ready to jump in and start writing some code!

Setting Up Application and Dependencies

As I mentioned at the beginning of this post, I recently started a side project that uses Selenium WebDriver to gather English Premier League statistics. For this project, I created a .NET 5 Console application. The type of application isn’t too important for this context, that just depends on how you intend to consume or process the information.

Читайте также:  Команда ввода данных python

Once we have a project created we’ll have to install the necessary NuGet packages for Selenium. The first one we need is Selenium.WebDriver, which can be installed with this command.

dotnet add package Selenium.WebDriver --version 4.0.0-beta4 

The next package that we’ll need to add will be specific to the browser driver that was chosen earlier. For example, I chose GeckoDriver (Firefox) so I need to download Selenium.Firefox.WebDriver. A list of Selenium packages can be found here.

dotnet add package Selenium.Firefox.WebDriver --version 0.27.0 

With the main Selenium.WebDriver and driver-specific NuGet Packages added to our project we’re ready to start testing things out. The following code will be executable inside of any application, but we’ll be looking at it from the lens of a Console application.

First, we’ll add the using statements to the file. This will make the necessary Selenium classes available for us to use.

using OpenQA.Selenium; using OpenQA.Selenium.Firefox; 

Next up is creating an instance of FirefoxDriver , which is used to make the web page requests and does most of the heavy lifting. One thing to note is that FirefoxDriver implements IDisposable so it’s recommended to dispose of the driver resources after completing our work with it and we can do this with a using statement. On top of the resource disposal, we’ll also want to call the Quit() method on FirefoxDriver . It’s a good idea to wrap our web scraping code in a try/finally block so that we always call Quit() , even if an exception is thrown. Here is an example.

using (IWebDriver driver = new FirefoxDriver()) < try < // Do some web scraping >finally < driver.Quit(); >> 

With that bit of code in place, we’re ready to start making web requests and using the functionality of Selenium to get specific data from the requested HTML. The first step is to call the Navigate() method followed up with GoToUrl(«https://google.com») . These methods are both pretty self-explanatory. Calling Navigate will return an INavigation implementation that exposes the GoToUrl method, which actually opens an instance of the browser and goes to the URL specified string url parameter. These steps end up looking like the example below.

using (IWebDriver driver = new FirefoxDriver()) < try < driver.Navigate().GoToUrl(@"https://fantasy.premierleague.com/statistics"); >finally < driver.Quit(); >> 

The next step is to actually select the data on the page that we are interested in. There are many methods available for selecting specific pieces of HTML, but I’ll be going through the one that I find to be most versatile. I would highly suggest looking through the Selenium documentation to determine what works best for the situation you’re in. In this example we’ll be finding an HTML element with the use of a CSS selector, just like we would select an element in a .css file. There are helper methods available to get elements by ID and class name, but we’ll just be going with a raw selector. So building on our previous code sample we’ll add in the ability to grab Teams from a dropdown menu.

using (IWebDriver driver = new FirefoxDriver()) < try < driver.Navigate().GoToUrl(@"https://fantasy.premierleague.com/statistics"); // Select an element with id filter followed by an optgroup element with the label attribute value "By Team" // Use the Text property to return the text of each select option var teams = driver.FindElement(By.CssSelector(#filter optgroup[label=\"By Team\"])).Text; Console.WriteLine(teams); >finally < driver.Quit(); >> 

To add a bit more color to this example here are screenshots of both the webpage and dev tools HTML that we selected in the code above.

selenium-team-dropdown.png

This screenshot contains the dropdown options that we are selecting the text from.

selenium-team-dev-tools.png

This is the HTML representing the dropdown above.

Beyond just selecting HTML elements we can actually click on elements via Selenium. The following example selects a collection of HTML button elements with the given CSS selector, iterates through the collection, and calls the .Click() method on each element. In the context of this example a dialog element is then displayed to the user on the web page we requested.

using (IWebDriver driver = new FirefoxDriver()) < try < driver.Navigate().GoToUrl(@"https://fantasy.premierleague.com/statistics"); foreach (var btn in driver.FindElements("div#root div:nth-child(2) table tbody button") < if (btn.Text.Contains("View player information")) < btn.Click(); // Close the modal dialog driver.FindElement( By.CssSelector("div#root-dialog >div[role=\"presentation\"] > dialog > div div:nth-child(1) button") ).Click(); > > > finally < driver.Quit(); >> 

Selenium WebDriver is a powerful tool that can be useful for automated testing, web scraping, and more. ,If you’d like to see a full working example of this code head over to the project that I’m working on and see how all the pieces come together in a full application. I hope this post was helpful in providing a starting point for collecting data from HTML with Selenium WebDriver and C#.

Источник

Автоматизированное тестирование веб-приложения (MS Unit Testing Framework + Selenium WebDriver C#). Часть 1: Введение

image

Итак, первым делом необходимо отобрать некоторое количество тестовых сценариев высокого приоритета, но довольно простых.
Далее создадим в студии новый solution. Вполне логично будет создать в нем 3 проекта: тесты, описание страниц и утилиты. Это и будут наши три базовые сущности.

image

Схема будет довольно простая: тест работает со страницами, запрашивая на них какие-либо данные или выполняя там какие-либо действия. В утилитах мы разместим классы, которые будут отвечать за работу c браузером и web-элементами на страницах посредством Selenium WebDriver. Вполне логично написать обертки (wrapper), поскольку Selenium WebDriver API имеет множество недостатков и может показаться довольно неудобным. Именно в этих обертках мы инкапсулируем (спрячем) весь специфический и некрасивый код. Для примера, создадим классы Browser и WebElement, которые предоставят разработчикам автотестов только тот футкционал, который им нужен. В дальнейшем я хотел бы описать этот процесс в отдельной статье, поэтому не буду останавливаться.

Тесты
  • входные (тестовые) данные
  • предусловие, т.е. некоторое состояние системы, при котором мы сможем выполнить необходимую проверку
  • взаимодействие с web-приложением
  • проверка — сравнение ожидаемого результата с полученным. В MS Unit Testing Framework для этого существует отдельный класс Assert
  • сокращение времени анализа результатов тестов
  • не нужно тратить время на реализацию масштабного логирования (не стоит забывать, что MS Unit Testing Framework умеет собирать всевозможную диагностическую информацию в процессе выполнения теста, например: стэк вызовов, лог событий, IntelliTrace, запись фото и видео, анализ кодового покрытия)
Описание web-страниц тестируемого продукта

Что же будут представлять из себя описания страниц?
Во-первых, это описания элементов, с которыми мы будем работать, т.е. способ распознавания их по id, классу, имени, xpath и др. Не надо описывать сразу все имеющиеся на странице элементы, это нерациональная трата времени. При этом все эти описания должны быть приватными и не выходить за рамки класса страницы.
Во вторых, страница будет содержать свойства (getters) и методы, с помощью которых тесты смогут получить информацию со страницы, например значение какого-нибудь текстового поля.
И в третьих, страница будет содержать методы для совершения действий на самой странице, например клик по кнопке. Важно отметить, что описание страницы не должно содержать никакой логики и никаких проверок! Проверки должны быть в тестах. И в то же время, здесь не должно быть никаких вызовов Selenium WebDriver API.

Утилиты

В данном проекте, как минимум, будут находится обертки над Selenium WebDriver API. В последствии это место станет скоплением всевозможных helper’ов, утилит, расширений и т.д. до их вынесения в отдельные сущности и проекты.

Заключение и пример

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

Далее я покажу один простой пример и на этом закончу статью. Если она окажется интересной, я обязательно напишу продолжение, где опишу детали реализации тестов, страниц и оберток над WebDriver API.

[TestClass] public class LogOnTests : TestsBase < [TestMethod] public void LogOnWithEmptyLogin() < #region TestData const string login = null; const string password = "password"; const string error = "Empty login!"; #endregion Browser.Open(. ); LogOnPage.LogOn(login, password); Assert.AreEqual(error, LogOnPage.Error, "Error expected."); >> public static class LogOnPage < private static readonly WebElement LoginEdit = new WebElement().ById("Login"); private static readonly WebElement PasswordEdit = new WebElement().ById("Password"); private static readonly WebElement LogOnButton = new WebElement().ById("LogOn"); private static readonly WebElement LogOnValidationError = new WebElement().ById("LogOnValidation"); public static void LogOn(string login, string password) < LoginEdit.Text = login; PasswordEdit.Text = password; LogOnButton.Click(); >public static string Error < get < return LogOnValidationError.Text; >> > 

P.S. Вспомнилась старинная русская поговорка: кто рано встает, тот отлаживает тесты.

Источник

Оцените статью