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

Чтобы сразу расставить точки над i: всё здесь ограничено исключительно публичными страницами Facebook. Это означает публичное название страницы, видимый текст публичных постов и публичные агрегированные счётчики, которые страница или пост показывает любому посетителю. Это не касается закрытых групп, списков участников, личных профилей, контента за стеной входа, комментариев, привязанных к конкретным людям, или каких-либо персональных данных. Facebook и его родительская компания Meta ограничивают автоматизированный доступ в своих условиях, поэтому прочитайте раздел о законности ближе к концу, прежде чем направить это на что-либо реальное. Для производственного или коммерческого использования правильным инструментом является официальный Facebook Graph API, а не скрейпер.

Что вы создадите

Небольшой Python-скрипт, написанный и запущенный в PyCharm, который берёт URL публичной страницы Facebook, получает полностью отрендеренную страницу через Crawling API с JavaScript-токеном и парсит несколько публичных полей:

  • Публичное название страницы: название бренда или компании, отображаемое на странице.
  • Текст публичных постов: видимый текст тела публичных постов на странице.
  • Публичные счётчики: агрегированные числа, которые показывает публичная страница, например счётчик реакций или публикаций поста, трактуемые только как числа.
  • URL публичных постов: постоянная ссылка на каждый публичный пост.

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

Почему обычный запрос не работает с Facebook

Запросите URL публичной страницы Facebook с простым HTTP-клиентом и вы получите ответ, технически успешный и практически бесполезный. Тело будет JavaScript-оболочкой: реальный контент появляется только после того, как скрипты страницы выполнятся в браузере и запросят данные из внутренних эндпоинтов. Facebook является одной из самых сложных целей в публичном вебе именно по этой причине, и так обстоит дело уже много лет.

Кроме рендеринга, Facebook быстро помечает автоматизированный трафик. Диапазоны IP датацентров, отсутствие поведения браузера и повторяющиеся паттерны запросов вызывают проверку или ограничения частоты задолго до того, как интересный контент успевает загрузиться. Таким образом, работающий скрейпер требует двух вещей в одном запросе: реального браузера для рендеринга страницы и IP-адреса, который платформа воспринимает как обычного посетителя. Можно построить это самостоятельно с headless-браузером и пулом ротирующих резидентных прокси, но поддержка этого стека является большей частью работы. Crawling API объединяет оба в один вызов: вы отправляете ему URL с JavaScript-токеном, он рендерит страницу за доверенным резидентным IP и возвращает готовый HTML для парсинга. Для более глубокого понимания смотрите наше руководство по краулингу JavaScript-сайтов.

Зачем нужен JS-токен

Crawlbase предлагает два типа токенов. Обычный токен получает статический HTML; JavaScript (JS) токен сначала рендерит страницу в реальном браузере. Facebook рендерится на стороне клиента, поэтому здесь нужен JS-токен. Обычный токен возвращает ту же оболочку, что и обычный запрос, из которой нечего парсить.

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

Несколько вещей для начала. Ни одна не занимает много времени.

Базовый Python. Вы должны уметь запускать скрипты и устанавливать пакеты с помощью pip. Если вы новичок в парсинге HTML, наш primer по как скрейпить сайт с Python покрывает сторону извлечения данных.

Python 3.8 или новее. Проверьте командой python --version. Если его нет, установите с python.org. Устаревшая версия этого руководства использовала Python 2 и urllib2; оба уже не поддерживаются, поэтому данный переработанный вариант ориентирован на современный Python 3.

PyCharm. Загрузите бесплатный Community edition от JetBrains и установите. PyCharm является IDE, которую мы используем для создания проекта, установки пакетов и запуска скрипта.

Аккаунт Crawlbase и JS-токен. Зарегистрируйтесь, откройте дашборд и скопируйте JavaScript (JS) токен со страницы документации аккаунта. Обращайтесь с ним как с паролем: он аутентифицирует ваши запросы, поэтому не допускайте его попадания в систему контроля версий.

Настройка проекта в PyCharm

