Исследовательский парсер соцсетей ломается не на разборе HTML, а на странице проверки: вместо профиля приходит форма reCAPTCHA v2 или виджет Cloudflare Turnstile, и сбор стоит, пока задачу не решат руками. Эта часть автоматизируется целиком: сборщик распознаёт разметку проверки, отправляет sitekey и pageurl в API CaptchaAI, получает токен и продолжает в той же сессии. Ниже — как устроен такой цикл на Python, где платформы включают проверку и какие лимиты частоты держать.
Речь идёт о публичных данных: открытые профили, посты по хэштегу, упоминания бренда в открытом поиске. Всё, что закрыто авторизацией чужого аккаунта, остаётся за рамками руководства.
Правовая рамка: что попадает в выборку
Для команд в России, Казахстане и Беларуси один ориентир стоит зафиксировать до первой строки кода. Если в выгрузке оказываются имена, ники, фото и контакты — это персональные данные, и на них распространяется 152-ФЗ «О персональных данных» и его аналоги в соседних юрисдикциях; в трансграничном проекте добавляется дисциплина уровня GDPR. Собирайте только поля, нужные для проверяемой гипотезы, и агрегируйте их на входе. Это не юридическая консультация, а базовая гигиена проекта.
Второй слой — правила площадки. Условия использования и robots.txt не заменяют закон, но очерчивают допустимый сбор. Если у площадки есть официальный API с нужными полями, берите API. Парсер с решением CAPTCHA оправдан там, где данные публичны, но интерфейса к ним нет.
Где платформы включают проверку
Проверка редко срабатывает случайно: она привязана к конкретным точкам — вход, повторяющийся поиск, серия обращений к профилям с одного адреса.
| Платформа | Тип проверки | Когда срабатывает | Контекст |
|---|---|---|---|
| reCAPTCHA v2 | Вход, поиск, доступ к профилю | Ограничение частоты запросов | |
| reCAPTCHA v2 | Вход, повторяющиеся поиски | Контрольная точка безопасности | |
| Twitter/X | Cloudflare Turnstile | Вход, доступ к API | Фильтрация ботов |
| TikTok | reCAPTCHA v3 | Просмотр профилей, поиск | Оценка качества трафика |
| Cloudflare Challenge | Сбор данных профиля | Обнаружение ботов | |
| reCAPTCHA v2 | Вход, интенсивный просмотр | Защита от злоупотреблений |
Все перечисленные типы CaptchaAI решает: reCAPTCHA v2 и v3, Cloudflare Turnstile и Challenge, а также GeeTest v3, image/OCR и grid. Чего сервис не решает — hCaptcha и FunCaptcha (Arkose Labs); GeeTest v4 заявлен как «скоро» и пока недоступен. Если площадка стоит на одном из этих трёх типов, планируйте исследование через её официальный API.
Цикл решения: in.php → res.php
Схема одинакова для всех типов и отличается только значением method. Сборщик отправляет POST на in.php с параметрами key, method, googlekey (это sitekey страницы) и pageurl, получает ID задачи и опрашивает res.php, пока вместо CAPCHA_NOT_READY не придёт токен. Токен подставляется в поле формы: g-recaptcha-response для reCAPTCHA, cf-turnstile-response для Turnstile. Класс ниже собирает это в один объект: сессия requests, детектор проверки и обработчик, который сам выбирает method.
import requests
import time
import re
CAPTCHAAI_KEY = "YOUR_API_KEY"
CAPTCHAAI_URL = "https://ocr.captchaai.com"
def solve_captcha(method, sitekey, pageurl, **kwargs):
data = {
"key": CAPTCHAAI_KEY,
"method": method,
"googlekey": sitekey,
"pageurl": pageurl,
"json": 1,
}
data.update(kwargs)
resp = requests.post(f"{CAPTCHAAI_URL}/in.php", data=data)
task_id = resp.json()["request"]
for _ in range(60):
time.sleep(5)
result = requests.get(f"{CAPTCHAAI_URL}/res.php", params={
"key": CAPTCHAAI_KEY, "action": "get",
"id": task_id, "json": 1,
})
r = result.json()
if r["request"] != "CAPCHA_NOT_READY":
return r["request"]
raise TimeoutError("Solve timeout")
class SocialMediaResearcher:
def __init__(self, proxy=None):
self.session = requests.Session()
if proxy:
self.session.proxies = {"http": proxy, "https": proxy}
self.session.headers.update({
"User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 17_5 like Mac OS X) "
"AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 "
"Mobile/15E148 Safari/604.1",
"Accept-Language": "en-US,en;q=0.9",
})
def authenticate(self, login_url, credentials, sitekey):
"""Login with CAPTCHA handling."""
# Load login page
self.session.get(login_url)
# Solve CAPTCHA
token = solve_captcha("userrecaptcha", sitekey, login_url)
# Submit login
resp = self.session.post(login_url, data={
**credentials,
"g-recaptcha-response": token,
})
return resp.status_code == 200
def collect_profiles(self, profile_urls):
"""Collect public profile data with CAPTCHA handling."""
profiles = []
for url in profile_urls:
try:
resp = self.session.get(url, timeout=30)
# Handle CAPTCHA if triggered
if self._has_captcha(resp.text):
resp = self._handle_captcha(resp.text, url)
profiles.append({
"url": url,
"data": self._parse_profile(resp.text),
"status": "success",
})
time.sleep(5) # Slow down between profiles
except Exception as e:
profiles.append({
"url": url,
"error": str(e),
"status": "failed",
})
return profiles
def _has_captcha(self, html):
return any(tag in html.lower() for tag in [
'data-sitekey', 'g-recaptcha', 'cf-turnstile',
'challenge-platform', 'captcha',
])
def _handle_captcha(self, html, url):
match = re.search(r'data-sitekey="([^"]+)"', html)
if not match:
return self.session.get(url)
sitekey = match.group(1)
if 'cf-turnstile' in html:
token = solve_captcha("turnstile", sitekey, url)
return self.session.post(url, data={"cf-turnstile-response": token})
else:
token = solve_captcha("userrecaptcha", sitekey, url)
return self.session.post(url, data={"g-recaptcha-response": token})
def _parse_profile(self, html):
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, "html.parser")
return {
"name": self._safe_text(soup, "h1, .profile-name"),
"bio": self._safe_text(soup, ".bio, .profile-bio"),
"followers": self._safe_text(soup, "[data-followers], .followers"),
"posts": self._safe_text(soup, "[data-posts], .posts-count"),
}
def _safe_text(self, soup, selector):
el = soup.select_one(selector)
return el.get_text(strip=True) if el else ""
Две детали здесь пропускают чаще всего. Первая: токен живёт ограниченное время — форму отправляют сразу после ответа, а не накапливают токены заранее. Вторая: _has_captcha смотрит на текст ответа, а не на код состояния, потому что страницу проверки обычно отдают со статусом 200, и наивная проверка resp.status_code == 200 засчитает её как успех.
Сценарий 1: исследование хэштега
Типовая задача для агентства в Алматы или продуктовой команды в Минске — собрать публичные посты по нескольким хэштегам и посчитать распределение тональности. Постраничный обход упрётся в проверку уже на третьей-четвёртой странице, поэтому обработчик подключается прямо в цикле.
def research_hashtag(hashtag, platform_url, pages=5):
"""Collect posts for a specific hashtag."""
researcher = SocialMediaResearcher(
proxy="http://user:[email protected]:5000"
)
all_posts = []
for page in range(pages):
url = f"{platform_url}/explore/tags/{hashtag}?page={page}"
resp = researcher.session.get(url, timeout=30)
if researcher._has_captcha(resp.text):
resp = researcher._handle_captcha(resp.text, url)
from bs4 import BeautifulSoup
soup = BeautifulSoup(resp.text, "html.parser")
posts = soup.select(".post-item, article")
for post in posts:
all_posts.append({
"text": post.get_text(strip=True)[:500],
"hashtag": hashtag,
"page": page,
})
time.sleep(5)
return all_posts
Пауза в пять секунд не декоративная: она удерживает частоту в диапазоне, при котором проверка срабатывает реже, и снижает расход потоков.
Сценарий 2: ежедневный мониторинг упоминаний бренда
Второй частый случай — регулярный прогон по нескольким площадкам с набором ключевых слов и сводкой в JSON. Важна не скорость, а то, что ночное задание доходит до конца без ручного вмешательства.
import json
from datetime import datetime
class BrandMonitor:
def __init__(self, brand_name, keywords, proxy=None):
self.brand = brand_name
self.keywords = keywords
self.researcher = SocialMediaResearcher(proxy=proxy)
def daily_scan(self, platform_urls):
"""Run daily brand mention scan across platforms."""
report = {
"brand": self.brand,
"date": datetime.now().isoformat(),
"platforms": {},
}
for name, url in platform_urls.items():
mentions = []
for keyword in self.keywords:
search_url = f"{url}/search?q={keyword}"
try:
resp = self.researcher.session.get(search_url, timeout=30)
if self.researcher._has_captcha(resp.text):
resp = self.researcher._handle_captcha(
resp.text, search_url,
)
from bs4 import BeautifulSoup
soup = BeautifulSoup(resp.text, "html.parser")
results = soup.select(".search-result, .post")
mentions.append({
"keyword": keyword,
"count": len(results),
})
time.sleep(5)
except Exception as e:
mentions.append({
"keyword": keyword,
"error": str(e),
})
report["platforms"][name] = mentions
return report
# Usage
monitor = BrandMonitor(
brand_name="CaptchaAI",
keywords=["captchaai", "captcha ai", "captcha solver"],
proxy="http://user:[email protected]:5000",
)
report = monitor.daily_scan({
"twitter": "https://twitter-alternative.example.com",
"reddit": "https://www.reddit.com",
})
print(json.dumps(report, indent=2))
Сводка складывается в один отчёт, а ошибка по одному ключевому слову не роняет прогон — для ежедневного расписания это принципиально.
Частота запросов и объём потоков
Ориентиры ниже — рабочая отправная точка: пороги площадки меняют без предупреждения, поэтому держите их в конфиге, а не в коде.
| Платформа | Частота запросов | Длительность сеанса |
|---|---|---|
| 1/10 с | до 5 мин, затем пауза | |
| 1/5 с | до 10 мин | |
| Twitter/X | 1/3 с | до 15 мин |
| TikTok | 1/5 с | до 5 мин |
| 1/10 с | до 5 мин | |
| 1/2 с | до 30 мин |
Сколько потоков заказывать? Поток в CaptchaAI — это одна задача в работе; после решения он сразу берёт следующую, а число решений внутри тарифа не ограничено. При частоте порядка одного запроса в 5 с и проверке примерно на каждом двадцатом обращении последовательному сборщику хватает BASIC ($15/мес, 5 потоков). Конвейер на 6–8 параллельных площадок укладывается в STANDARD ($30/мес, 15 потоков), ночной прогон по большому списку профилей — в ADVANCE ($90/мес, 50 потоков). Для команд, выставляющих счета в волатильной валюте, плоский месячный платёж в USD удобнее оплаты за каждое решение: бюджет известен заранее.
Что ломается чаще всего
| Симптом | Причина | Что делать |
|---|---|---|
| Проверка на каждом запросе | Адрес помечен как источник нагрузки | Снизьте частоту, используйте авторизованный сетевой выход |
| Пустая страница вместо профиля | Контент доступен только после входа | Проверьте публичность данных; если нет — исключите из выборки |
| Зацикленная проверка Cloudflare | Несогласованные сигналы клиента | Работайте через реальный браузер (Puppeteer, Playwright) |
| Токен не принимается формой | Просрочен или не в том поле | Отправляйте форму сразу, проверьте имя поля |
| Ответ не совпадает с браузером | Разница по региону и cookie | Сопоставьте регион выхода с аудиторией |
CAPCHA_NOT_READY дольше минуты |
Опрос идёт без пауз | Опрашивайте res.php с интервалом 5 с |
Часто задаваемые вопросы
Сколько потоков нужно исследовательскому парсеру соцсетей?
Считайте по числу одновременных задач, а не по объёму данных. Последовательный сборщик редко выходит за 5 потоков BASIC; несколько площадок параллельно — уровень STANDARD (15 потоков). Решения внутри тарифа не лимитированы, поэтому пересчитывать бюджет при росте выборки не придётся.
Какие типы проверок остаются вне зоны покрытия?
hCaptcha и FunCaptcha (Arkose Labs) CaptchaAI не поддерживает, GeeTest v4 заявлен как «скоро». Поддерживаются reCAPTCHA v2/v3, Cloudflare Turnstile и Challenge, GeeTest v3, image/OCR и grid; CaptchaFox (beta), Friendly Captcha (beta) и Lemin (beta) — в бета-статусе.
Почему проверка возвращается, хотя токен приняли?
Токен закрывает конкретную задачу, а не сессию целиком. Если проверка появляется снова через несколько запросов, причина в частоте обращений: увеличьте паузу и сократите длительность сеанса по таблице выше.
Что делать, если нужные данные закрыты авторизацией?
Считать их вне выборки. Автоматический вход в чужие аккаунты и заведение учётных записей ради снятия лимитов — не исследовательский сценарий. Публичные данные плюс официальный API площадки почти всегда закрывают реальную гипотезу.
Можно ли обойтись без прокси?
Часто да — если частота умеренная и сбор идёт с авторизованного сетевого выхода вашей организации. В исследовательском контуре прокси решают задачу географии: посмотреть публичную выдачу глазами нужного региона.
Связанные руководства
- Сетевой выход и частота запросов при решении CAPTCHA
- Сохранение состояния сессии браузера
- Изоляция браузерных профилей в связке с CaptchaAI
Соберите публичные данные соцсетей без ручных остановок — получите API-ключ CaptchaAI и подключите решение проверки в парсер.