Парсинг данных онлайн-магазина на C#

Аватарка пользователя Yaroslav Menshikov
Отредактировано

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

32К открытий36К показов

Всем привет! Сегодня мы учимся парсить любой веб-портал из кода нашего приложения. Для парсинга данных используем язык программирования C#. Если ваш любимый язык не C#, то не беда — используя данный подход можно решить задачу парсинга на любом современном языке.

Итак, ставим задачу.

Задача: спарсить карточку товара из онлайн магазина baucenter.ru, зная артикул товара.

Что понадобится ?

1. Сниффер HTTPS пакетов. Использую Fiddler.

2. Среда разработки приложения Visual Studio 2019.

Этап 1. Сбор данных сниффером пакетов

Запускаем Fiddler, параллельно открываем браузер и переходим на baucenter.ru. В поле поиска товара вставляем любой известный на данном сайте артикул товара (при открытии любого товара отображается артикул). Использую артикул 416001653.

Парсинг данных онлайн-магазина на C# 1
 Результат сбора данных представлен на рисунке 1. Только собранных пакетов будет не 32 как нарисунке, а больше (у меня 320).

Этап 2. Фильтрация пакетов

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

Ненужные пакеты — это:

  • Пакеты вида Tunnel to …;
  • Изображения и шрифты;
  • JavaScript файлы;
  • CSS файлы;
  • Запросы на другие порталы нежели baucenter.ru.

Удалив ненужное, получаем следующее:

Парсинг данных онлайн-магазина на C# 2

Рисунок 2. Список отфильтрованных пакетов

Этап 3. Анализ отфильтрованных пакетов.

Открыв карточку товара с артикулом 416001653 в браузере, видим карточку товара со всеми данными. Нас интересует название товара и цена.

Название товара: Тумба с раковиной Onika Крит 52 см.

Цена товара: 3390.

В Fiddler через поиск по тексту ищем, в каком запросе есть текст с названием товара, ценой и артикулом. В моём случае это запрос №241. Рассмотрим его.

Парсинг данных онлайн-магазина на C# 3

Обратим внимание, чтобы выполнить данный запрос нужно знать адрес карточки товара https://baucenter.ru/mebel_dlya_vannoy_razmer_50_59sm1217/686594/. А его в данный момент у нас нет.

Снова через поиск по тексту в Fiddler ищем текст: https://baucenter.ru/mebel_dlya_vannoy_razmer_50_59sm1217/686594/. В моём случае этот текст находится в запросе №217.

Парсинг данных онлайн-магазина на C# 4
Парсинг данных онлайн-магазина на C# 5
Рассмотрев данный запрос и ответ веб-сайта на данный запрос (рисунки 4 и 5), делаем следующие выводы:
  • в HTML-коде ответа на запрос №217 есть ссылка на карточку товара. Зная эту ссылку, мы из кода программы сделаем туда запрос и получим необходимые данные о товаре (название и цену, например);
  • для выполнения запроса №217 нужно знать только артикул товара, а он у нас есть («416001653»);
  • чтобы получить карточку товара из кода приложения, нужно сделать 2 запроса: POST-запрос на адрес https://baucenter.ru, передав артикул товара, и GET-запрос на полученный адрес из первого запроса.