Это часть руководства, посвящённая PyCharm. Откройте PyCharm и выберите New Project. Назовите его что-нибудь вроде facebook-page-scraper, позвольте PyCharm создать виртуальное окружение (по умолчанию) и убедитесь, что интерпретатор Python 3.8 или новее. Нажмите Create. Затем щёлкните правой кнопкой мыши по проекту в панели Project, выберите New, Python File и назовите его scraper.py.

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

bash
python --version

pip install crawlbase beautifulsoup4

Две зависимости делают работу: crawlbase является официальным клиентом для Crawling API, а beautifulsoup4 парсит возвращённый HTML, позволяя вытаскивать отдельные поля по селектору. Если предпочитаете GUI, окно инструментов Python Packages в PyCharm устанавливает те же пакеты без обращения к терминалу.

Шаг 1: Получение отрендеренной страницы

Начните с получения готовой страницы. В scraper.py импортируйте CrawlingAPI, инициализируйте с вашим JS-токеном и запросите URL публичной страницы Facebook. Проверяйте статус-код перед парсингом, чтобы сбои оставались явными, а не молчаливыми.

python
from crawlbase import CrawlingAPI

api = CrawlingAPI({"token": "YOUR_CRAWLBASE_TOKEN"})

def crawl(page_url):
    options = {"ajax_wait": "true", "page_wait": 5000}
    response = api.get(page_url, options)
    if response["status_code"] == 200:
        return response["body"].decode("utf-8")
    print(f"Request failed: {response['status_code']}")
    return None

if __name__ == "__main__":
    page_url = "https://www.facebook.com/MetaForBusiness"
    html = crawl(page_url)
    print(html[:500] if html else "No HTML returned")

Запустите его из PyCharm: щёлкните правой кнопкой мыши в редакторе и выберите Run 'scraper' или нажмите зелёную стрелку запуска в gutter. Два параметра ожидания важны для клиент-рендеренной цели. ajax_wait говорит API дождаться окончания загрузки асинхронного контента, а page_wait держит фиксированное количество миллисекунд после загрузки, чтобы поздно рендерящиеся элементы появились перед захватом страницы. Пять секунд являются разумной отправной точкой; увеличивайте, если поля возвращаются пустыми. В примере используется публичная бизнес-страница именно потому, что она публична и безлична. В панели Run вы должны увидеть реальную разметку страницы, что подтверждает работу рендеринга до написания единого селектора.

Crawlbase Facebook Scraper

Facebook требует отрендеренной страницы за доверенным IP в одном вызове. Crawling API принимает JS-токен, запускает страницу в реальном браузере, ротирует через резидентные IP на стороне сервера и передаёт готовый HTML, так что вы минуете запуск флота headless-браузеров и пула прокси самостоятельно. Сначала направьте его на публичную бизнес-страницу на бесплатном тарифе.

Шаг 2: Парсинг публичных полей с BeautifulSoup

Имея готовый HTML, загрузите его в BeautifulSoup и извлеките публичные поля. Facebook раскрывает много стабильных метаданных в тегах <meta> страницы, что гораздо надёжнее, чем гоняться за глубоко вложенными, часто переименовываемыми CSS-классами. Публичное название страницы и описание находятся в стандартных тегах Open Graph meta; видимый текст публичных постов и постоянные ссылки на посты находятся в отрендеренном DOM.

python
from bs4 import BeautifulSoup

def meta(soup, prop):
    el = soup.find("meta", attrs={"property": prop})
    return el["content"] if el and el.has_attr("content") else None

def scrape_page(html):
    soup = BeautifulSoup(html, "html.parser")

    page_name = meta(soup, "og:title")
    summary = meta(soup, "og:description")

    post_urls = []
    for a in soup.select("a[href*='/posts/']"):
        href = a["href"].split("?")[0]
        if href.startswith("/"):
            href = f"https://www.facebook.com{href}"
        if href not in post_urls:
            post_urls.append(href)

    return {
        "page_name": page_name,
        "summary": summary,
        "post_urls": post_urls,
    }

