Парсер для форума 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
предложить оффер
- jQuery: как получить значение атрибута?
- PHP работа с изображением, класс SimpleImage
- Интеграция с API ОСАГО сайта sravni.ru
- Комментарии на PHP, Ajax, mySQL
- PHP: Категории бесконечного уровня вложенности.
- Nginx редирект на другой сервис с сохранением URL спросил (а) Сергей
- Исполнитель пропал, почему такое случается и понять с кем работать? спросил (а) Артем
- Можно ли WordPress считать универсальным движком? спросил (а) Андрей
- Что такое самописный скрипт или CMS? спросил (а) Антон
- Как при поиске в linux используя grep, добавить исключения? спросил (а) Алексей
- Консольный скрипт(JavaScript) для автоматических заказов на OZON к записи
- Консольный скрипт(JavaScript) для автоматических заказов на OZON к записи
- Как создать Telegram-бота с авторизацией через сайт к записи
- PHP скрипт: каталог закладок на сайты к записи
- Валидация на PHP к записи
- Сколько зарабатывают в бизнесе на совместных покупках к записи
- Сколько зарабатывают в бизнесе на совместных покупках к записи
Archive
- +2024 (25)
- Ноябрь 2024 (10)
- Октябрь 2024 (8)
- Сентябрь 2024 (1)
- Август 2024 (5)
- Май 2024 (1)
- +2023 (27)
- Ноябрь 2023 (1)
- Октябрь 2023 (13)
- Сентябрь 2023 (10)
- Апрель 2023 (1)
- Март 2023 (1)
- Февраль 2023 (1)
- +2022 (21)
- Декабрь 2022 (11)
- Ноябрь 2022 (1)
- Май 2022 (2)
- Апрель 2022 (2)
- Март 2022 (3)
- Февраль 2022 (1)
- Январь 2022 (1)
- +2021 (17)
- Декабрь 2021 (5)
- Ноябрь 2021 (2)
- Июль 2021 (1)
- Июнь 2021 (2)
- Май 2021 (5)
- Апрель 2021 (1)
- Март 2021 (1)
- +2020 (20)
- Декабрь 2020 (6)
- Сентябрь 2020 (2)
- Август 2020 (1)
- Июль 2020 (2)
- Май 2020 (2)
- Апрель 2020 (2)
- Март 2020 (2)
- Февраль 2020 (1)
- Январь 2020 (2)
- +2019 (18)
- Декабрь 2019 (3)
- Ноябрь 2019 (2)
- Октябрь 2019 (2)
- Сентябрь 2019 (1)
- Август 2019 (2)
- Июль 2019 (1)
- Июнь 2019 (1)
- Апрель 2019 (2)
- Март 2019 (1)
- Февраль 2019 (3)
- +2018 (44)
- Декабрь 2018 (4)
- Ноябрь 2018 (7)
- Октябрь 2018 (8)
- Сентябрь 2018 (1)
- Август 2018 (4)
- Июль 2018 (5)
- Май 2018 (3)
- Апрель 2018 (7)
- Март 2018 (1)
- Февраль 2018 (2)
- Январь 2018 (2)
- +2017 (19)
- Декабрь 2017 (2)
- Ноябрь 2017 (1)
- Октябрь 2017 (1)
- Сентябрь 2017 (2)
- Июль 2017 (1)
- Июнь 2017 (1)
- Май 2017 (2)
- Апрель 2017 (3)
- Март 2017 (2)
- Февраль 2017 (1)
- Январь 2017 (3)
- +2016 (36)
- Декабрь 2016 (3)
- Ноябрь 2016 (3)
- Октябрь 2016 (2)
- Сентябрь 2016 (3)
- Август 2016 (7)
- Июнь 2016 (3)
- Май 2016 (3)
- Апрель 2016 (3)
- Февраль 2016 (1)
- Январь 2016 (8)
- +2015 (36)
- Ноябрь 2015 (5)
- Октябрь 2015 (4)
- Сентябрь 2015 (1)
- Август 2015 (8)
- Июнь 2015 (1)
- Май 2015 (4)
- Апрель 2015 (8)
- Март 2015 (3)
- Февраль 2015 (2)
- +2014 (26)
- Ноябрь 2014 (2)
- Октябрь 2014 (5)
- Сентябрь 2014 (6)
- Июль 2014 (1)
- Июнь 2014 (2)
- Май 2014 (3)
- Апрель 2014 (6)
- Февраль 2014 (1)
- +2013 (27)
- Декабрь 2013 (2)
- Ноябрь 2013 (1)
- Октябрь 2013 (1)
- Август 2013 (1)
- Июль 2013 (3)
- Июнь 2013 (10)
- Май 2013 (1)
- Апрель 2013 (2)
- Февраль 2013 (3)
- Январь 2013 (3)
- +2012 (41)
- Декабрь 2012 (2)
- Ноябрь 2012 (3)
- Октябрь 2012 (7)
- Сентябрь 2012 (2)
- Август 2012 (1)
- Июль 2012 (3)
- Июнь 2012 (2)
- Май 2012 (6)
- Апрель 2012 (2)
- Март 2012 (7)
- Февраль 2012 (5)
- Январь 2012 (1)
- +2011 (57)
- Декабрь 2011 (6)
- Ноябрь 2011 (2)
- Октябрь 2011 (3)
- Сентябрь 2011 (5)
- Август 2011 (4)
- Июль 2011 (3)
- Июнь 2011 (3)
- Май 2011 (3)
- Апрель 2011 (4)
- Март 2011 (10)
- Февраль 2011 (5)
- Январь 2011 (9)
- +2010 (43)
- Декабрь 2010 (7)
- Ноябрь 2010 (21)
- Октябрь 2010 (14)
- Сентябрь 2010 (1)
Свежие записи
- Интеграция платежной системы MoonPay на сайт по API 10.11.2024
- Парсер товаров с Taobao 08.11.2024
- Упаковка и минификация кода JavaScript онлайн 07.11.2024
- Как эффективно анализировать логи при DDOS атаке 07.11.2024
- Бот для автоматических заказов на OZON (плагин для Chrome) 07.11.2024