Рубрика: Создание шаблонов

Проверка e-mail адресов на существование: yandex, gmail, mail.ru, mail.com и др.

Проверка e-mail адресов на существование: yandex, gmail, mail.ru, mail.com и др.

В первой части статьи Универсальный чекер e-mail почты на валидность. Часть 1. мы говорили о методе проверке почтовых адресов к которым у Вас есть доступ (по паре логин:пароль). Сегодня мы продолжим данную тему и расскажем, как проверить почту на существование с помощью ZennoPoster.

Мы рассмотрим с Вами 4 пункта (условно их 3):
1. Проверить синтаксис написания почтового адреса по формату.
2. Проверить существование домена.
3. Подключиться к SMTP серверу проверяемого ящика и совершить попытку отправки письма.
3.1 Проверить существование email адреса через почтовый сервис.

Зачем это нужно?

Отправляя письма на несуществующие почтовые адреса, ваши письма будут определены как «нежелательные», что повлечёт за собой санкции со стороны почтового хостинга — бóльшая часть писем будет автоматически отправляться в папку спам или отклоняться вовсе.

И именно для того чтобы предотвратить появления в Вашей базе невалидных email-адресов, необходимо провести вышеописанные проверки.

Синтаксическая проверка

Проверка существования email адреса начинается с соответствия стандартам написания, согласно RFC 5322.

Например, хорошие:

Плохие:

 

Это регулярное выражение для канонических адресов электронной почты:

^(?(")(".+?(?<!\\)"@)|(([0-9a-z]((\.(?!\.))|[-!#\$%&'\*\+/=\?\^`\{\}\|~\w])*)(?<=[0-9a-z])@))(?(\[)(\[(\d{1,3}\.){3}\d{1,3}\])|(([0-9a-z][-\w]*[0-9a-z]*\.)+[a-z0-9][\-a-z0-9]{0,22}[a-z0-9]))$

Проверка существования домена

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

Нас интересует не столько статус домена, сколько наличие MX (mail exchanger) записей в DNS. которые указывают серверы, на которые нужно отправлять электронную почту, предназначенную для адресов в данном домене. Если они не прописаны, значит и проверяемый нами почтовый ящик не существует.

Данную проверку можно осуществить разными способами. Я поделюсь с Вами четырьмя:

  • С помощью библиотеки ARSoft.Tools.Net.Dns
  • Запрос к dns.google.com
  • Утилита dig
  • Утилита nslookup

(Шаблон с примерами будет в комплекте)

Я воспользуюсь 4-им способом, так он мне наиболее привычен.

Стандартный кубик запуска программ не позволяет сохранить результат выполнения в переменную, поэтому будем выполнять её через C# код:

var mx_srv = project.Variables["MAIL_SERVER"].Value;

var process = new System.Diagnostics.Process {
    StartInfo = new System.Diagnostics.ProcessStartInfo {
     UseShellExecute = false,
     CreateNoWindow = true,
     RedirectStandardError = true,
     RedirectStandardInput = true,
     RedirectStandardOutput = true,
     FileName = @"cmd.exe",
     WorkingDirectory = @"C:\Program Files\dig",
     Arguments = @"/c nslookup -type=mx "+mx_srv
     }
};
process.Start();
string output = process.StandardOutput.ReadToEnd();
process.WaitForExit();
process.Close();
process.Dispose();
return output;

Анализ ответа почтового сервера

Финальный шаг — подключаемся к SMTP серверу и имитируем отправку сообщения на проверяемый ящик. Если вернётся ответ 250 — ящик существует, 550 — к сожалению, такого адреса нет. Данный способ не является панацеей т.к. не все почтовые сервисы возвращают корректный ответ на данную команду, к ним относятся Mail Ru, Mail.com, Hotmail, Yahoo (о них мы поговорим отдельно, чуть ниже). Но с такими популярными службами, как Яндекс и Gmail проблем не возникает.

Итак, чтобы начать, необходимо подключиться к одному из почтовых серверов по 25 порту, которые хранятся у нас в списке «MX».

Далее мы говорим ему привет 🙂 с помощью команды:

HELO domain.com

Где второе — это название домена с которого Вы обращаетесь, может быть любым.

После чего мы посылаем команду:

MAIL FROM:<[email protected]>

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

RCPT TO:<[email protected]>

И вот здесь мы ждём ответ, 250 — good, 550 — bad.

Код выглядит следующим образом:

var list = project.Lists["MX"];
var logg = new StringBuilder();
string rcpt = project.Variables["email"].Value;
string exFromMail = string.Format(@"{0}@mail.com", project.Profile.NickName);

string mx_Server = System.Text.RegularExpressions.Regex.Replace(list[0], @"\.$", "");
project.SendInfoToLog("Взяли MX: "+mx_Server);
	
try {		
	//TcpClient SmtpServ = new TcpClient(mx_Server,25);
	var SmtpServ = new TcpClient();
	if (!SmtpServ.ConnectAsync(mx_Server, 25).Wait(7000)) {
		list.RemoveAt(0);
		project.SendWarningToLog("Connection timeout");
		return null;
	}
	string Data;
	byte[] szData;
	string CRLF = "\r\n";
	project.SendInfoToLog("Законектились");
	// Инициализация
	NetworkStream NetStrm = SmtpServ.GetStream();
	NetStrm.ReadTimeout = 7000;
	SmtpServ.Client.ReceiveTimeout = 7000;
	StreamReader  RdStrm= new StreamReader(SmtpServ.GetStream());
	logg.AppendLine(RdStrm.ReadLine());
	// Приветствуем сервер
	Data = "HELO mail.com" + CRLF;                
	szData = System.Text.Encoding.ASCII.GetBytes(Data.ToCharArray());
	NetStrm.Write(szData,0,szData.Length);
	logg.AppendLine(RdStrm.ReadLine());
	project.SendInfoToLog("EHLO");
	Data = string.Format("MAIL FROM: <{0}>{1}", exFromMail, CRLF);
	szData = System.Text.Encoding.ASCII.GetBytes(Data.ToCharArray());
	NetStrm.Write(szData,0,szData.Length);
	logg.AppendLine(RdStrm.ReadLine());
	// Указываем получателя (ящик которого мы и будем проверять)
	Data = "RCPT TO: <"+rcpt+">"+CRLF;
	szData = System.Text.Encoding.ASCII.GetBytes(Data.ToCharArray());
	NetStrm.Write(szData,0,szData.Length);
	logg.AppendLine(RdStrm.ReadLine());
	// quit from server SMTP
	Data = "QUIT"+ CRLF;
	szData = System.Text.Encoding.ASCII.GetBytes(Data.ToCharArray());
	NetStrm.Write(szData,0,szData.Length);
	//LogList.Items.Add(RdStrm.ReadLine());
	//logg.AppendLine(RdStrm.ReadLine());
	// Закрываем соединение
	NetStrm.Close();
	RdStrm.Close();
	//logg.AppendLine("Close connection");
} catch(InvalidOperationException err) {
	logg.AppendLine("Error: "+ err.ToString());
}
list.RemoveAt(0);
return logg;

С этим разобрались, супер!

Когда способ через SMTP сервер не работает — проверяем существование E-mail адреса через почтовый сервис

Вернёмся к почтовым сервисам, где данная проверка через SMTP сервер не работает (Mail Ru, Mail.com, Hotmail, Yahoo). Как же быть в таком случае?

На сайте КАЖДОГО почтового сервиса есть возможность восстановления пароля и\или проверка занятности адреса при регистрации, этими способами на примере двух сайтов (mail.ru и mail.com) мы и воспользуемся.

Mail.Ru

Переходим на страницу восстановления пароля: https://e.mail.ru/password/restore/

Перед нами несложная форма — то, что нужно!

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

Введём заведомо несуществующий логин и посмотрим, в каком виде нам придёт ответ.

Ключевой запрос, который нам нужен: https://e.mail.ru/api/v1/user/password/restore

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

Остается только перенести необходимые аргументы в запрос: X-Requested-With, Referer, X-Request-Id; Последний мы сгенерируем с помощью кода:

project.Variables["guid"].Value = Guid.NewGuid().ToString();

Последний шаг — формирование данных, которые необходимо передать в POST запросе. Делаем также по примеру:

Меняем статичные данные на переменные: tab-time (unix время) и e-mail, предварительно обработав UrlEncode.

Отправляем запрос и получаем примерно такой ответ:

Строчка «not_exist» означает, что ящика не существует, по ней и будем проверять все остальные почтовые ящики.

Не так уж и сложно, не правда ли? 🙂

Если всё-таки у Вас возникли сложности — пишите в обсуждении данной темы на форуме.

Mail.com

Переходим на страницу восстановления пароля: https://password.mail.com/passwordrecovery/

К сожалению, данная форма нам не подходит из-за каптчи т.к. это сильно будет тормозить процесс.

Воспользуемся вторым способом — проверкой занятости никнейма через форму регистрации: https://service.mail.com/registration.html

Рядом с полем ввода никнейма есть кнопка для проверки его на занятость, по клику на которую вылетит соответствующее уведомление:

Если же E-mail существует, появится следующий текст: nickna[email protected] is not available, please choose one of the following

Отследим запросы. Ключевой запрос выглядит так:

Нужные куки так же получаем после первого GET запроса к странице и копируем дополнительные заголовки: Wicket-Ajax, Wicket-FocusedElementId: id20

Данные для отправки выглядят следующим образом: [email protected]&

Значение zXXXXXXXX является динамическим, поэтому его, как и почту, необходимо заменить на переменную.

Применим xPath выражение, чтобы его достать: «.//*/span[contains(@class, ‘EmailAddress’)]/input»

Данные, которые передаются в URL (после знака вопроса) также являются динамическими и хранятся в аргументе onclick того же поля, откуда мы забрали нужно zXXXXXX значение.

Готово!

Отправляем запрос, парсим текст оповещения и определяем, существует почта или нет.

Готовый шаблон Вы можете скачать в теме данной статьи, на форуме.

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

Сбор целевой аудитории ВКонтакте. Часть 1.

Сбор целевой аудитории ВКонтакте. Часть 1.

Сегодня мы начинаем цикл статей по созданию шаблона по парсингу участников сообществ (группы, паблики, встречи) ВКонтакте для ретаргетинга. На данном примере Вы убедитесь, что создать собственными руками функциональный инструмент для сбора ЦА — это реальность. По завершению данной серии статей, у нас будет полноценный аналог сервисов по формированию аудитории для таргетированной рекламы или любых других коммуникаций, что позволит сделать Вашу рекламу эффективнее и дешевле, чем у конкурентов.

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

Мы будем использовать кубики GET-запросов из стандартного набора ZennoPoster. На первый взгляд такие слова, как «GET\POST запросы» и «API» звучат сложно и непонятно, но на деле — это проще пареной репы, тем более с использованием ZP. И сейчас Вы в этом убедитесь, поехали!

План действий:

  1. Создаём приложение
  2. Составляем запросы к API
  3. Собираем ID пользователей Вконтакте в *.txt файл

 

Создаём приложение

Переходим на страницу разработчиков, в раздел «Мои приложения» и жмём на кнопку «Создать приложение».

Указываем название и подключаем приложение, кликом по кнопке.

Далее в секции настроек необходимо его включить.

Составляем запросы к API

Список всех доступных методов Вы можете найти в документации.

Нам нужен всего 1 метод и это groups.getMembers

Данный метод принимает до 6 параметров. Самые важные для нас — это group_id и offset.

count (кол-во участников о которых нам нужно получить информацию) по-умолчанию стоит на 1000, что является максимумом, поэтому трогать его не будем.

В данном случае нам не нужен пользовательский ключ доступа (access_token) т.к. этот метод является открытым, но он пригодится нам в дальнейшем.

Информацию об этом Вы можете получить в шапке каждого из методов.

В итоге наш запрос будет выглядеть следующим образом, для примера возьмём группу Команда ВКонтакте (https://vk.com/team):

https://api.vk.com/method/groups.getMembers?v=5.69&group_id=team&offset=0

Он вернёт 1000 ID пользователей сообщества, чтобы получить следующую тысячу, необходимо изменить offset на 1000, далее на 2000 и т.д.

Собираем ID пользователей ВКонтакте в *.txt файл

В проекте ZennoPoster создаём переменную group_id и offset. Далее добавляем кубик HTTP -> GET-запрос,

В URL кубика прописываем:

https://api.vk.com/method/groups.getMembers?v=5.69&group_id={-Variable.group_id-}&offset={-Variable.offset-}

Загружаем только содержимое и кладём в переменную JSON.

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

Теперь необходимо всё это дело положить в список и сохранить в файл. И так в цикле до тех пор, не разберем все данные.

Делать мы будем это с помощью кубика «Обработка JSON/XML». Запускаем в ZennoPoster конструктор XPath / JSONPath, чтобы получить путь к нашим ID.

Вставляем туда текст и выделяем фрагмент со словом items, внутри которого лежат ID пользователей и жмем «Найти». Чуть выше появится специальная конструкция, которую необходимо скопировать.

$..items

Теперь необходимо добавить в проект 2 экшена по обработке JSON. Первый произведет парсинг по пути, который мы скопировали. Второй — отправит все ID в список.

Следующим шагом мы прибавляем 1000 к переменной offset (которая изначально была равна 0) и повторяем процедуру, начиная с запроса.

В конце, когда все данные будут собраны, с помощью кубика «Операции над списком» сохраняем результат в текстовый файл.

В следующей статье мы рассмотрим способ ускорения парсинга больших сообществ с помощью двух методов:

  • ВКонтакте API. Метод Execute.
  • За счёт многопоточности ZennoPoster

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

Парсер Яндекс Маркет с помощью 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.
Итоговое регулярное выражение:

(?&lt;=a class="link[^"]*"[^&gt;]+&gt;)[\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. А дальше начинается разрабор данные с помощь регулярок.

Название

(?&lt;=&lt;div\ class="n-snippet-card2__title"&gt;&lt;a[^&gt;]+&gt;)[^&gt;]+(?=&lt;/a&gt;&lt;/div&gt;)

Цена

(?&lt;=&lt;div class="price"&gt;от&amp;nbsp;)[\d\s]+

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

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

(?&lt;=li class="n-snippet-card2__desc-item"&gt;)[^&lt;]+

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

(?&lt;=img class="image" src=")[^"]+

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

(?&lt;=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

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