Тег og:title содержит публичное название страницы, а og:description нередко содержит короткую публичную строку сводки. Ссылки на посты собираются из якорей, чей href содержит /posts/, очищаются от строк запроса, нормализуются до абсолютных URL и дедублируются, поскольку одна постоянная ссылка может встречаться в отрендеренном DOM несколько раз. Всё здесь является публичным, страничным сигналом, а не профилем какого-либо отдельного человека.

Селекторы меняются

Facebook меняет разметку и имена классов без предупреждения, поэтому этот код опирается на теги Open Graph meta и стабильную форму URL /posts/, а не на хрупкие вложенные классы. Когда поле возвращает None, заново проинспектируйте живую страницу в инструментах разработчика браузера и обновите селектор. Периодическое обслуживание нормально для любого производственного скрейпера, а не признак того, что что-то сломалось.

Шаг 3: Извлечение публичного текста и счётчиков из поста

Страница публичного поста содержит те же метаданные Open Graph плюс видимый текст публичного поста в отрендеренном DOM. Из неё можно извлечь текст публичного поста и любые публичные счётчики, которые показывает страница, например число реакций или публикаций. Читайте эти числа как простые агрегаты, никогда как способ перечислить стоящих за ними людей.

python
import re
from bs4 import BeautifulSoup

def scrape_post(html):
    soup = BeautifulSoup(html, "html.parser")

    desc = soup.find("meta", attrs={"property": "og:description"})
    post_text = desc["content"] if desc and desc.has_attr("content") else None

    counts = {}
    for label in ("reaction", "share"):
        node = soup.find("div", attrs={"aria-label": re.compile(label, re.I)})
        if node:
            digits = re.sub(r"[^\d]", "", node.get_text())
            counts[label] = int(digits) if digits else None

    return {
        "post_text": post_text,
        "counts": counts,
    }

Это извлекает только публичные, неперсональные поля: видимый текст поста и агрегированные счётчики, которые показывает страница. Оно не читает отдельные комментарии, идентификаторы комментаторов или то, кто реагировал на пост. Формы aria-label и селектора меняются со временем, поэтому заново инспектируйте их, когда поле перестаёт разрешаться. Эта сдержанность намеренна, и именно она делает работу защищаемой. Счётчики, это числа; люди за ними не ваши для сбора.

Шаг 4: Собрать всё вместе

Теперь свяжите получение и парсинг в один запускаемый скрипт, который читает публичную страницу, затем посещает её первые несколько публичных постов. Вставьте это поверх scraper.py и запустите из PyCharm.

python
import re
import json
import time
from crawlbase import CrawlingAPI
from bs4 import BeautifulSoup

api = CrawlingAPI({"token": "YOUR_CRAWLBASE_TOKEN"})

def crawl(page_url):
    options = {"ajax_wait": "true", "page_wait": 5000}
    response = api.get(page_url, options)
    if response["status_code"] == 200:
        return response["body"].decode("utf-8")
    print(f"Request failed: {response['status_code']}")
    return None

def main():
    page_url = "https://www.facebook.com/MetaForBusiness"
    html = crawl(page_url)
    if not html:
        return

    page = scrape_page(html)
    records = []
    for post_url in page["post_urls"][:5]:
        post_html = crawl(post_url)
        if post_html:
            record = scrape_post(post_html)
            record["url"] = post_url
            records.append(record)
        time.sleep(3)

    output = {"page_name": page["page_name"], "posts": records}
    print(json.dumps(output, indent=2, ensure_ascii=False))

if __name__ == "__main__":
    main()

time.sleep(3) между запросами не является украшением. Темп является единственным наиболее важным фактором того, останется ли запуск здоровым, и мы вернёмся к этому. Срез [:5] держит демо небольшим; увеличивайте его только тогда, когда ваш темп и объём ответственны. Держите функции scrape_page и scrape_post из предыдущих шагов в том же файле, чтобы этот скрипт запускался от начала до конца.

Как выглядит вывод

Запустите полный скрипт в PyCharm и получите чистую запись публичных полей, готовую для записи в JSON, CSV или базу данных.

