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

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

Как обойти амазон капчу на portal-nc.tylertech.cloud

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

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

portal-nc.tylertech.cloud — портал судов Северной Каролины на платформе Tyler Technologies. Публичный поиск по делам закрыт капчей Amazon WAF.

На главной странице портала проверки нет, она включается при переходе в разделы с данными. Например, по адресу /Portal/Home/Dashboard/29 вместо страницы поиска открывается «Let's confirm you are human» с кнопкой Begin.

Значения iv и context страница выдаёт новые при каждой загрузке. Сохранить их и подставлять в следующие задачи не выйдет: сервис капчу решит, но сайт такое решение отклонит. Читать их придётся со страницы каждый раз.

Ответ от сервиса состоит из двух значений. Первое предназначено встроенной функции страницы, второе — для cookie. Что с ними делать, разбираем в разделе про токен.

Адреса скриптов капчи у портала свои, и регион в них us-gov-west-1, а не us-east-1, как в примерах документации. Копировать адреса из примеров не получится.

Параметры задачи

Тип задачи — AmazonTaskProxyless, если решать через прокси сервиса, или AmazonTask, если подставлять свои.

У Amazon WAF есть два варианта разметки: с парой скриптов challenge.js и captcha.js и с одним скриптом jsapi.js. На портале лежат оба скрипта из первой пары, поэтому дальше речь только про этот вариант.

Параметр Тип Обязательный Описание
type String Да AmazonTaskProxyless или AmazonTask
websiteURL String Да Адрес страницы, на которой появилась проверка: https://portal-nc.tylertech.cloud/Portal/Home/Dashboard/29
websiteKey String Да Ключ сайта. Лежит в объекте gokuProps в коде страницы
iv String Да Значение iv из того же объекта. Меняется при каждой загрузке страницы
context String Да Значение context из того же объекта. Тоже меняется при каждой загрузке
challengeScript String Нет Адрес скрипта challenge.js. Поле необязательное, но для портала лучше его передавать
captchaScript String Нет Адрес скрипта captcha.js. То же самое
proxyType String Да для AmazonTask Тип прокси: http или socks5
proxyAddress String Да для AmazonTask IP-адрес прокси-сервера или имя хоста
proxyPort Число Да для AmazonTask Порт прокси-сервера
proxyLogin String Нет Логин для авторизации на прокси
proxyPassword String Нет Пароль для авторизации на прокси

Как найти параметры на portal-nc.tylertech.cloud

Все три значения лежат прямо в коде страницы проверки, во встроенном теге script:

html Copy
<script type="text/javascript">
window.awsWafCookieDomainList = ['tylertech.cloud'];
window.gokuProps = {
  "key": "AQIDAHjArpIF94zAGfD1jHMK+X+fGwFDxU3Rah+BaNzPreei5wEQVIS0rYSlPDG5...OLB0Q==",
  "iv": "CgAHbUDiVwAAAamI",
  "context": "rM6MrRNd31WTMQScBddAj7jpVNT0PQkTDASLN6Veten7FZUGstY0kbodqvqT...g=="
};
</script>
<script src="https://e9b10f157f38.9a96e8b4.us-gov-west-1.token.awswaf.com/e9b10f157f38/6082afcd5143/bd1ef86d885e/challenge.js"></script>
<script src="https://e9b10f157f38.9a96e8b4.us-gov-west-1.captcha.awswaf.com/e9b10f157f38/6082afcd5143/bd1ef86d885e/captcha.js"></script>

Ключ и context в примере укорочены, чтобы поместились в строку: целиком каждое из этих значений занимает несколько сотен символов.

Проще всего забрать их одной строкой в консоли браузера:

js Copy
window.gokuProps

Адреса скриптов от загрузки к загрузке не меняются:

Ключ сайта на момент написания статьи такой:

Copy
AQIDAHjArpIF94zAGfD1jHMK+X+fGwFDxU3Rah+BaNzPreei5wEQVIS0rYSlPDG5aZ6OHq6HAAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMmzDIFX2SSuNuEabWAgEQgDth9TJhevx6o2BPR3VuiAP5Rzf16WQp5RmonvmrCkOm4SY8uVNCeqgdXkz+qd49ACet3cA9ZPrx/OLB0Q==

