Пишем парсеры в Zennoposter на C#. Инструкция для новичков от новичка часть 2

volody00

Client
Регистрация
06.09.2016
Сообщения
58
Благодарностей
81
Баллы
18
В прошлой статье я показал, как парсить на веб. В этой статье разберем парсинг на запросах. Писать будем парсер нашего любимого форума zennolab. Несколько предупреждений:

  • Статья для новичков
  • В статье могут быть неточности в терминах ввиду неопытности автора
  • Шаблон писался на последней версии (5.39.0.0)
  • Не рассматривается вариант, когда какие-либо данные подгружаются скриптом
  • В этой статье на логике я останавливаться не буду. Просто покажу, как парсить на запросах простенькие сайты. Если вы пока не понимаете, как писать парсеры, то можете ознакомиться с моей предыдущей статьей.
Подготовка

Собирать будем ссылки на профили пользователей. Парсить мы будем активных пользователей, т.е. тех, кто оставляет сообщения. Нужные нам ссылки на профили находятся здесь (1):
46138

Зальем в txt файл ссылки на разделы, которые хотим парсить. Для примера взял «новости», «партнерская программа», «ZennoStore»
46140

Создаем кубик c# и привязываемся к нашему txt файлу:
46142 46143

В кубике c# мы создали список (далее к нему будем обращаться по имени spis):

C#:
IZennoList spis = project.Lists["разделы"]; //создаем список с именем spis
Создадим цикл и возьмем первый раздел:
46144

Теперь спарсим html-код страницы. Делается это следующим образом:
46145

Так, теперь у нас в переменной response хранится код вот этой страницы - https://zennolab.com/discussion/forums/novosti.35/

Сейчас нам надо составить xpath путь до нужных нам ссылок. Идем в гугл хром, открываем страницу, устанавливаем плагин Xpath Helper Wizard (если его нет, устанавливаем). Посмотрим, как можно выцепить нужные нам ссылки. Жмем по ним правой кнопкой мыши, смотрим в код:
46147

За сами ссылки не зацепиться, будем брать элементы повыше. Видим, что у него есть «родитель» <div class="structItem-title">
46148

