CoderCastrov logo
CoderCastrov
Парсер

Facebook парсер бот с использованием Node JS и Mongo DB

Facebook парсер бот с использованием Node JS и Mongo DB
просмотров
5 мин чтение
#Парсер
Table Of Content

    Я работаю над приложением, которое должно отображать ленты Facebook на основе тематических каналов с использованием конечных точек Facebook oEmbed, которые позволяют находить, фильтровать и взаимодействовать с клиентами в социальных сетях. Конечные точки Facebook oEmbed позволяют получать встроенный HTML и основные метаданные для страниц, постов и видео, чтобы отображать их на другом веб-сайте или в приложении. Поскольку официальная документация API Facebook устарела для получения последних медиа, включая содержимое ленты, URL, время создания, количество лайков/комментариев и количество репостов для лент, я разработал парсер Facebook для извлечения этой информации. Здесь я собираюсь реализовать свое решение, используя Node JS puppeteer в качестве инструмента автоматизации и Mongo DB для хранения собранных данных ленты.

    Puppeteer - это библиотека для Node JS, которая предоставляет высокоуровневый API для управления Chrome или Chromium, и большинство вещей, которые мы можем делать вручную в браузере, могут быть сделаны с помощью puppeteer.

    Существует много сторонних библиотек, которые я исследовал, но они имеют ограничения, поскольку платформа Facebook обновляет свои CSS-стили и классы, и мы не можем использовать динамически генерируемые стили классов для стабильного решения парсинга. Поэтому не рекомендуется полагаться на стороннее решение, потому что мы не можем гарантировать, что оно будет работать с последними обновлениями Facebook. Поэтому я разработал собственную обертку Facebook, используя Node JS. Ниже я пошагово объясню мою реализацию.

    Итак, приступим.

    Предварительные требования:

    • Базовое знание Node JS

    Шаг 01:

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

    Шаг 02:

    На этом шаге я добавил некоторые общие конфигурационные сообщения в отдельный файл, как показано ниже.

    Здесь мы добавим loginFacebook(), который посещает веб-сайт Facebook, ожидает, пока сеть не будет простаивать, и ожидает появления интерфейса входа, а затем выполняет действие входа, как показано ниже.

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

    Здесь я выбираю элементы пользовательского интерфейса, оценивая внутренний HTML, потому что селекторы меняются случайным образом в Facebook.

    Шаг 03:

    На этом шаге мы начнем парсинг на основе тегов фильтра, таких как @упоминания/ключевые слова/хэштеги. Поэтому мой следующий шаг будет перейти на страницу Facebook на основе тега фильтра, как показано ниже. Я настроил базовый URL в файле конфигурации.

    const page_url = config.base_url + filter_tag;await this.page.goto(page_url, {waitUntil: "networkidle2",});

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

    Шаг 04:

    Затем, если страница Facebook доступна для соответствующего тега фильтра, я буду прокручивать страницу и отображать ленты в содержимом DOM, как показано ниже. Здесь мы можем настроить количество постов для парсинга, используя параметр post_count. Я определил, что один пост обернут в тег div[role="article"]. Поэтому я собираюсь подсчитать количество тегов div[role="article"], отображаемых в содержимом DOM, прокручивая страницу.

    Шаг 05:

    Мой следующий шаг - определить посты для извлечения, потому что на предыдущем шаге мы завершили логику прокрутки на основе тега div[role="article"], но я определил, что он также содержит некоторое другое текстовое содержимое. Поэтому нам нужно отфильтровать это. Здесь в качестве уникального элемента я определил, что если это пост для извлечения, его ariaLabel имеет значение null. Основываясь на этом, я собираюсь добавить фильтр, как показано ниже, и для каждого поста я собираюсь возвращать текстовое содержимое и внутренний HTML.

    Шаг 06:

    В качестве следующего шага я собираюсь перебрать список фильтров и извлечь содержимое поста, количество реакций, количество репостов и количество комментариев, а также время создания поста. Для извлечения этих значений необходимо разобрать внутренний HTML поста с помощью парсера HTML и получить корневой HTML, как показано ниже. Для этого я использовал node-html-parser, который генерирует упрощенное дерево DOM с поддержкой запросов элементов.

    import { parse } from “node-html-parser”;const root_html = parse(filtered_list[i].html);

    Извлечение содержимого поста:

    Извлечение количества комментариев:

    Извлечение количества реакций:

    Извлечение количества репостов:

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

    Извлечение времени создания поста:

    Здесь платформа Facebook не позволяет нам парсить время напрямую из содержимого DOM. Они упорядочили каждый элемент в строке времени с использованием тегов стилей. Поэтому нам нужно пройти по тегам span и найти стиль этих элементов, чтобы найти их порядок. Затем в моей логике я добавил эти элементы в массив, используя порядок стиля в качестве индекса массива. Затем я определил, что есть стиль классов {display:none;}, которые внедрены в эти элементы с порядком стиля. Поэтому мне нужно пропустить эти элементы, как показано ниже.

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

    И после этого я могу создать время создания поста для сохранения в БД, как показано ниже.

    const ymd_timestamp = moment.unix(timestamp / 1000).format(config.date_time_format);

    Шаг 07:

    В качестве следующего шага мне нужно извлечь URL поста, чтобы отобразить ленты Facebook в веб-приложении с использованием Facebook oEmbed, как показано ниже. Из действий поста я собираюсь извлечь встроенный код oEmbed и с помощью этой строки я собираюсь извлечь URL и идентификатор поста, как показано ниже.

    Шаг 08:

    В качестве последнего шага я собираюсь обновить Mongo DB с извлеченной записью ленты Facebook в следующем формате.

    let dataObj = {post_id: post_id,post_text: post_text,screen_name: filter_tag,post_created_at: ymd_timestamp,attributes: {share_count: share_count,comment_count: comment_count,reaction_count: reaction_count,page_link: page_url,link: post_url,},time_stamp: Math.round(new Date().getTime() / 1000),};

    В этом решении есть ограничения:

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

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

    Спасибо за чтение!