Он привязан к настройкам защиты на стороне сайта, так что смениться может в любой момент. Значения iv и context точно новые при каждой загрузке, и документация требует брать их заново на каждый запрос. Надёжнее всего читать со страницы все три значения сразу — так скрипт не сломается, когда сайт обновит ключ.

Примеры кода

Python + requests (API v2)

Отправка задачи и опрос результата. Значения key, iv и context подставьте свежие — те, что лежат на странице в момент запуска.

python Copy
import time

import requests

API_KEY = "ВАШ_API_КЛЮЧ"
PAGE_URL = "https://portal-nc.tylertech.cloud/Portal/Home/Dashboard/29"
CHALLENGE_SCRIPT = ("https://e9b10f157f38.9a96e8b4.us-gov-west-1.token.awswaf.com"
                    "/e9b10f157f38/6082afcd5143/bd1ef86d885e/challenge.js")
CAPTCHA_SCRIPT = ("https://e9b10f157f38.9a96e8b4.us-gov-west-1.captcha.awswaf.com"
                  "/e9b10f157f38/6082afcd5143/bd1ef86d885e/captcha.js")

WEBSITE_KEY = "AQIDAHjArpIF94zAGfD1jHMK...OLB0Q=="
IV = "CgAHbUDiVwAAAamI"
CONTEXT = "rM6MrRNd31WTMQScBddAj7jpVNT0PQkTDASLN6Veten7...g=="

task = {
    "type": "AmazonTaskProxyless",
    "websiteURL": PAGE_URL,
    "websiteKey": WEBSITE_KEY,
    "iv": IV,
    "context": CONTEXT,
    "challengeScript": CHALLENGE_SCRIPT,
    "captchaScript": CAPTCHA_SCRIPT,
}

created = requests.post(
    "https://api.rucaptcha.com/createTask",
    json={"clientKey": API_KEY, "task": task},
    timeout=30,
).json()

if created.get("errorId") != 0:
    raise RuntimeError(f"Задача не создана: {created}")

task_id = created["taskId"]
print("Задача создана:", task_id)

for _ in range(24):
    time.sleep(5)
    result = requests.post(
        "https://api.rucaptcha.com/getTaskResult",
        json={"clientKey": API_KEY, "taskId": task_id},
        timeout=30,
    ).json()

    if result.get("status") == "ready":
        voucher = result["solution"]["captcha_voucher"]
        existing_token = result["solution"]["existing_token"]
        print("Ваучер получен:", voucher[:20], "…")
        break

    if result.get("errorId") != 0:
        raise RuntimeError(f"Ошибка: {result}")
else:
    raise RuntimeError("Решение не пришло за отведённое время")

Python + Playwright

Скрипт открывает страницу с проверкой, читает параметры из объекта gokuProps, отправляет задачу и передаёт ваучер обратно странице.

python Copy
import os
import time

import requests
from playwright.sync_api import sync_playwright

API_KEY = os.getenv("APIKEY_RUCAPTCHA", "ВАШ_API_КЛЮЧ")
PAGE_URL = "https://portal-nc.tylertech.cloud/Portal/Home/Dashboard/29"


def solve(task):
    created = requests.post(
        "https://api.rucaptcha.com/createTask",
        json={"clientKey": API_KEY, "task": task},
        timeout=30,
    ).json()

    if created.get("errorId") != 0:
        raise RuntimeError(f"Задача не создана: {created}")

    task_id = created["taskId"]

    for _ in range(24):
        time.sleep(5)
        result = requests.post(
            "https://api.rucaptcha.com/getTaskResult",
            json={"clientKey": API_KEY, "taskId": task_id},
            timeout=30,
        ).json()

        if result.get("status") == "ready":
            return result["solution"]

        if result.get("errorId") != 0:
            raise RuntimeError(f"Ошибка: {result}")

    raise RuntimeError("Решение не пришло за отведённое время")


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

    try:
        page.goto(PAGE_URL)
        page.wait_for_function("window.gokuProps !== undefined", timeout=30000)

        params = page.evaluate("""() => {
            const scripts = [...document.querySelectorAll('script[src]')].map(s => s.src);
            return {
                key: window.gokuProps.key,
                iv: window.gokuProps.iv,
                context: window.gokuProps.context,
                challenge: scripts.find(s => s.includes('challenge.js')),
                captcha: scripts.find(s => s.includes('captcha.js')),
            };
        }""")

        solution = solve({
            "type": "AmazonTaskProxyless",
            "websiteURL": PAGE_URL,
            "websiteKey": params["key"],
            "iv": params["iv"],
            "context": params["context"],
            "challengeScript": params["challenge"],
            "captchaScript": params["captcha"],
        })

        voucher = solution["captcha_voucher"]
        print("Ваучер получен:", voucher[:20], "…")

        page.evaluate("""async (voucher) => {
            if (!window.ChallengeScript
                || typeof window.ChallengeScript.submitCaptcha !== 'function') {
                throw new Error('ChallengeScript.submitCaptcha на странице не найден');
            }
            await window.ChallengeScript.submitCaptcha(voucher);
        }""", voucher)

        page.reload()
        page.wait_for_load_state("networkidle")
        print("Заголовок после проверки:", page.title())

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

