Looking for international version of our service? Go to 2captcha.com

Логотип «RuCaptcha»Перейти на главную страницу
Туториалы по обходу капчи

Эта статья была полезной?

Как обойти FunCaptcha (Arkose Labs) с помощью Playwright

Джерри Слиман
Джерри Слиман

Технический специалист

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

В этом руководстве мы разберём полный цикл обхода FunCaptcha в Playwright на Python: извлечём публичный ключ со страницы, получим решённый токен через API RuCaptcha и запишем его в поле, которое проверяет форма.

Что понадобится

  • Python 3.7 или выше
  • Установленный Playwright
  • Аккаунт и API-ключ от RuCaptcha
  • URL целевой страницы
  • Опционально: прокси, если целевой сайт блокирует запросы с IP-адресов дата-центров

Шаг 1. Установка зависимостей

Установите необходимые библиотеки и браузеры Playwright:

bash Copy
pip install playwright 2captcha-python
playwright install chromium

Шаг 2. Инициализация браузера и переход на страницу

Для отладки всегда начинайте с видимого режима headless=False. Это позволит визуально контролировать процесс появления виджета и внедрения токена.

python Copy
from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.launch(headless=False)
    page = browser.new_page()

    # Переход на целевую страницу
    page.goto("https://mysite.com/page/with/funcaptcha")

Шаг 3. Извлечение публичного ключа

Публичный ключ сайта находится в одном из двух мест. Основное — атрибут data-pkey у элемента div с виджетом. Запасное — поле fc-token: в его значении ключ идёт после pk, а адрес сервиса после surl.

python Copy
import re

widget = page.locator("[data-pkey]").first
surl = None

if widget.count() > 0:
    pkey = widget.get_attribute("data-pkey")
else:
    fc_token = page.locator('[name="fc-token"]').first.get_attribute("value")

    pk_match = re.search(r"pk=([^|]+)", fc_token)
    if not pk_match:
        raise RuntimeError("В значении fc-token нет параметра pk")
    pkey = pk_match.group(1)

    surl_match = re.search(r"surl=([^|]+)", fc_token)
    surl = surl_match.group(1) if surl_match else None

page_url = page.url

print(f"Публичный ключ: {pkey}")

Важно: проверка count() здесь обязательна. Без неё вызов get_attribute на отсутствующем элементе завершится не пустым значением, а таймаутом, и до запасного способа выполнение не дойдёт. По той же причине у обоих локаторов стоит .first: локаторы Playwright работают в строгом режиме и на двух совпадениях выдают ошибку вместо первого элемента.

Адрес сервиса в fc-token записан со схемой, и SDK ждёт значение именно в таком виде.

Шаг 4. Отправка задачи в API и получение токена

Самый простой способ — использовать официальный Python SDK. Он автоматически создаёт задачу и опрашивает сервер до получения результата.

python Copy
import os

from twocaptcha import TwoCaptcha

api_key = os.getenv('APIKEY_RUCAPTCHA', 'ВАШ_API_КЛЮЧ')

solver = TwoCaptcha(api_key, server='rucaptcha.com')

result = solver.funcaptcha(
    sitekey=pkey,
    url=page_url,
    surl=surl or 'https://client-api.arkoselabs.com'
)

token = result['code']
print(f"Токен получен: {token[:20]}...")

Параметр surl — адрес сервиса, с которого загружается виджет. Необязательный: если его не передать, используется значение по умолчанию, которое подходит в большинстве случаев. Передавать всё равно рекомендуется.

Некоторым сайтам нужен ещё один параметр — blob. Как найти его на странице и убедиться, что он верный, разобрано в отдельной статье: Как найти и проверить параметр blob. Если сайт использует blob, передайте в задачу то же значение, что ушло в виджет. Значение действует ограниченное время, новое получают перезагрузкой страницы.

python Copy
result = solver.funcaptcha(
    sitekey=pkey,
    url=page_url,
    surl='https://client-api.arkoselabs.com',
    userAgent='Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36',
    proxy={'type': 'HTTPS', 'uri': 'login:[email protected]:8080'},
    **{'data[blob]': 'BLOB_DATA_VALUE'}
)

Альтернатива (прямой HTTP-запрос):
Если вы не используете SDK, отправьте запрос напрямую через curl или библиотеку requests. Форма записи там другая: адрес сервиса передаётся полем funcaptchaApiJSSubdomain без схемы, а blob — полем data строкой JSON.

bash Copy
curl -X POST https://api.rucaptcha.com/createTask \
  -H "Content-Type: application/json" \
  -d '{
    "clientKey": "ВАШ_API_КЛЮЧ",
    "task": {
      "type": "FunCaptchaTaskProxyless",
      "websiteURL": "https://mysite.com/page/with/funcaptcha",
      "websitePublicKey": "6220FF23-9856-3A6F-9FF1-A14F88123F55",
      "funcaptchaApiJSSubdomain": "client-api.arkoselabs.com",
      "data": "{\"blob\":\"BLOB_DATA_VALUE\"}"
    }
  }'

Если сайт требует привязки к конкретному IP, используйте тип задачи FunCaptchaTask и добавьте параметры прокси: proxyType, proxyAddress, proxyPort, proxyLogin, proxyPassword.

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

