@itd-api/turnstile
Токен Cloudflare Turnstile для входа по логину и паролю в itd-api.
Вход на итд.com требует токен капчи, а получить его можно только в браузере. Этот пакет поднимает браузер, берёт токен и отдаёт функцию, которая подставляется в auth клиента.
Отдельным пакетом — чтобы itd-api оставался клиентом API: без Playwright в зависимостях, без требования графической оболочки и без кода, который нужен далеко не всем. Если сессия уже сохранена в FileTokenStorage, этот пакет не нужен вовсе.
Установка
npm i @itd-api/turnstile playwright
npx playwright install chromiumplaywright объявлен необязательной одноранговой зависимостью: подойдёт и playwright-core, и совместимая по API сборка вроде patchright — см. параметр launch.
Использование
import { ItdClient } from 'itd-api';
import { FileTokenStorage } from 'itd-api/node';
import { createTurnstileSolver } from '@itd-api/turnstile';
const itd = new ItdClient({
storage: new FileTokenStorage('./.itd-session.json'),
auth: {
email: process.env.ITD_EMAIL!,
password: process.env.ITD_PASSWORD!,
getTurnstileToken: createTurnstileSolver(),
},
});Передаётся именно функция: токен одноразовый и живёт несколько минут, поэтому клиент спрашивает его заново перед каждым входом. Браузер поднимается на время одного вызова и сразу закрывается.
Разовый вызов без клиента:
import { solveTurnstile } from '@itd-api/turnstile';
const token = await solveTurnstile();Запуск на сервере
Браузер по умолчанию запускается с окном. В безоконном режиме виджет проходится заметно хуже: признаки такого режима видны странице. На сервере без графической оболочки поднимите виртуальный дисплей — это надёжнее, чем headless: true:
apt install xvfb
xvfb-run -a node bot.jsВ Docker к образу нужны системные библиотеки браузера: npx playwright install --with-deps chromium.
Как это устроено
Пакет не заходит на сайт. Навигация на https://xn--d1ah4a.com/ перехватывается и вместо настоящей страницы отдаётся своя — с одним виджетом Turnstile. Для браузера origin при этом настоящий, поэтому привязка ключа к домену не нарушается, а сервер при проверке токена видит ожидаемый hostname.
Из этого следует остальное:
- пароль в браузер не попадает — форма входа не участвует, вход выполняет сам
itd-api; - ничего не ломается от изменений вёрстки сайта: важен только публичный ключ виджета;
- нет гонки с настоящим запросом входа, а значит и незачем его подвешивать.
Чекбокс живёт в iframe чужого происхождения, до его DOM не дотянуться — клик идёт по координатам. Отсчёт ведётся от собственного контейнера известного размера, поэтому попадание не зависит от чужой вёрстки. Координаты слегка разбрасываются, первому касанию предшествует пауза, а User-Agent не подменяется: заявленная версия, разошедшаяся с реальным движком, сама по себе служит признаком автоматизации.
Настройки
Все необязательны.
| Параметр | По умолчанию | Что делает |
|---|---|---|
headless | false | Запуск без окна. См. раздел про сервер. |
disableSandbox | false | Отключить sandbox Chromium; только для изолированного контейнера. |
timeout | 60000 | Сколько ждать токен, мс. |
attempts | 2 | Сколько попыток при таймауте. |
theme | 'auto' | Оформление виджета. |
origin | https://xn--d1ah4a.com | Сайт, чей виджет решается. |
sitekey | ключ итд.com | Публичный ключ виджета. |
executablePath | — | Путь к браузеру, если он лежит не там, где ищет Playwright. |
args | — | Дополнительные аргументы командной строки. |
proxy | — | Прокси для браузера. |
browser | — | Готовый браузер. Тогда пакет его не запускает и не закрывает. |
launch | — | Свой запуск браузера. Заменяет все параметры запуска. |
logger | — | Куда писать ход решения, например console.debug. |
Свой драйвер:
createTurnstileSolver({
launch: async () => {
const { chromium } = await import('patchright');
return chromium.launch({ headless: false });
},
});Ошибки
Всё, что пошло не так, приходит как TurnstileError с полем reason:
reason | Что делать |
|---|---|
driver-missing | Установить playwright либо передать свой launch. |
launch-failed | Браузер не запустился: нет исполняемого файла или дисплея. |
timeout | Виджет не отдал токен. Обычно лечится повтором. |
widget-error | Виджет отказал; код Cloudflare лежит в widgetCode. |
Код 110200 в widgetCode означает, что ключ не разрешён для указанного домена, — повторять бессмысленно, и пакет этого не делает.