Эта статья была полезной?
Как обойти амазон капчу на 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
<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
window.gokuProps
Адреса скриптов от загрузки к загрузке не меняются:
- challenge.js: https://e9b10f157f38.9a96e8b4.us-gov-west-1.token.awswaf.com/e9b10f157f38/6082afcd5143/bd1ef86d885e/challenge.js
- captcha.js: https://e9b10f157f38.9a96e8b4.us-gov-west-1.captcha.awswaf.com/e9b10f157f38/6082afcd5143/bd1ef86d885e/captcha.js
Ключ сайта на момент написания статьи такой:
AQIDAHjArpIF94zAGfD1jHMK+X+fGwFDxU3Rah+BaNzPreei5wEQVIS0rYSlPDG5aZ6OHq6HAAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMmzDIFX2SSuNuEabWAgEQgDth9TJhevx6o2BPR3VuiAP5Rzf16WQp5RmonvmrCkOm4SY8uVNCeqgdXkz+qd49ACet3cA9ZPrx/OLB0Q==
Он привязан к настройкам защиты на стороне сайта, так что смениться может в любой момент. Значения iv и context точно новые при каждой загрузке, и документация требует брать их заново на каждый запрос. Надёжнее всего читать со страницы все три значения сразу — так скрипт не сломается, когда сайт обновит ключ.
Примеры кода
Python + requests (API v2)
Отправка задачи и опрос результата. Значения key, iv и context подставьте свежие — те, что лежат на странице в момент запуска.
python
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
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
{
"captcha_voucher": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...",
"existing_token": "c06440ad-3f91-4e24-a13e-0aee760ececf:FgoAdy2S0xUFAAAA:eF1Y43dKAaLQ..."
}
captcha_voucher — ответ на саму проверку. Страница ждёт его в своей встроенной функции. Её код прямо на странице:
js
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
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, а не ваучер |
Полезные ссылки
- Документация API по Amazon WAF: https://rucaptcha.com/api-docs/amazon-aws-waf-captcha
- Как обойти капчу Amazon: https://rucaptcha.com/h/how-to-bypass-amazon-captcha
- Обход капчи Amazon: https://rucaptcha.com/p/amazon-captcha-bypass
- Песочница для тестирования API: https://rucaptcha.com/api-docs/debugging
- Работа с прокси: https://rucaptcha.com/api-docs/proxy
- Python SDK на GitHub: https://github.com/2captcha/2captcha-python
- Другие примеры обхода капч на сайтах: https://rucaptcha.com/h?category=sites