Рубрика: Парсинг

Парсер Яндекс Маркет с помощью ZennoPoster за 30 минут.

Парсер Яндекс Маркет с помощью ZennoPoster за 30 минут.

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

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

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

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

Благодаря ZennoPoster Вы сможете создать собственный парсер, который будет работать так как Вы захотите, без программистов, регистраций и смс всего за 30 минут. Не верите? Читайте дальше!

На примере Яндекс Маркет мы создадим автоматизированный шаблон, который будет собирать названия товаров, фотографии, цены и другие данные с последующей выгрузкой в Excel \ CSV файл.
Статья будет содержать информацию, как для новичков, так и для продвинутых пользователей.

Создаем шаблон парсера Яндекс Маркет за 30 минут. Быстрый старт для новичка.

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

Но перед тем, как продолжить нам необходимо изучить пациента и выстроить логику работы. Для примера возьмём каталог мобильных телефонов.
Зайдя на страницу, первое на что я обратил внимание – это количество отображаемых позиций: 12. Их определённо необходимо увеличить.
Сделать это мы можем с помощью переключателя:

Так же мы видим 2 варианта перехода на следующую страницу:

  • Подгрузка данных
  • Классический постраничный листинг

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

И, пожалуй, изменим вид отображения так как нам нужны ещё и краткие характеристики товара.

Стоит заметить, что при клике на иконку, изменился URL нашей страницы. Появился параметр: viewtype=list

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

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

{-Variable.URL-}list?viewtype=list

Сразу выполняем этот кубик и продолжаем работу прямо во внутреннем браузере Project Maker. Теперь нам необходимо добавить 2 действия клика для смены кол-ва видимых позиций.

Исследуем элемент выпадающего списка и пробегаем по его свойству и древу в целом.

Наша задача – определить параметр(ы) для поиска нужного нам элемента на странице. Желательно чтобы в найденных отображался только он. Я остановился на таких значениях:

Жмём кнопку “Добавить в проект”. Далее делаем тоже самое для выпадающего списка, пункта “Показывать по 24”.

При таком раскладе у нас находится 2 элемента, а нам нужен один. Поэтому я решил добавить ещё параметр поиска. Для этого так же жмём “Добавить в проект” и щелкаем 2 раза левой кнопкой мыши по ново-созданному кубику.

И в условиях я указал:

  • Группа: 0
  • Атрибут: innerHtml
  • Тип поиска: regexp
  • Значение: 24
  • Номер совпадения: 0

А для нашего первого условия поменял номер совпадения с 0 на “0-end”. Это было сделано для того, чтобы если вдруг изменится набор пунктов, поиск проходил не только по первой позиции, а по всем пунктам от начала и до конца. Подробнее о диапазонах читайте здесь: https://zennolab.com/wiki/ru:ranges

О правильном поиске элементов Вы можете прочитать в одной из конкурсных статей: Правильный поиск элементов на странице и работа с ними! Основы и хитрости! Должен знать каждый!

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

А именно: Наименование, Цена, Категория и подкатегория, Характеристики (краткие), Фотография и Ссылка на товаров в Я.М.

Из всего набора данных один из параметров является статичным, поэтому его нужно будет спарсить только один раз – это (под)категория.

Расположение которой находится в самом вверху и именуется, как “Хлебные крошки”. Чтобы удобнее было распарсить всё это дело, предлагаю положить фрагмент этого HTML кода в отдельную переменную, путём исследования элемента по условиям:

  • Группа: 0
  • Атрибут: id
  • Тип поиска: text
  • Значение: n-breadcrumbs
  • Номер совпадения: 0

И действием GET, где атрибут outerhtml.

Если мы не изменим переменную назначения, данные попадут в автоматически созданную. Теперь нам необходимо получить названия ссылок и отправить их в переменную “cat”.

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

Так же в ProjectMaker есть удобный конструктор регулярных выражений, где Вы можете просто заполнить соответствующие поля и регулярка сформируется автоматически.
Добавляем кубик обработки текста, а в опциях выбираем Regex.
Итоговое регулярное выражение:

(?<=a class="link[^"]*"[^>]+>)[\w\s]+

 

Так как нужна вся иерархия, забираем “Все” и кладем в список.
Следующим шагом объединяем в переменную “cat” и очищаем список.
А куда мы будем складывать данные? Пора создать файл сделать привязку.
Создаём таблицу “Файл экспорта” и делаем, как на скриншоте:

Отлично! Добавляем действие -> Таблицы –> Операции над таблицей, в опциях выбираем «Привязать к файлу».
Путь:

{-Project.Directory-}{-Variable.cat-}[{-TimeNow.Datedd-MM-yy-}].csv

Где последний тег – это время.
Файл будет выглядеть примерно следующим образом: Электроника-Телефоны и аксессуары к ним-Мобильные телефоны[03-11-17].csv
Как насчёт заголовков в нашем CSV файле?

Между 2-мя этими кубиками следует добавить паузу секунд на 5, чтобы файл успел создаться.

Мы будем парсить по одному сниппету, а далее в цикле разбирать его по косточкам. Вновь возвращаемся к нашему любимому занятию – исследование элемента с GET’ом на атрибут outerhtml. А после жмём по кубику правой кнопкой мыши и выбираем пункт “Повторить в цикле”.

У нас появилась авто-переменная counter0, её необходимо будет добавить в номер совпадения, чтобы по итогу у нас получилось так:

  • Атрибут: class
  • Тип поиска: regexp
  • Значение: n-snippet-card2 b-zone i-bem
  • Номер совпадения: {-Variable.Counter0-}

А всё, что попало в {-Variable.0-}, мы кладём в список “Карточки товаров”.

Вот, что у нас получилось:

Откуда взялось {count}, спросите Вы. Вместо него должно быть число 24 так как именно столько товарных позиций будет на каждой странице. Но может, например, сломаться селект или что-то не прогрузится и их кол-во не изменится, поэтому имеет смысл сделать программную проверку.

Создадим C# кубик и расположим его перед синим кубиком со скриншота. Его содержимое:

return instance.ActiveTab.FindElementsByAttribute("div", "class", "n-snippet-card2 b-zone i-bem", "regexp").Count;

Чтобы его не потерять, выделите код в кубике и нажмите правую кнопку мыши, а далее по пункту “Сохранить в C# сниппет”. Теперь, если появится необходимость в подсчёте элементов, достаточно будет кликнуть «Вставить C# сниппет».

Результат кладём в переменную “count”.
А минус -1 в конце потому, что «машинный счёт” идёт с 0, а не 1. Можно, конечно, построить цикл по-другому или вообще отказаться от него, но об этом в другой раз.
Как только все элементы будут обработаны, можем приступать ко второму циклу – парсингу значений по мини-карточкам товаров, которые сейчас находятся в списке “Карточки товаров”.

Протягиваем красную стрелку от кубика логики к «Получению строки из списка с удалением», которую будем класть в переменную data. А дальше начинается разрабор данные с помощь регулярок.

Название

(?<=<div\ class="n-snippet-card2__title"><a[^>]+>)[^>]+(?=</a></div>)

Цена

(?<=<div class="price">от )[\d\s]+

После нам необходимо убрать в цене лишние пробелы, чтобы было не так 6 990,  так 6990.
Делаем это с помощью замены текста по Regex, а конкретно {-String.Space-} (пробел) на пустую строку.

Характеристики

(?<=li class="n-snippet-card2__desc-item">)[^<]+

Но здесь нам необходимо получить все совпадения, а не первое. Поэтому кладём результат в список «Временные данные» и после объединяем элементы в переменную char. По завершению удаляем данные из списка.
Изображение

(?<=img class="image" src=")[^"]+

Ссылка на карточку в Я.М.

(?<=a class="link[^"]*" href=").*?search

В ссылке может быть HTML-сущность, которую необходимо заменить на обычный символ.

В переменную yam_link упадёт относительная ссылка. Если же нам нужна абсолютная, добавьте кубик обработки переменных со значением:

https://market.yandex.ru{-Variable.yam_link-}


Финальным шагом мы добавляем полученные данные в нашу таблицу «Файл экспорта», которая привязана к файлу.
Добавить действие -> Таблицы -> Операции над таблицами -> Добавить строку
Далее считаем сколько осталось строк в списке “Карточек товаров” и кубиком логики проверяем, чтобы это значение было > 0. Цикл будет продолжать, пока не будут обработаны все данные.

Как только все товары со страницы будут обработаны, пора переходить к следующему листу, протянув красную стрелку к следующему блоку:

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