Проверяются при этом именно параметры. Капча открылась в приложении — websiteURL, публичный ключ и blob найдены верно. Не открылась — ошибка в одном из них, например устарел blob или взят не тот публичный ключ. Режим включается в настройках аккаунта и доступен после первого пополнения. После проверки его нужно выключить, иначе новые задачи так и будут приходить вам, а не работникам. Подробнее на странице Отладка.

Шаг 5. Внедрение токена в страницу (Критический этап)

Токен записывают в поле fc-token. Проверяйте несколько вариантов, как в примере ниже.

Токен приходит длинной строкой со знаками |, = и %, поэтому передавайте его в страницу аргументом функции, а не подстановкой в текст скрипта: склейка строки способна сломать сам скрипт.

python Copy
page.evaluate("""(token) => {
    const field = document.querySelector('[name="fc-token"]')
        || document.querySelector('#fc-token');
    if (!field) {
        throw new Error('Поле fc-token на странице не найдено');
    }
    field.value = token;
}""", token)

Ошибка в этой функции нужна. Без неё скрипт молча пропустит запись, отправит форму с пустым полем и напечатает, что всё прошло успешно.

Кроме того, часть сайтов использует callback-функцию, которая срабатывает при успешном решении и разблокирует кнопку отправки. Её имя зависит от сайта, ищите его в коде страницы и вызывайте через page.evaluate тем же способом.

Шаг 6. Отправка формы

После успешного внедрения токена форма должна считать себя валидной. Селектор кнопки подставьте свой: button[type='submit'] подходит не всякой форме.

python Copy
page.click("button[type='submit']")
page.wait_for_load_state("networkidle")

browser.close()

Результат решения стоит подтверждать: в SDK для этого существует метод report, а в API — методы reportCorrect и reportIncorrect. Идентификатор задачи лежит в том же ответе, что и токен: solver.report(result['captchaId'], True).

Полный рабочий пример (Python)

python Copy
import os
import re

from playwright.sync_api import sync_playwright
from twocaptcha import TwoCaptcha

API_KEY = os.getenv('APIKEY_RUCAPTCHA', 'ВАШ_API_КЛЮЧ')
TARGET_URL = "https://mysite.com/page/with/funcaptcha"


def solve_funcaptcha():
    solver = TwoCaptcha(API_KEY, server='rucaptcha.com')

    with sync_playwright() as p:
        browser = p.chromium.launch(headless=False)
        page = browser.new_page()

        try:
            page.goto(TARGET_URL)

            # 1. Извлекаем публичный ключ и адрес сервиса
            widget = page.locator("[data-pkey]").first
            surl = None

            if widget.count() > 0:
                pkey = widget.get_attribute("data-pkey")
            else:
                fc_token = page.locator('[name="fc-token"]').first.get_attribute("value")

                pk_match = re.search(r"pk=([^|]+)", fc_token)
                if not pk_match:
                    raise RuntimeError("В значении fc-token нет параметра pk")
                pkey = pk_match.group(1)

                surl_match = re.search(r"surl=([^|]+)", fc_token)
                surl = surl_match.group(1) if surl_match else None

            print(f"Публичный ключ: {pkey}")

            # 2. Решаем капчу через API
            print("Отправка задачи в API...")
            result = solver.funcaptcha(
                sitekey=pkey,
                url=TARGET_URL,
                surl=surl or 'https://client-api.arkoselabs.com'
            )
            token = result['code']
            print("Токен получен!")

            # 3. Внедряем токен в поле fc-token
            page.evaluate("""(token) => {
                const field = document.querySelector('[name="fc-token"]')
        || document.querySelector('#fc-token');
                if (!field) {
                    throw new Error('Поле fc-token на странице не найдено');
                }
                field.value = token;
            }""", token)

            # 4. Отправляем форму
            page.click("button[type='submit']")
            page.wait_for_load_state("networkidle")

            print("Форма отправлена.")
            page.wait_for_timeout(3000)  # Пауза для визуальной проверки

        except Exception as e:
            print(f"Ошибка: {e}")
        finally:
            browser.close()


if __name__ == "__main__":
    solve_funcaptcha()

Решение частых проблем

  • Публичный ключ не находится (возвращает пустое значение): атрибута data-pkey в разметке нет. Возьмите ключ из значения поля fc-token, как показано в Шаге 3.
  • Скрипт не находит элемент капчи: виджет может находиться внутри iframe. Обращайтесь к нему через page.frame_locator.
  • Задача создана, но решение не приходит: возможно, сайту требуется blob, а он не передан или устарел. Перезагрузите страницу и возьмите новое значение.
  • Токен записан, но форма не принимает его: сайт проверяет решение своим обработчиком, а не только содержимым поля. Найдите этот обработчик в коде страницы и вызовите его через page.evaluate, как показано в Шаге 5.

Остальные коды ошибок перечислены на странице «Коды ошибок», ссылка в конце.

Заключение

Главная сложность этой капчи в том, что её задание нельзя разобрать программно: сервис показывает интерактивную сцену, а не текст или сетку картинок. Метод FunCaptcha снимает эту сложность целиком — задание решает работник, а вашему коду остаются три действия.

Найти публичный ключ, дождаться токена и записать его в поле fc-token. Из них внимания требует последнее: запись должна проверяться, иначе пустое поле уходит вместе с формой незаметно для скрипта.

Отправляйте отчёты методами reportCorrect и reportIncorrect: по ним сервис определяет, какие решения не подошли.

Полезные ссылки