Как использовать .NET C# для парсинга веб-страниц

Как использовать .NET C# для парсинга веб-страниц

7 февраля 2023 г.

Руководство по анализу веб-страниц в .NET C# с примерами кода.

Что такое парсинг веб-страниц

В английском языке слово Scraping имеет разные значения, но все они имеют одно и то же значение.

В Dictionary.com

<цитата>

удалить (внешний слой, налипшие вещества и т.п.) таким способом: соскоблить краску и лак со стола.

В Dictionary.Cambridge.org

<цитата>

снятие поверхности с чего-либо острым краем или чем-то грубым.

Однако нас наверняка интересует, что означает веб-скрейпинг в программном обеспечении.

В программном обеспечении веб-скрейпинг – это процесс извлечения некоторой информации из веб-ресурса из его пользовательского интерфейса, а не из его законных API. Таким образом, это не похоже на вызов REST API веб-сайта для получения некоторых данных, это похоже на извлечение страницы веб-сайта, как это делает браузер, анализирует HTML и затем извлекает данные, отображаемые в HTML.


Зачем нам удалять веб-сайт

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


Законен ли веб-скрейпинг

Это зависит от самого веб-ресурса. На некоторых веб-сайтах это где-то написано, является ли это законным или нет, а иногда это нигде не написано.

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


Как делать парсинг в Интернете

Есть разные способы сделать это, но в большинстве случаев применяется одна и та же концепция; вы пишете код для получения HTML-кода с использованием URL-адреса веб-сайта, анализируете HTML-код и, наконец, извлекаете нужные данные.

Однако, если мы будем придерживаться только этого определения, мы упустим много деталей.

В некоторых случаях все обстоит сложнее. Это зависит от того, как построен веб-сайт.

Для статических веб-сайтов, где данные уже преобразованы в HTML из первого экземпляра, вы можете выполнить те же шаги, которые мы описали.

Однако для динамических веб-сайтов, где данные не отображаются в HTML с первого экземпляра, а загружаются динамически с помощью библиотек и фреймворков JavaScript (например, Angular, React, Vue и т. д.), вам необходимо использовать другой подход.

По сути, в этом случае вы пытаетесь имитировать действия веб-браузера (например, Chrome, Firefox, IE, Edge и т. д.), а затем получаете окончательный HTML-код из виртуального браузера, который вы использовали. Когда у вас будет полный HTML-код, в котором отображаются данные, все остальное будет таким же.


Должны ли мы сделать это сами с нуля

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

Например, вот список некоторых библиотек, которые мы можем использовать.

Выполнение звонков:

  1. .NET HttpClient
  2. RestSharp

Разбор HTML:

  1. Html Agility Pack (HAP)
  2. CSQuery
  3. AngleSharp

Виртуальный браузер:

  1. Безголовый Chrome
  2. Selenium WebDriver
  3. Кукловод Sharp

Это не единственные библиотеки, которым мы должны помочь в нашем проекте Web Scraping. Если поискать в Интернете, можно найти намного больше.


Photo by Markus Spiske on Unsplash

Очистка статического веб-сайта

Для начала попытаемся удалить некоторые данные со статического веб-сайта. В этом примере мы собираемся удалить мой собственный профиль GitHub https://github.com/AhmedTarekHasan< /p>

Мы попытаемся получить список закрепленных репозиториев в моем профиле. Каждая запись будет состоять из имени репозитория и его описания.

Итак, приступим.


Наблюдение за структурой данных в HTML

До момента написания этой статьи мой профиль на GitHub выглядел так.

Image by Ahmed Tarek

Когда я проверил HTML, я обнаружил следующее:

  1. Все мои закрепленные репозитории находятся внутри основного контейнера по следующему пути: div[@class=js-pinned-items-reorder-container] > пр > ли
  2. Каждый закрепленный репозиторий содержится внутри контейнера со следующим относительным путем к родительскому пути: div > раздел
  3. Каждый закрепленный репозиторий будет иметь свое имя внутри div > раздел > диапазон > a и его описание внутри p

Написание кода

Вот шаги, которые я выполнил:

  1. Создано консольное приложение. Решение: WebScraping. Проект: WebScraper.
  2. Установлен пакет NuGet HtmlAgilityPack.
  3. Добавлена ​​директива using using HtmlAgilityPack
  4. Определил метод private static Task<string> GetHtml() для получения HTML.
  5. Определил метод private static List<(string RepositoryName, string Description)> ParseHtmlUsingHtmlAgilityPack(string html) для анализа HTML.
  6. И наконец, код должен выглядеть следующим образом:

using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
using HtmlAgilityPack;

namespace WebScraper
{
    class Program
    {
        static async Task Main(string[] args)
        {
            var html = await GetHtml();
            var data = ParseHtmlUsingHtmlAgilityPack(html);
        }

        private static Task<string> GetHtml()
        {
            var client = new HttpClient();
            return client.GetStringAsync("https://github.com/AhmedTarekHasan");
        }

        private static List<(string RepositoryName, string Description)> ParseHtmlUsingHtmlAgilityPack(string html)
        {
            var htmlDoc = new HtmlDocument();
            htmlDoc.LoadHtml(html);

            var repositories =
                htmlDoc
                    .DocumentNode
                    .SelectNodes("//div[@class='js-pinned-items-reorder-container']/ol/li/div/div");

            List<(string RepositoryName, string Description)> data = new();

            foreach (var repo in repositories)
            {
                var name = repo.SelectSingleNode("div/div/span/a").InnerText;
                var description = repo.SelectSingleNode("p").InnerText;
                data.Add((name, description));
            }

            return data;
        }
    }
}

Запустив этот код, вы получите следующее

Image by Ahmed Tarek

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

Как видите, использовать HttpClient и HtmlAgilityPack просто. Все, что вам нужно, это привыкнуть к их API, и тогда это будет несложно.

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

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


Парсинг динамического веб-сайта

Теперь мы должны попытаться удалить некоторые данные с динамического веб-сайта. Однако, поскольку я должен быть осторожен перед парсингом веб-сайта, я бы применил тот же пример, что и раньше, но теперь предполагая, что веб-сайт является динамическим.

Поэтому, опять же, в этом примере мы собираемся удалить мой собственный профиль GitHub https://github.com/AhmedTarekHasan< /сильный>


Наблюдение за структурой данных в HTML

Это будет то же самое, что и раньше.


Написание кода

Вот шаги, которые я выполнил:

  1. Создано консольное приложение. Решение: WebScraping. Проект: WebScraper.
  2. Установлен пакет NuGet HtmlAgilityPack.
  3. Установлен пакет NuGet Selenium.WebDriver.
  4. Установлен пакет NuGet Selenium.WebDriver.ChromeDriver.
  5. Добавлена ​​директива using using HtmlAgilityPack
  6. Добавлена ​​директива using using OpenQA.Selenium.Chrome;
  7. Определен метод private static string GetHtml() для получения HTML.
  8. Определил метод private static List<(string RepositoryName, string Description)> ParseHtmlUsingHtmlAgilityPack(string html) для анализа HTML.
  9. И наконец, код должен выглядеть следующим образом:

using System.Collections.Generic;
using HtmlAgilityPack;
using OpenQA.Selenium.Chrome;


namespace WebScraper
{
    class Program
    {
        static void Main(string[] args)
        {
            var html = GetHtml();
            var data = ParseHtmlUsingHtmlAgilityPack(html);
        }

        private static string GetHtml()
        {
            var options = new ChromeOptions
            {
                BinaryLocation = @"C:Program Files (x86)GoogleChromeApplicationchrome.exe"
            };

            options.AddArguments("headless");

            var chrome = new ChromeDriver(options);
            chrome.Navigate().GoToUrl("https://github.com/AhmedTarekHasan");

            return chrome.PageSource;
        }

        private static List<(string RepositoryName, string Description)> ParseHtmlUsingHtmlAgilityPack(string html)
        {
            var htmlDoc = new HtmlDocument();
            htmlDoc.LoadHtml(html);

            var repositories =
                htmlDoc
                    .DocumentNode
                    .SelectNodes("//div[@class='js-pinned-items-reorder-container']/ol/li/div/div");

            List<(string RepositoryName, string Description)> data = new();

            foreach (var repo in repositories)
            {
                var name = repo.SelectSingleNode("div/div/span/a").InnerText;
                var description = repo.SelectSingleNode("p").InnerText;
                data.Add((name, description));
            }

            return data;
        }
    }
}

Запустив этот код, вы получите следующее

Image by Ahmed Tarek

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

Как видите, использовать Selenium.WebDriver и Selenium.WebDriver.ChromeDriver очень просто.


Photo by Pablo Heimplatz on Unsplash

Заключительные слова

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

Вот и все, надеюсь, вам было так же интересно читать эту статью, как мне было ее писать.


Также опубликовано здесь


Оригинал