Если после перезагрузки заголовок страницы всё ещё Human Verification, проверка не принята. Разбор причин — в таблице ниже.

Если предпочитаете Python SDK, метод называется amazon_waf, сигнатура такая: solver.amazon_waf(sitekey, iv, context, url, challenge_script=..., captcha_script=...). Ответ сервиса SDK кладёт в одно поле result["code"] строкой.

Как использовать полученный токен на portal-nc.tylertech.cloud

Сервис возвращает два значения:

json Copy
{
  "captcha_voucher": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...",
  "existing_token": "c06440ad-3f91-4e24-a13e-0aee760ececf:FgoAdy2S0xUFAAAA:eF1Y43dKAaLQ..."
}

captcha_voucher — ответ на саму проверку. Страница ждёт его в своей встроенной функции. Её код прямо на странице:

js Copy
window.addEventListener("load", function() {
  const container = document.querySelector("#captcha-container");
  CaptchaScript.renderCaptcha(container, async (voucher) => {
      await ChallengeScript.submitCaptcha(voucher);
      window.location.reload(true);
  });
});

Когда проверку проходит человек, ваучер в эту функцию передаёт сам виджет капчи. В скрипте виджета нет, поэтому вызовите submitCaptcha сами и передайте ей ваучер от сервиса.

python Copy
page.evaluate("""async (voucher) => {
    if (!window.ChallengeScript
        || typeof window.ChallengeScript.submitCaptcha !== 'function') {
        throw new Error('ChallengeScript.submitCaptcha на странице не найден');
    }
    await window.ChallengeScript.submitCaptcha(voucher);
}""", voucher)
page.reload()

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

existing_token — готовое значение cookie aws-waf-token. По форме оно полностью совпадает с тем, что портал ставит сам: идентификатор из 36 символов, служебная часть из 16 символов и base64, всё через двоеточие. Этот вариант пригодится, если вы работаете не браузером, а запросами: тогда достаточно положить значение в cookie и обращаться к порталу напрямую.

Домен для cookie портал задаёт сам, в переменной awsWafCookieDomainList на странице: tylertech.cloud.

Про срок жизни: ваучер — это подписанный токен со своим временем истечения внутри, и на решение у вас есть считаные минуты. Не копите задачи, применяйте ответ сразу.

Частые ошибки и решения

Ошибка / Проблема Причина Решение
Ответ получен, но страница снова показывает проверку Использованы старые iv и context Читайте их со страницы при каждом запуске: они новые при каждой загрузке
Задача создаётся, но решение не подходит В websiteURL указан корень домена Указывайте адрес страницы, где реально появилась проверка, например /Portal/Home/Dashboard/29
Ошибка «ChallengeScript.submitCaptcha на странице не найден» Скрипты капчи ещё не загрузились или страница уже не является страницей проверки Дождитесь появления window.gokuProps и только потом обращайтесь к функции
Ваучер передан, но содержимое страницы не изменилось Не выполнена перезагрузка После submitCaptcha перезагрузите страницу
Проверка проходит, но следующий запрос снова упирается в неё Cookie aws-waf-token не сохраняется между запросами Работайте в одном контексте браузера или переносите cookie вручную
Взяты адреса скриптов из примера в документации В примере регион us-east-1, у портала us-gov-west-1 Берите адреса challenge.js и captcha.js со страницы портала
Решение приходит, но сайт его отклоняет Между получением ваучера и его применением прошло слишком много времени Применяйте ответ сразу после получения
При работе запросами cookie не принимается Значение взято из captcha_voucher В cookie кладётся existing_token, а не ваучер

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