Парсер для форума XenForo

Author Автор: Роман Чернышов    Опубликовано: 22 декабря 2020

Парсер XenForo XenForo — движок, набирающий все большую популярность, среди сайтов-форумов, вместе с этим растет и его сообщество, пишутся плагины, патчи и хаки, и ко мне все чаще обращаются клиенты с различными задачами по доработке данного движка. Среди многообразия задач и решений, выделается интерес к моей разработке парсера, который в том числе я адаптировал под работу с движком форума XenForo. Это значит, что парсер может получать данные с любых сайтов и сохранять их в базу данных XenForo, тем самым наполняя сайт: разделами, форумами, темами, сообщениями, пользователями(в том числе их публично-доступными данными включая аватар) и т.д. Далее я расскажу подробнее о логике работы парсера и о технической части касаемо XenForo.

Логика работы парсера

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

  • Первичная настройка парсера на сайт донора, с указанием где и какие данные ему собирать, обучить «пониманию» структуры HTML страниц донора (задача не сложная, например прописать путь в xPath до заголовка страницы H1);
  • Обход главной страницы форума, сбор ссылок на разделы и их названия;
  • Обход разделов, сбор в них ссылок на форумы и их названия;
  • Обход форумов, сбор в них ссылок на топики и их названия;
  • Обход топиков, сбор в них всех сообщений и ссылок на их авторов(на профили пользователей);
  • Обход профилей пользователей и сбор всех доступных данных по ним;
  • Отдельно происходит сбор ссылок на постраничную навигацию, для последующего сбора информации на других страницах списков форумов и топиков.

После обхода каждого шага, парсер отсылает данные на принимающий скрипт(назовем его inputParseData.php), который размещен на нашем сайте с XenForo, этот скрипт получает данные и взаимодействует с базой данных форума, в зависимости от типа данных, он сохраняет их в ту или иную таблицу.

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

Одним из важных критериев, является возможность парсинга сайтов, которые доступны только после регистрации, имеют защиту от парсинга или защиту множественного открытия страниц в течении определенного промежутка времени. Для решения этой задачи, можно воспользоваться сторонними сервисами, помогающими обойти такую защиту, как например Google reCaptcha и т.д. Но, можно пойти и другим путем, перенести основную часть парсера на JavaScript и запустить парсер в почти автономном режиме в своем же браузере через UserScript(дополнение Violentmonkey для Chrome) в таком случае вы сможете воочию наблюдать за работой парсера, а также вмешиваться в неё если потребуется, помогать ему, в том числе для прохождения теста что вы не бот, например капчи от Google reCaptcha. Из недостатков это пожалуй то, что парсер будет работать на вашем ПК прямо в вашем браузере, впрочем и это решаемо, перенос парсера на «безголовый» браузер по типу PhantomJS и запуск его на сервере хостинга, уже полностью в автономной режиме работы без вашего участия(позаботившись о списках прокси и о сервисах обхода капчи, конечно же).

Сохраняем данные в базу XenForo

Пришедшие данные на каждом этапе, сохраняются в базу данных XenForo. Далее я расскажу в какие таблицы сохраняются те или иные типы данных, а также назначение их(таблиц) полей.

Сохраняем разделы

Таблица: xf_node

Запрос:

INSERT INTO `xf_node` (`node_id`, `title`, `description`, `node_name`, `node_type_id`, `parent_node_id`, `display_order`, `display_in_list`, `lft`, `rgt`, `depth`, `style_id`, `effective_style_id`, `breadcrumb_data`, `navigation_id`, `effective_navigation_id`, `xfa_nit_type`, `xfa_nit_params`) 
VALUES
(1,	'Название раздела',	'',	NULL,	UNHEX(''),	0,	300,	1,	51,	128,	0,	0,	0,	'a:0:{}',	UNHEX(''),	UNHEX(''),	0,	'');

В данном запросе стоит обратить внимания на значение полей:
node_id — ID раздела;
title — Название раздела;
parent_node_id — Если значение равно нулю значит данная запись является разделом, в ином случае форумом. Разделы и форумы хранятся в одной таблице.

Сохраняем форумы

Таблица: xf_forum

Запрос:

INSERT INTO `xf_forum` 
(`node_id`, `discussion_count`, `message_count`, `last_post_id`, `last_post_date`, `last_post_user_id`, `last_post_username`, `last_thread_title`, `last_thread_prefix_id`, `moderate_threads`, `moderate_replies`, `allow_posting`, `allow_poll`, `count_messages`, `find_new`, `field_cache`, `prefix_cache`, `prompt_cache`, `default_prefix_id`, `default_sort_order`, `default_sort_direction`, `list_date_limit_days`, `require_prefix`, `allowed_watch_notifications`, `min_tags`, `seo`) VALUES
(2,	1,	1,	1,	1608562826,	999,	'ИмяПользователя',	'Название форума',	46,	0,	0,	1,	1,	1,	1,	'a:0:{}',	'[]',	'',	0,	'last_post_date',	'desc',	0,	0,	'all',	0,	'');

В данном запросе стоит обратить внимания на значение полей:
node_id — ID форума;
discussion_count — Количество топиков;
message_count — Количество сообщений;
last_post_id — ID последнего сообщения;
last_post_date — Дата последнего сообщения (Unix time);
last_post_user_id — ID пользователя оставившего последнее сообщение;
last_post_username — Имя пользователя оставившего последнее сообщение;
last_thread_title — Название последнего топика;
last_thread_prefix_id — ID префикса(из таблицы прифексов xf_thread_prefix) последнего топика;
count_messages — Количество сообщений;

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