Этап 4. Создать классы GetRequest и PostRequest в приложении

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

			public class GetRequest
    {
        HttpWebRequest _request;
        string _address;

        public Dictionary Headers { get; set; }

        public string Response { get; set; }
        public string Accept { get; set; }
        public string Host { get; set; }
        public string Referer { get; set; }
        public string Useragent { get; set; }
        public WebProxy Proxy { get; set; }

        public GetRequest(string address)
        {
            _address = address;
            Headers = new Dictionary();
        }

        public void Run(CookieContainer cookieContainer)
        {
            _request = (HttpWebRequest)WebRequest.Create(_address);
            _request.Method = "Get";
            _request.CookieContainer = cookieContainer;
            _request.Proxy = Proxy;
            _request.Accept = Accept;
            _request.Host = Host;
            _request.Referer = Referer;
            _request.UserAgent = Useragent;

            foreach (var pair in Headers)
            {
                _request.Headers.Add(pair.Key, pair.Value);
            }

            try
            {
                HttpWebResponse response = (HttpWebResponse)_request.GetResponse();
                var stream = response.GetResponseStream();
                if (stream != null) Response = new StreamReader(stream).ReadToEnd();
            }
            catch (Exception)
            {
            }
        }
    }
		
			public class PostRequest
    {
        HttpWebRequest _request;
        string _address;

        public Dictionary Headers { get; set; }

        public string Response { get; set; }
        public string Accept { get; set; }
        public string Host { get; set; }
        public string Data { get; set; }
        public string ContentType { get; set; }
        public WebProxy Proxy { get; set; }
        public string Referer { get; set; }
        public string Useragent { get; set; }

        public PostRequest(string address)
        {
            _address = address;
            Headers = new Dictionary();
        }

        public void Run(CookieContainer cookieContainer)
        {
            _request = (HttpWebRequest)WebRequest.Create(_address);
            _request.Method = "Post";
            _request.CookieContainer = cookieContainer;
            _request.Proxy = Proxy;
            _request.Accept = Accept;
            _request.Host = Host;
            _request.ContentType = ContentType;
            _request.Referer = Referer;
            _request.UserAgent = Useragent;

            byte[] sentData = Encoding.UTF8.GetBytes(Data);
            _request.ContentLength = sentData.Length;
            Stream sendStream = _request.GetRequestStream();
            sendStream.Write(sentData, 0, sentData.Length);
            sendStream.Close();

            foreach (var pair in Headers)
            {
                _request.Headers.Add(pair.Key, pair.Value);
            }

            try
            {
                HttpWebResponse response = (HttpWebResponse)_request.GetResponse();
                var stream = response.GetResponseStream();
                if (stream != null) Response = new StreamReader(stream).ReadToEnd();
            }
            catch (Exception)
            {
            }
        }
    }
		

Данные классы позволяют выполнять Get и Post запросы на веб-порталы. В конструктор класса передается адрес веб-сайта. В свойства класса передаются стандартные заголовки HTTP запроса: Accept, Host, Data, ContentType, Referer, Useragent. Свойство Proxy служит для установки прокси-сервера, через который будет отправлен запрос.

Это нужно для удобной проверки выполнения своего кода, передав в это свойство значение прокси-сервера Fiddler (по умолчанию 127.0.0.1:8888). Таким образом, при выполнении запросов из программы вы увидите запросы в Fiddler и сможете легко понять проблему, если она будет.

Выполнение запроса происходит при вызове метода Run, и передаче в данный метод контейнер куки. Контейнер куки создаёте перед выполнением всех запросов. После выполнения запросов контейнер записывает в себя, полученные от веб-портала куки. Это позволяет выполнять последующие запросы с сохраненными куки-данными.

Результат выполнения запроса записывается в виде текста в свойство Response.

Этап 5. Создание приложения для получения карточки товара

			static void Main(string[] args)
        {
            // артикул товара
            var code = "416001653";
            
            // прокси-сервер
            var proxy = new WebProxy("127.0.0.1:8888");
            
            // контейнер куки
            var cookieContainer = new CookieContainer();

            // запрос №1. получение адреса карточки товара по артикулу товара
            var postRequest = new PostRequest("https://baucenter.ru/");
            postRequest.Data = $"ajax_call=y&INPUT_ID=title-search-input&q={code}&l=2";
            postRequest.Accept = "*/*";
            postRequest.Useragent = "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko";
            postRequest.ContentType = "application/x-www-form-urlencoded";
            postRequest.Referer = "https://baucenter.ru/";
            postRequest.Host = "baucenter.ru";
            postRequest.Proxy = proxy;
            postRequest.Headers.Add("Bx-ajax", "true");
            postRequest.Run(cookieContainer);

            // поиск в HTML-коде ответа адрес карточки товара
            var strStart = postRequest.Response.IndexOf("search-result-group search-result-product");
            strStart = postRequest.Response.IndexOf("
		
			/// 
    /// Класс карточка товара.
    /// Метод Parse - парсинг HTML, запись свойств Title и Price
    /// 
    public class Card
    {
        public string Price { get; set; }
        public string Title { get; set; }

        public void Parse(string html)
        {
            var priceStart = html.IndexOf("Цена") + 11;
            var priceEnd = html.IndexOf("") + 4;
            var titleEnd = html.IndexOf("", titleStart);
            Title = html.Substring(titleStart, titleEnd - titleStart).Trim();
        }
    }
		

Результат выполнения программы представлен на рисунке 6.

Парсинг данных онлайн-магазина на C# 6

Код приложения можно найти здесь.

Подробное видео разработки данного проекта здесь:

Превью видео ehA6kwLbpwo
Следите за новыми постами
Следите за новыми постами по любимым темам
32К открытий36К показов