json
{
  "page_name": "Meta for Business",
  "posts": [
    {
      "post_text": "New tools to help businesses reach customers.",
      "counts": { "reaction": 1820, "share": 214 },
      "url": "https://www.facebook.com/MetaForBusiness/posts/example123"
    }
  ]
}

Масштабирование и сохранение незаблокированности

Чтобы читать более одной страницы, оберните цикл краулинга по списку URL публичных страниц и записывайте каждый результат на диск по мере получения, чтобы сбой на полпути не потерял всё. Даже с обработкой рендеринга Crawling API Facebook следит за скрейперообразным трафиком. Несколько привычек помогают запуску оставаться здоровым, и они применимы к любой сложной, хорошо защищённой цели.

  • Соблюдайте темп запросов. Долбить страницы в тесном цикле, это самый быстрый способ получить ограничение. Добавляйте реальные задержки, как в time.sleep выше, и противьтесь искушению агрессивно распараллеливаться.
  • Опирайтесь на ротацию. Пул резидентных IP распределяет запросы по множеству реальных пользовательских адресов, чтобы ни один не вызвал ограничение частоты. Crawling API делает это за вас; если вы строите собственный стек, именно эту часть нужно сделать правильно.
  • Читайте статус-коды. Запуск, начавший возвращать вызовы или ошибки, говорит вам, что текущего темпа или уровня IP уже недостаточно. Отступите, а не давите сильнее.
  • Держите объём низким и цели разнообразными. Исследование публичных данных не требует краулинга всей истории страницы. Берите выборку того, что нужно, и останавливайтесь.

Для более широкого руководства смотрите нашу статью о как скрейпить сайты без блокировок. Если вызова управляемого рендеринга с ротацией недостаточно для вашего объёма и вы хотите автоматически распарсенный вывод страниц, наш более подробный разбор освоения извлечения данных Facebook с Crawling API покрывает путь структурированного вывода.

Законно ли скрейпить Facebook?

Это раздел, который нужно прочитать до написания производственного кода. Facebook принадлежит Meta, и Условия обслуживания Meta жёстко ограничивают автоматизированный доступ и сбор данных. Автоматизированный скрейпинг может нарушать эти условия независимо от того, насколько аккуратен ваш инструментарий, и ни один из приведённых выше кодов этого не меняет. Он только делает технически работающей часть. Читайте Условия обслуживания Meta и Facebook и robots.txt Facebook, соблюдайте ограничения частоты платформы и относитесь ко всему этому как к границе того, что вы собираете.

Честные, ограничительные правила, которым нужно следовать. Собирайте только публичные данные с публичных страниц: публичное название страницы, видимый текст публичных постов, публичные агрегированные счётчики и URL публичных постов, которые любой может видеть без входа в систему. Никогда не скрейпите закрытые группы, списки участников групп, личные профили, контент за стеной входа, личные сообщения, комментарии, привязанные к конкретным людям, или какие-либо персональные данные. Устаревшая версия этого руководства указывала на группы Facebook; это именно та поверхность, которую данный переработанный вариант избегает, поскольку контент групп и данные участников являются персональными и нередко находятся за защитой приватности. Никогда не обходите аутентификацию, программно не решайте задачу входа и не используйте чужие учётные данные для доступа к контенту. Это красные линии, и данное руководство по дизайну остаётся на публичной стороне всех из них.

Когда задействованы персональные данные, применяется закон о конфиденциальности. В рамках GDPR в ЕС и CCPA в Калифорнии вам нужно правовое основание для обработки персональных данных и вы должны выполнять запросы об удалении и отказе. Самая безопасная позиция, полностью избегать персональных данных и ограничиваться агрегатами публичного уровня страницы, что и делает приведённый выше скрипт. Для любого реального или коммерческого использования правильным инструментом является официальный Facebook Graph API. Он создан для санкционированного доступа к страницам, которыми вы владеете или управляете, даёт гарантированную структуру и держит вас в рамках условий Meta. Эта статья является техническим руководством, строго ограниченным публичными страницами. Это не одобрение массового сбора персональных данных, и оно не охватывает ничего за логином. Если ваш проект требует большего, чем небольшой образец публичных полей, Graph API или формальное соглашение о данных является правильным путём, а не более умный скрейпер.