Таблица (та же, что и для разделов): xf_node

Запрос:

INSERT INTO `xf_node` (`node_id`, `title`, `description`, `node_name`, `node_type_id`, `parent_node_id`, `display_order`, `display_in_list`, `lft`, `rgt`, `depth`, `style_id`, `effective_style_id`, `breadcrumb_data`, `navigation_id`, `effective_navigation_id`, `xfa_nit_type`, `xfa_nit_params`) 
VALUES
(2,	'Название раздела',	'',	NULL,	UNHEX(''),	1,	300,	1,	51,	128,	0,	0,	0,	'a:0:{}',	UNHEX(''),	UNHEX(''),	0,	'');

В данном запросе стоит обратить внимания на значение полей:
node_id — ID форума;
title — Название форума;
parent_node_id — ID раздела к которому относится данный форум.

Сохраняем топики

Таблица: xf_thread

Запрос:

INSERT INTO `xf_thread` (`thread_id`, `node_id`, `title`, `reply_count`, `view_count`, `user_id`, `username`, `post_date`, 
`sticky`, `discussion_state`, `discussion_open`, `discussion_type`, `first_post_id`, `first_post_likes`, `last_post_date`, 
`last_post_id`, `last_post_user_id`, `last_post_username`, `prefix_id`, `tags`, `custom_fields`, `brms_promote_date`, 
`is_sticked`, `seo`, `rate`, `rate_count`) 
VALUES
(1,	2,	'Название форума',	0,	1,	999,	'ИмяПользователя',	'1608562826',	0,	'',	0,	'',	0,	0,	'1608562826',	0,	999,	'ИмяПользователя', 46,	'a:0:{}',	'a:0:{}',	0,	0,	'a:0:{}',	0.0,	0);

В данном запросе стоит обратить внимания на значение полей:
thread_id — ID топика;
node_id — ID форума к которому относится топик;
title — Название топика;
post_date — Дата создания топика (Unix time);
prefix_id — ID префикса из таблицы xf_thread_prefix, префикс это метка вначале названия топика: важно, новинка, информация, и т.д.

Сохраняем сообщения в топиках

Таблица: xf_post

Запрос:

INSERT INTO `xf_post` (`post_id`, `thread_id`, `user_id`, `username`, `post_date`, `message`, `ip_id`, `message_state`, `attach_count`, `position`, `likes`, `like_users`, `warning_id`, `warning_message`, `last_edit_date`, `last_edit_user_id`, 
`edit_count`, `embed_metadata`) 
VALUES
(1,	1,	999,	'ИмяПользователя',	'1608562826',	'Текст сообщения топика',	0,	'visible',	1,	0,	0,	'',	0,	'',	"1608562826',	1,	1,	'');

В данном запросе стоит обратить внимания на значение полей:
post_id — ID сообщения;
thread_id — ID топика;
user_id — ID пользователя;
username — Имя пользователя;
post_date — Дата создания сообщения (Unix time);

Также при сохранении сообщений в топик, необходимо обновить записи в БД топиков и форумов, изменив в них количество сообщений, а также информацию о последнем активном топике и данных о последнем сообщении.

Обновляем топик, указывая ID последнего сообщения и дату:

UPDATE `xf_thread` SET 
`first_post_id` = '1',
`last_post_id` = '1',
`discussion_state` = 'visible',
`post_date` = '1608562826',
`last_post_date` = '1608562826'
WHERE `thread_id` = '1'

Обновляем информацию о последнем активном топике и сообщении в таблице форума xf_forum:

UPDATE `xf_forum` SET 
`last_thread_title` = 'Название форума',
`last_post_id` = '1',
`last_post_user_id` = '999',
`last_post_date` = '1608562826',
`last_post_username` = 'ИмяПользователя',
`discussion_count` = `discussion_count` + 1,
`message_count` = `message_count` + 1
WHERE `node_id` = '2'";

Технические характеристики

Парсер состоит из двух частей, как я уже ранее сказал, это — головная часть на JavaScript запускаемая через UserScript или PhantomJS который непосредственно парсит данные с сайта донора и принимающий данные скрипт inputParseData написанный на PHP 7, который сохраняет данные в MySQL базу данных XenForo. Скорость парсинга можно наращивать путем параллельного запуска нескольких копий(вкладок в браузере) головной части. Настройка парсера на сайт донора осуществляется указанием путей xPath до нужных HTML элементов страницы.

Заключение

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

Обращайтесь буду рад поработать с вами!

Оставить комментарий

Автор блога
Роман Чернышов
Веб-разработчик,
Full Stack
Senior, Architect
PHP, JavaScript, Node.JS, Python, HTML 5, CSS 3, MySQL, Bash, Linux Admin
Заказать работу
предложить оффер

Моя книга
Книга. Веб-разработчик. Легкий вход в профессию
Печатная книга
Веб-разработчик.
Легкий вход в профессию
Купить за 159₽
Последние вопросы
Список вопросов
Последние комментарии
Меню

Archive

Мои проекты
Insurance CMS Love Crm CMS Совместные покупки Мой PHP Framework Хостинг для моих клиентов Лицензии на мой софт и поддержка