А далее в случае успеха мы переходим к кубику “Считаем кол-во товаров на странице”, продолжая цикл, пока не обработаем все страницы, либо к оповещению о завершении проекта, если элемент не будет найден.

Парсер Яндекс Маркет с помощью XPath для продвинутых пользователей.

Выше описанный вариант – это не единственный способ написания шаблона, но второй способ, что будет изложен ниже, требует определённых навыков, как например знание HTML разметки и базовое понимание C# кода.

XPath —  Это гибкий и мощный язык запросов к элементам xml или (x)html документа и xslt преобразований по DOM, который является стандартом консорциума W3C.

Для тех, кто хочет познакомиться с ним ближе: http://zennolab.com/wiki/ru:xpath

В нашем продвинутом варианте мы заменим все кубики распарса сниппета по регулярным выражениям на поиск значений через XPath. Начнём, пожалуй, с поиска категории по хлебным крошкам.

project.Variables["cat"].Value = string.Empty;

// Парсим хлебные крошки
var chars = instance.ActiveTab.FindElementsByXPath("//*[@id='n-breadcrumbs']/li/a");
string sep = "-";
int count = chars.Count;
int i = 1;

// Перебираем ХК и парсим категории\подкатегории
foreach(HtmlElement item in chars) {
	if (i==count) sep = string.Empty;
	project.Variables["cat"].Value = string.Format(@"{0}{1}{2}", project.Variables["cat"].Value, item.FindChildByXPath(".", 0).InnerText, sep);
	project.SendInfoToLog(i.ToString());
	i++;
}
// Удаляем лишние пробелы и отступы
project.Variables["cat"].Value = project.Variables["cat"].Value.Trim();

Где мы забираем все элементы <a> принадлежащие идентификатору n-breadcrumbs в коллекцию.
Далее в цикле получаем каждый элемент и записываем его в переменную «cat«.

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

// Инициализируем счётчик
int i = Convert.ToInt32(project.Variables["Counter0"].Value);

// ID товара
string itemID = instance.ActiveTab.FindElementByXPath(".//*[contains(@data-id, 'model-')]", i).GetAttribute("data-id").Replace("model-", "");

// Наименование товара
var name = instance.ActiveTab.FindElementByXPath(".//*[contains(@data-id, 'model-"+itemID+"')]//div[contains(@class, '_title')]/a[contains(@class, 'link')]",0);
project.Variables["name"].Value = name.GetAttribute("innertext");

// Цена
var price = instance.ActiveTab.FindElementByXPath(".//*[contains(@data-id, 'model-"+itemID+"')]//div[contains(@class, 'main-price')]/a/*[contains(@class, 'price')]",0);
project.Variables["price"].Value = Regex.Match(price.GetAttribute("innertext"), @"[\d\s]+").Value.Replace(" ", ""); // Убираем в цене лишнее. Оставляем только цифры.

// Характеристики
project.Variables["char"].Value = string.Empty;
var chars = instance.ActiveTab.FindElementsByXPath(".//*[contains(@data-id, 'model-"+itemID+"')]/div//ul/li");
// Перебериаем коллекцию элементов
foreach(HtmlElement item in chars) {
	project.Variables["char"].Value = string.Format(@"{0}{2}{1}", project.Variables["char"].Value, item.FindChildByXPath(".", 0).InnerText, System.Environment.NewLine);
}
// Удаляем лишние пробелы и отступы
project.Variables["char"].Value = project.Variables["char"].Value.Trim();

// Ссылка на карточку товара в Я.М.
var url = instance.ActiveTab.FindElementByXPath(".//*[contains(@data-id, 'model-"+itemID+"')]//div[contains(@class, '_title')]/a[contains(@class, 'link')]",0);
project.Variables["yam_link"].Value = url.GetAttribute("href");

// Фотография
var photo = instance.ActiveTab.FindElementByXPath(".//*[contains(@data-id, 'model-')]//div/a[contains(@class, '_image')]/img",0);
project.Variables["img"].Value = photo.GetAttribute("src");

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

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

Итог

Как Вы видите, с помощью ZennoPoster можно написать шаблон любой сложности при использовании инструментов, как из стандартного набора, так и при применении собственного кода. И необязательно быть программистом.

Шаблоны для использования

Быстрый старт: https://yadi.sk/d/35O_M86G3PTBfv
XPath: https://yadi.sk/d/N3mttLWi3PTBgF

Обсудить на форуме