Видим, что данный вариант нам подходит. На всякий случай разберем наш xpath путь (//div[@class='structItem-title']/a). Я сказал, что мне надо найти тег div с классом равным 'structItem-title', а затем найти его «ребенка» тег a.

Ок, xpath путь мы составили. Чтобы нам спарсить эти элементы нам понадобится ещё два списка:

  • Один временный - List<string> vrem = new List<string>();
  • Другой основной - IZennoList ssylk = project.Lists["ссылки"]

46149

Запустим шаблон. Зайдем в наш файл ссылки.txt и убедимся, что всё норм.
46150

Всё норм, но перед /discussion/ не хватает https://zennolab.com/. Мы это потом поправим.

Парсим остальные страницы

Сейчас мы с вами получили парсинг только трех страниц, указанных в txt файле. Нам надо собрать остальные. Как мы это сделаем? Мы будем искать кнопку Next до тех пор, пока она не исчезнет.
46151
46152
Т.е.логика у нас такая:
  • находим кнопку Next
  • если она есть, то берем у неё href
  • загружаем html-код стр
  • парсим что нам нужно
  • находим кнопку Next, если она есть, то берем у неё href
  • загружаем html-код стр
  • и т.д.
Если нет, то цикл завершает работу. Давайте реализовывать
46153

Что хочу отметить:
  • обратите внимание на 13 строку. Тут мы уже складываем в переменную, отбирая только один элемент (с помощью ElementAt(0))
  • Если в результате выполнения ZennoPoster.Parser.ParseBByXpath ничего не найдется, то будет ошибка. Именно поэтому мы обернули данный код в try-catch. Т.е. если ничего не будет найдено, то будет ошибка и шаблон перейдет к выполнению того, что написано внутри catch {}. Там я говорю, что надо выйти из цикла (значит, мы больше не нашли кнопок Next)
  • Если xpath пути привязываете к названиям (например, //a[contains(string(), 'ZennoDroid')]), то следите за тем, чтобы на сайте не было нескольких языковых версий (обжегся на этом, пока писал данный код)
Многопоток

Я в многопотоке не силен, но решил включить в статью, чтобы вы могли с чего-то начать. В общем, у нас есть такая конструкция:



Если вы что-то напишите внутри него, то остальные потоки будут ждать. SyncObjects может быть 3 видов:

SyncObjects.ListSyncer - для списков
SyncObjects.TableSyncer - для таблиц
SyncObjects.InputSyncer - для буфера обмена

Вот нарисовал для себя как это работает, может кому-то будет полезно. Предположим, что у нас есть 3 спортсмена, которые стартуют одновременно:
46154


Затем кто-то из них (тот, кто первый =) ) заходит в поле lock. Остальные при этом туда зайти не могут и ждут, пока тот выбежет оттуда.
46155

Когда чел выходит из поля lock(){}, туда запускают ещё одного (только одного (!))
46157

У нас в коде может быть несколько lock(). При этом сколько бы их ни было, в поле может находиться только один чел.
46158

О последнем факте и о том, что бывает не только SyncObjects.ListSyncer, я узнал совсем недавно вот отсюда (рекомендую ознакомиться).
С детским садом закончили, перейдем к практике. Как мы с вами поступим:

  • На 8-й строке мы с вами получаем строку (razdel = spis), в которой содержится категория. Нам нельзя, чтобы несколько потоков её взяли. Поэтому мы её залочим и после взятия удалим
    Соответственно, следующий поток уже не сможет взять тот же урл (мы его удалили), он возьмет уже следующий и будет работать с ним.
    Следующий лок нам нужен тогда, когда мы записываем в наш основной txt файл, чтобы не получилось так, что несколько потоков одновременно засовывают туда информацию. Это 12 строка и 23 строка


Давайте реализуем это:
46159

Ап. Начал тестить шаблон и нашел косяки. Какие нюансы:

    • Во-первых, я забыл поменять шестую строку. Поскольку мы с вами теперь удаляем строки из файла, то spis.Count у нас постоянно уменьшается. Её надо за циклом записать в переменную и в цикле уже подставлять именно переменную
    • Во-вторых, при парсинге выяснился такой нюанс: например, на 5 странице мой Xpath путь работает, а на шестой уже нет. Из-за этого собирались не все данные
    • При запуске многопотока выходит ошибка, что индекс за пределами диапазона
Давайте исправлять. Сначала по первому пункту:

46161
Теперь по второму пункту. Переделаем xpath путь. И добавим проверку. В общем, если зайти на стр то можно увидеть общее количество страниц:
46162
Если наш шаблон вывалился в catch, то делаем проверку: равна ли последняя цифра в урл этой цифре. Если нет, то выведем себе сообщение, что наш xpath путь фуфло. Т.е. мы будем сравнивать вот эти две цифры:
46163

Получаем цифру (где постраничная пагинация)
46164
Сравниваем:
46165
И теперь по третьему пункту:
46166
При работе на запросах можно поставить галочку «без браузера».
46167

Парсим пользователей

Тут принцип тот же. Создаем новый кубик и действуем по следующей схеме:
  • Создаем цикл
  • Берем урл
  • Удаляем его
  • Делаем запрос
  • Вытаскиваем профили пользователей
  • Перебираем их в цикле
  • Складываем в список

Реализацию можно посмотреть в шаблоне. Спасибо за внимание.
 
Категория
Полезно

Вложения

  • 20,5 КБ Просмотры: 71
Последнее редактирование модератором:

Valandersi

Client
Регистрация
19.01.2015
Сообщения
989
Благодарностей
428
Баллы
63
Для тех кто только начинает осваивать c# хороший пример, спасибо
 

Supergrok

Client
Регистрация
05.03.2019
Сообщения
54
Благодарностей
64
Баллы
18
А я буду изучать, потому что хочу сам парсер себе написать. А можно видео запилить?
 

volody00

Client
Регистрация
06.09.2016
Сообщения
58
Благодарностей
81
Баллы
18
А я буду изучать, потому что хочу сам парсер себе написать. А можно видео запилить?
видео модераторы не пропустили, из-за того что автор (т.е. я) периодически тупил и из-за этого затянул его на 30 мин. Переписывать не хочу. По шагам запускайте и смотрите, что происходит. если что спрашивайте
 

Phoenix78

Client
Регистрация
06.11.2018
Сообщения
1 319
Благодарностей
639
Баллы
113
видео модераторы не пропустили, из-за того что автор (т.е. я) периодически тупил и из-за этого затянул его на 30 мин. Переписывать не хочу. По шагам запускайте и смотрите, что происходит. если что спрашивайте
самокритично :-)
этот 12-й конкурс прям впечатляет. статья за статьей и все такие интересные :-)
 

DenisK

Client
Регистрация
28.06.2016
Сообщения
351
Благодарностей
142
Баллы
43
Спасибо, пригодится . 8-)
 

Valandersi

Client
Регистрация
19.01.2015
Сообщения
989
Благодарностей
428
Баллы
63
Пример с человечками хороший, реально на пальцах объяснил
 

Чешир

Client
Регистрация
27.06.2014
Сообщения
1 257
Благодарностей
608
Баллы
113
Спасибо. Очень доходчиво. Даже коту, вроде меня, понятно. А для Хпата есть подобный плагин для Мозиллы (не люблю я Хрома, он говнюк)
 

Кто просматривает тему: (Всего: 1, Пользователи: 0, Гости: 1)