Итоги

Ключевые выводы

  • Только публичные страницы. Данное руководство нацелено на публичные страницы Facebook, никогда на закрытые группы, данные участников или личные профили.
  • Facebook рендерится на стороне клиента и защищён от ботов. Обычный запрос возвращает пустую оболочку, поэтому перед парсингом страницу необходимо отрендерить.
  • PyCharm берёт на себя настройку. Создайте проект и его виртуальное окружение, установите crawlbase и beautifulsoup4 и запустите скрипт из IDE.
  • Рендеринг и доверенный IP должны быть в одном вызове. Crawling API с JS-токеном делает и то и другое; ajax_wait и page_wait контролируют, как долго ждать контента.
  • Соблюдайте темп, ротируйте и предпочитайте Graph API. Держите объём низким, опирайтесь на резидентную ротацию, учитывайте GDPR и CCPA и используйте официальный Facebook Graph API для всего реального или коммерческого.

Часто задаваемые вопросы

Почему обычный запрос не возвращает данные из Facebook?

Потому что Facebook рендерит контент своих страниц и постов на стороне клиента с помощью JavaScript. Исходный HTML является оболочкой, которая заполняется только после того, как скрипты страницы выполнятся в браузере, поэтому сырой HTTP-запрос возвращает почти пустое тело. Чтобы получить реальные публичные данные, необходимо сначала отрендерить страницу, что и делает JS-токен Crawling API за вас.

Нужен ли мне обычный токен или JS-токен для Facebook?

JS-токен. Обычный токен получает статический HTML, который на Facebook является той же пустой оболочкой, что и обычный запрос. JS-токен рендерит страницу в реальном браузере перед передачей HTML, поэтому публичные поля присутствуют при их парсинге BeautifulSoup.

Какие данные Facebook безопасно скрейпить?

Только публичные данные с публичных страниц: публичное название страницы, видимый текст публичных постов, публичные агрегированные счётчики в виде чисел и URL публичных постов. Закрытые группы, списки участников групп, личные профили, контент за стеной входа, личные сообщения и удостоверения личности отдельных комментаторов недопустимы. Это персональные данные, и их сбор нарушает условия Meta и во многих юрисдикциях является нарушением закона о конфиденциальности.

Почему это руководство охватывает страницы, а не группы?

Потому что публичные страницы являются защищаемой поверхностью. Контент групп, списки участников и посты отдельных участников являются персональными данными и нередко находятся за защитой приватности, даже для групп с пометкой «публичная». Бренд- и бизнес-страницы созданы для того, чтобы их видел каждый без входа в систему, поэтому чтение их публичного названия страницы, текста постов и агрегированных счётчиков остаётся в пределах публичной границы.

Стоит ли использовать официальный Facebook Graph API или скрейпить сайт?

Для любого реального, постоянного или коммерческого использования используйте официальный Facebook Graph API. Это санкционированный путь, он даёт гарантированную структуру и держит вас в рамках условий Meta. Скрейпинг небольшой выборки полей публичных страниц описанным здесь подходом подходит для лёгкого исследования публичных данных, где нет доступа к API, при условии соблюдения условий, robots.txt и ограничений частоты.

Как избежать блокировки при скрейпинге Facebook?

Держите частоту запросов на IP низкой, добавляйте реальные задержки между запросами, варьируйте цели вместо краулинга всей истории одной страницы и маршрутизируйте через ротирующие резидентные IP, чтобы ни один адрес не превышал ограничения частоты. Crawling API управляет ротацией и доверенным пулом IP за вас. Следите за статус-кодами и немедленно отступайте, как только начинаете получать вызовы.

Начать создавать

Обходите любой сайт в масштабе, без борьбы с инфраструктурой.

Crawlbase берёт на себя прокси, отпечатки и CAPTCHA, чтобы ваша команда выпускала конвейеры данных вместо поддержки обвязки краулинга. 1 000 запросов бесплатно, без карты.

Самообслуживание · Звонок отдела продаж не требуется · Доступны корпоративные объёмы краулинга