yandex-smartcaptcha-solver 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +434 -0
  2. package/index.js +429 -0
  3. package/package.json +46 -0
package/README.md ADDED
@@ -0,0 +1,434 @@
1
+ # yandex-smartcaptcha-solver
2
+
3
+ [![npm version](https://badge.fury.io/js/yandex-smartcaptcha-solver.svg)](https://www.npmjs.com/package/yandex-smartcaptcha-solver)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
+
6
+ Автоматическое решение Yandex SmartCaptcha с использованием сервиса распознавания XEvil.
7
+
8
+ ## 🚀 Установка
9
+
10
+ ```bash
11
+ npm install yandex-smartcaptcha-solver
12
+ ```
13
+
14
+ ## 📖 Быстрый старт
15
+
16
+ ```javascript
17
+ const YandexSmartCaptchaSolver = require('yandex-smartcaptcha-solver');
18
+
19
+ const solver = new YandexSmartCaptchaSolver({
20
+ xevilUrl: 'http://127.0.0.1:80',
21
+ xevilApiKey: 'your_xevil_api_key',
22
+ siteUrl: 'https://example.com/page-with-captcha',
23
+ siteKey: 'ysc1_YourSiteKeyHere'
24
+ });
25
+
26
+ // Решить капчу
27
+ const result = await solver.solve();
28
+ console.log(result);
29
+ // { status: 'ok', token: 'dD0xNzcx...' }
30
+
31
+ // Использовать токен в вашем запросе
32
+ const response = await fetch('https://example.com/api/submit', {
33
+ method: 'POST',
34
+ body: JSON.stringify({
35
+ captcha_token: result.token,
36
+ // другие данные...
37
+ })
38
+ });
39
+ ```
40
+
41
+ ## 🔧 API
42
+
43
+ ### Constructor
44
+
45
+ ```javascript
46
+ new YandexSmartCaptchaSolver(config, options)
47
+ ```
48
+
49
+ #### Обязательные параметры (config):
50
+
51
+ - **xevilUrl** (string) - URL вашего XEvil сервера (например: `'http://127.0.0.1:80'`)
52
+ - **xevilApiKey** (string) - API ключ для XEvil
53
+ - **siteUrl** (string) - Полный URL страницы с капчей (например: `'https://example.com/page'`)
54
+ - **siteKey** (string) - Site key Yandex SmartCaptcha (находится в коде страницы)
55
+ - **coreName** (string, optional) - Имя конкретного ядра XEvil для использования (например: `'XEvil1'`, `'XEvil2'`)
56
+
57
+ #### Опциональные параметры (options):
58
+
59
+ - **userAgent** (string) - User-Agent браузера (по умолчанию: Chrome 120)
60
+ - **debug** (boolean) - Режим отладки с детальными логами (по умолчанию: `false`)
61
+ - **saveImages** (boolean) - Сохранять изображения капчи для анализа (по умолчанию: `false`)
62
+ - **imagesDir** (string) - Папка для сохранения изображений (по умолчанию: `'./captcha_images'`)
63
+ - **humanDelayMin** (number) - Минимальная задержка перед отправкой ответа в мс (по умолчанию: `2000`)
64
+ - **humanDelayMax** (number) - Максимальная задержка перед отправкой ответа в мс (по умолчанию: `4000`)
65
+ - **timeout** (number) - Timeout для HTTP запросов в мс (по умолчанию: `60000`)
66
+
67
+ ### Методы
68
+
69
+ #### solve()
70
+
71
+ Решает капчу один раз.
72
+
73
+ ```javascript
74
+ const result = await solver.solve();
75
+ // { status: 'ok', token: 'dD0x...' }
76
+ ```
77
+
78
+ **Возвращает:** `Promise<{status: string, token: string}>`
79
+
80
+ **Выбрасывает:** `Error` при неудаче
81
+
82
+ #### solveWithRetry(maxAttempts, retryDelay)
83
+
84
+ Решает капчу с автоматическими повторными попытками.
85
+
86
+ ```javascript
87
+ const result = await solver.solveWithRetry(5, 4000);
88
+ // До 5 попыток с задержкой 4 секунды между ними
89
+ ```
90
+
91
+ **Параметры:**
92
+ - `maxAttempts` (number, по умолчанию: 3) - Максимальное количество попыток
93
+ - `retryDelay` (number, по умолчанию: 3000) - Задержка между попытками в мс
94
+
95
+ **Возвращает:** `Promise<{status: string, token: string}>`
96
+
97
+ ## 📝 Примеры
98
+
99
+ ### Базовое использование
100
+
101
+ ```javascript
102
+ const YandexSmartCaptchaSolver = require('yandex-smartcaptcha-solver');
103
+
104
+ async function main() {
105
+ const solver = new YandexSmartCaptchaSolver({
106
+ xevilUrl: 'http://127.0.0.1:80',
107
+ xevilApiKey: 'your_api_key',
108
+ siteUrl: 'https://example.com/page',
109
+ siteKey: 'ysc1_SiteKey123'
110
+ });
111
+
112
+ try {
113
+ const result = await solver.solve();
114
+ console.log('Token:', result.token);
115
+ } catch (error) {
116
+ console.error('Error:', error.message);
117
+ }
118
+ }
119
+
120
+ main();
121
+ ```
122
+
123
+ ### С retry и debug режимом
124
+
125
+ ```javascript
126
+ const solver = new YandexSmartCaptchaSolver({
127
+ xevilUrl: 'http://127.0.0.1:80',
128
+ xevilApiKey: 'your_api_key',
129
+ siteUrl: 'https://example.com/page',
130
+ siteKey: 'ysc1_SiteKey123',
131
+ coreName: 'XEvil2' // Использовать конкретное ядро XEvil
132
+ }, {
133
+ debug: true, // Включить детальные логи
134
+ saveImages: true, // Сохранять изображения
135
+ humanDelayMin: 3000, // Увеличить задержку до 3-6 секунд
136
+ humanDelayMax: 6000
137
+ });
138
+
139
+ // До 5 попыток с задержкой 4 секунды
140
+ const result = await solver.solveWithRetry(5, 4000);
141
+ ```
142
+
143
+ ### С использованием конкретного ядра XEvil
144
+
145
+ ```javascript
146
+ // Если у вас несколько ядер XEvil, можно указать конкретное
147
+ const solver = new YandexSmartCaptchaSolver({
148
+ xevilUrl: 'http://127.0.0.1:80',
149
+ xevilApiKey: 'your_api_key',
150
+ siteUrl: 'https://example.com/page',
151
+ siteKey: 'ysc1_SiteKey123',
152
+ coreName: 'XEvil1' // Название ядра из XEvil
153
+ });
154
+
155
+ const result = await solver.solve();
156
+ ```
157
+
158
+ ### Использование с переменными окружения
159
+
160
+ ```javascript
161
+ require('dotenv').config();
162
+
163
+ const solver = new YandexSmartCaptchaSolver({
164
+ xevilUrl: process.env.XEVIL_URL,
165
+ xevilApiKey: process.env.XEVIL_API_KEY,
166
+ siteUrl: process.env.SITE_URL,
167
+ siteKey: process.env.SITE_KEY
168
+ });
169
+
170
+ const result = await solver.solveWithRetry();
171
+ ```
172
+
173
+ ### Express API endpoint
174
+
175
+ ```javascript
176
+ const express = require('express');
177
+ const YandexSmartCaptchaSolver = require('yandex-smartcaptcha-solver');
178
+
179
+ const app = express();
180
+
181
+ app.post('/api/solve-captcha', async (req, res) => {
182
+ try {
183
+ const solver = new YandexSmartCaptchaSolver({
184
+ xevilUrl: process.env.XEVIL_URL,
185
+ xevilApiKey: process.env.XEVIL_API_KEY,
186
+ siteUrl: req.body.siteUrl,
187
+ siteKey: req.body.siteKey
188
+ });
189
+
190
+ const result = await solver.solveWithRetry(3);
191
+ res.json(result);
192
+ } catch (error) {
193
+ res.status(500).json({ error: error.message });
194
+ }
195
+ });
196
+
197
+ app.listen(3000, () => {
198
+ console.log('Server running on port 3000');
199
+ });
200
+ ```
201
+
202
+ ### Пример для HurmaCredit
203
+
204
+ ```javascript
205
+ const YandexSmartCaptchaSolver = require('yandex-smartcaptcha-solver');
206
+
207
+ const solver = new YandexSmartCaptchaSolver({
208
+ xevilUrl: 'http://127.0.0.1:80',
209
+ xevilApiKey: 'your_xevil_key',
210
+ siteUrl: 'https://borrow.hurmacredit.ru/?term=12&amount=10000',
211
+ siteKey: 'ysc1_LuYGybUg4evR0gMXB5JMtarE9ExcyxmHrELxL1oWb310434a'
212
+ }, {
213
+ debug: true,
214
+ saveImages: true
215
+ });
216
+
217
+ const result = await solver.solveWithRetry(5);
218
+ console.log('Spravka token:', result.token);
219
+
220
+ // Использовать result.token для отправки заявки
221
+ ```
222
+
223
+ ## 🔍 Отладка
224
+
225
+ ### Включение debug режима
226
+
227
+ ```javascript
228
+ const solver = new YandexSmartCaptchaSolver({
229
+ // ... config
230
+ }, {
231
+ debug: true
232
+ });
233
+ ```
234
+
235
+ Вывод в консоль:
236
+ ```
237
+ [2024-01-15T12:34:56.789Z] [INFO] Starting captcha solving process...
238
+ [2024-01-15T12:34:57.123Z] [DEBUG] Generated GUID: abc-123-def
239
+ [2024-01-15T12:34:58.456Z] [INFO] Sending captcha to XEvil...
240
+ [2024-01-15T12:35:03.789Z] [INFO] Captcha recognized: "текст"
241
+ [2024-01-15T12:35:07.012Z] [INFO] Submitting answer to Yandex...
242
+ [2024-01-15T12:35:08.345Z] [INFO] Captcha solved successfully!
243
+ ```
244
+
245
+ ### Сохранение изображений
246
+
247
+ ```javascript
248
+ const solver = new YandexSmartCaptchaSolver({
249
+ // ... config
250
+ }, {
251
+ saveImages: true,
252
+ imagesDir: './my-captcha-images'
253
+ });
254
+ ```
255
+
256
+ Изображения сохраняются с префиксами:
257
+ - `captcha_timestamp_SUCCESS_text.png` - успешно решено
258
+ - `captcha_timestamp_FAILED_text.png` - Яндекс отклонил
259
+ - `captcha_timestamp_UNKNOWN_text.png` - ошибка при решении
260
+
261
+ ## ⚙️ Как найти siteKey
262
+
263
+ 1. Откройте страницу с капчей в браузере
264
+ 2. Откройте DevTools (F12)
265
+ 3. Перейдите во вкладку Elements/Инспектор
266
+ 4. Найдите элемент с `smartcaptcha.yandexcloud.net`
267
+ 5. Найдите параметр `data-sitekey` или `sitekey` в коде
268
+ 6. Скопируйте значение (обычно начинается с `ysc1_`)
269
+
270
+ Или через консоль браузера:
271
+ ```javascript
272
+ // В консоли DevTools
273
+ document.querySelector('[data-sitekey]').getAttribute('data-sitekey')
274
+ ```
275
+
276
+ ## 🎯 Использование конкретного ядра XEvil (coreName)
277
+
278
+ Если у вас установлено несколько ядер XEvil, вы можете указать конкретное ядро для решения капчи:
279
+
280
+ ### Как узнать имя ядра:
281
+ 1. Откройте интерфейс XEvil (обычно http://127.0.0.1:80)
282
+ 2. В разделе "Cores" / "Ядра" вы увидите список доступных ядер
283
+ 3. Имена обычно выглядят как: `XEvil1`, `XEvil2`, `XEvil3`, и т.д.
284
+
285
+ ### Примеры использования:
286
+
287
+ ```javascript
288
+ // Использовать конкретное ядро
289
+ const solver = new YandexSmartCaptchaSolver({
290
+ xevilUrl: 'http://127.0.0.1:80',
291
+ xevilApiKey: 'your_key',
292
+ siteUrl: 'https://example.com',
293
+ siteKey: 'ysc1_SiteKey',
294
+ coreName: 'XEvil2' // Указываем имя ядра
295
+ });
296
+ ```
297
+
298
+ ```javascript
299
+ // Через переменную окружения
300
+ const solver = new YandexSmartCaptchaSolver({
301
+ xevilUrl: process.env.XEVIL_URL,
302
+ xevilApiKey: process.env.XEVIL_API_KEY,
303
+ siteUrl: process.env.SITE_URL,
304
+ siteKey: process.env.SITE_KEY,
305
+ coreName: process.env.XEVIL_CORE // XEvil1, XEvil2, etc.
306
+ });
307
+ ```
308
+
309
+ ```javascript
310
+ // Если не указывать coreName, будет использовано ядро по умолчанию
311
+ const solver = new YandexSmartCaptchaSolver({
312
+ xevilUrl: 'http://127.0.0.1:80',
313
+ xevilApiKey: 'your_key',
314
+ siteUrl: 'https://example.com',
315
+ siteKey: 'ysc1_SiteKey'
316
+ // coreName не указан - используется default core
317
+ });
318
+ ```
319
+
320
+ ### Зачем использовать конкретное ядро?
321
+
322
+ - **Балансировка нагрузки** - распределить задачи между ядрами
323
+ - **Приоритизация** - выделить отдельное ядро для важных задач
324
+ - **Производительность** - разные ядра могут иметь разную скорость/точность
325
+ - **Изоляция** - разделить проекты по ядрам
326
+
327
+ ## 🛠️ Требования
328
+
329
+ - Node.js >= 14.0.0
330
+ - Работающий XEvil сервер (купить на xevil.net)
331
+ - npm пакеты: axios, uuid, form-data
332
+
333
+ ## 📊 Производительность
334
+
335
+ - **Среднее время решения:** 8-15 секунд
336
+ - XEvil распознавание: 5-10 секунд
337
+ - Задержка перед submit: 2-4 секунды
338
+ - **Успешность:** ~70-90% (с использованием retry)
339
+
340
+ ## ⚠️ Обработка ошибок
341
+
342
+ ```javascript
343
+ try {
344
+ const result = await solver.solve();
345
+ } catch (error) {
346
+ if (error.message.includes('XEvil')) {
347
+ console.error('Проблема с XEvil:', error.message);
348
+ // Проверьте что XEvil запущен и доступен
349
+ } else if (error.message.includes('Yandex rejected')) {
350
+ console.error('Яндекс отклонил ответ:', error.message);
351
+ // Попробуйте увеличить humanDelay или используйте retry
352
+ } else if (error.message.includes('timeout')) {
353
+ console.error('Timeout:', error.message);
354
+ // Увеличьте timeout в настройках
355
+ } else {
356
+ console.error('Неизвестная ошибка:', error.message);
357
+ }
358
+ }
359
+ ```
360
+
361
+ ## 💡 Советы
362
+
363
+ 1. **Всегда используйте retry** для повышения успешности:
364
+ ```javascript
365
+ await solver.solveWithRetry(5, 4000);
366
+ ```
367
+
368
+ 2. **Увеличьте задержку** если Яндекс часто отклоняет правильные ответы:
369
+ ```javascript
370
+ { humanDelayMin: 5000, humanDelayMax: 8000 }
371
+ ```
372
+
373
+ 3. **Используйте переменные окружения** для конфиденциальных данных:
374
+ ```javascript
375
+ xevilApiKey: process.env.XEVIL_API_KEY
376
+ ```
377
+
378
+ 4. **Включите debug и saveImages** при проблемах с решением
379
+
380
+ 5. **Мониторьте баланс XEvil:**
381
+ ```bash
382
+ curl "http://127.0.0.1:80/res.php?key=YOUR_KEY&action=getbalance"
383
+ ```
384
+
385
+ ## 🐛 Известные проблемы
386
+
387
+ ### "Yandex rejected the answer"
388
+
389
+ **Причина:** Яндекс отклоняет правильно распознанный текст
390
+
391
+ **Решение:**
392
+ - Увеличьте `humanDelayMin` и `humanDelayMax` до 5-8 секунд
393
+ - Используйте `solveWithRetry()` для автоматических повторов
394
+ - Проверьте что siteKey актуален
395
+
396
+ ### "XEvil timeout"
397
+
398
+ **Причина:** XEvil слишком долго решает капчу
399
+
400
+ **Решение:**
401
+ - Проверьте что XEvil запущен: `curl http://127.0.0.1:80`
402
+ - Проверьте баланс XEvil
403
+ - Убедитесь что сервер не перегружен
404
+
405
+ ## 📄 Лицензия
406
+
407
+ MIT
408
+
409
+ ## ⚖️ Disclaimer
410
+
411
+ Этот инструмент предназначен только для законного использования, тестирования и образовательных целей. Убедитесь, что вы не нарушаете Terms of Service целевого сайта. Авторы не несут ответственности за неправомерное использование.
412
+
413
+ ## 🤝 Вклад
414
+
415
+ Contributions приветствуются! Пожалуйста, создавайте pull requests или issues на GitHub.
416
+
417
+ ## 📞 Поддержка
418
+
419
+ Если у вас возникли проблемы:
420
+
421
+ 1. Проверьте что все требования выполнены
422
+ 2. Включите `debug: true` и проверьте логи
423
+ 3. Проверьте сохраненные изображения (если `saveImages: true`)
424
+ 4. Создайте issue на GitHub с логами и описанием проблемы
425
+
426
+ ## 🔗 Полезные ссылки
427
+
428
+ - [XEvil официальный сайт](https://xevil.net)
429
+ - [Yandex SmartCaptcha документация](https://cloud.yandex.ru/docs/smartcaptcha/)
430
+ - [GitHub репозиторий](https://github.com/yourusername/yandex-smartcaptcha-solver)
431
+
432
+ ---
433
+
434
+ Made with ❤️ for automation
package/index.js ADDED
@@ -0,0 +1,429 @@
1
+ const axios = require('axios');
2
+ const { v4: uuidv4 } = require('uuid');
3
+ const FormData = require('form-data');
4
+ const fs = require('fs');
5
+ const path = require('path');
6
+
7
+ /**
8
+ * Yandex SmartCaptcha Solver
9
+ * Автоматическое решение Yandex SmartCaptcha через XEvil
10
+ * @module yandex-smartcaptcha-solver
11
+ */
12
+
13
+ class YandexSmartCaptchaSolver {
14
+ /**
15
+ * Создать новый экземпляр солвера
16
+ * @param {Object} config - Конфигурация
17
+ * @param {string} config.xevilUrl - URL XEvil сервера (например: 'http://127.0.0.1:80')
18
+ * @param {string} config.xevilApiKey - API ключ для XEvil
19
+ * @param {string} config.siteUrl - Полный URL страницы с капчей
20
+ * @param {string} config.siteKey - Site key Yandex SmartCaptcha
21
+ * @param {string} [config.coreName] - Имя ядра XEvil для использования (опционально)
22
+ * @param {Object} [options] - Дополнительные опции
23
+ * @param {string} [options.userAgent] - User-Agent браузера
24
+ * @param {boolean} [options.debug=false] - Режим отладки
25
+ * @param {boolean} [options.saveImages=false] - Сохранять изображения капчи
26
+ * @param {string} [options.imagesDir='./captcha_images'] - Папка для изображений
27
+ * @param {number} [options.humanDelayMin=2000] - Минимальная задержка перед submit (мс)
28
+ * @param {number} [options.humanDelayMax=4000] - Максимальная задержка перед submit (мс)
29
+ * @param {number} [options.timeout=60000] - Timeout для HTTP запросов (мс)
30
+ */
31
+ constructor(config, options = {}) {
32
+ if (!config.xevilUrl) {
33
+ throw new Error('xevilUrl is required');
34
+ }
35
+ if (!config.xevilApiKey) {
36
+ throw new Error('xevilApiKey is required');
37
+ }
38
+ if (!config.siteUrl) {
39
+ throw new Error('siteUrl is required');
40
+ }
41
+ if (!config.siteKey) {
42
+ throw new Error('siteKey is required');
43
+ }
44
+
45
+ // Парсим URL
46
+ const url = new URL(config.siteUrl);
47
+
48
+ this.config = {
49
+ xevilUrl: config.xevilUrl,
50
+ xevilApiKey: config.xevilApiKey,
51
+ siteUrl: config.siteUrl,
52
+ siteKey: config.siteKey,
53
+ host: url.hostname,
54
+ coreName: config.coreName || null, // Опциональное имя ядра
55
+
56
+ // Опции
57
+ userAgent: options.userAgent || 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
58
+ debug: options.debug || false,
59
+ saveImages: options.saveImages || false,
60
+ imagesDir: options.imagesDir || './captcha_images',
61
+ humanDelayMin: options.humanDelayMin || 2000,
62
+ humanDelayMax: options.humanDelayMax || 4000,
63
+ timeout: options.timeout || 60000
64
+ };
65
+
66
+ this.state = {
67
+ captchaId: null,
68
+ recognizedText: null
69
+ };
70
+
71
+ this.axios = axios.create({
72
+ headers: {
73
+ 'User-Agent': this.config.userAgent,
74
+ 'Accept': '*/*',
75
+ 'Accept-Language': 'ru-RU,ru;q=0.9,en;q=0.8',
76
+ 'Accept-Encoding': 'gzip, deflate, br'
77
+ },
78
+ timeout: this.config.timeout
79
+ });
80
+
81
+ if (this.config.saveImages && !fs.existsSync(this.config.imagesDir)) {
82
+ fs.mkdirSync(this.config.imagesDir, { recursive: true });
83
+ }
84
+ }
85
+
86
+ /**
87
+ * Логирование
88
+ * @private
89
+ */
90
+ _log(message, level = 'info') {
91
+ if (!this.config.debug && level === 'debug') return;
92
+
93
+ const timestamp = new Date().toISOString();
94
+ const prefix = `[${timestamp}] [${level.toUpperCase()}]`;
95
+
96
+ console.log(`${prefix} ${message}`);
97
+ }
98
+
99
+ /**
100
+ * Сохранить изображение капчи
101
+ * @private
102
+ */
103
+ _saveImage(imageBuffer, text, success) {
104
+ if (!this.config.saveImages) return;
105
+
106
+ try {
107
+ const timestamp = Date.now();
108
+ const status = success === true ? 'SUCCESS' : success === false ? 'FAILED' : 'UNKNOWN';
109
+ const cleanText = text.replace(/[^a-zA-Zа-яА-Я0-9]/g, '_');
110
+ const filename = `captcha_${timestamp}_${status}_${cleanText}.png`;
111
+ const filepath = path.join(this.config.imagesDir, filename);
112
+
113
+ fs.writeFileSync(filepath, imageBuffer);
114
+ this._log(`Image saved: ${filename}`, 'debug');
115
+ } catch (error) {
116
+ this._log(`Failed to save image: ${error.message}`, 'warn');
117
+ }
118
+ }
119
+
120
+ /**
121
+ * Сообщить XEvil о неправильном ответе
122
+ * @private
123
+ */
124
+ async _reportBadCaptcha() {
125
+ if (!this.state.captchaId) return;
126
+
127
+ try {
128
+ this._log(`Reporting incorrect answer to XEvil (ID: ${this.state.captchaId})`, 'debug');
129
+
130
+ await axios.get(`${this.config.xevilUrl}/res.php`, {
131
+ params: {
132
+ key: this.config.xevilApiKey,
133
+ action: 'reportbad',
134
+ id: this.state.captchaId
135
+ },
136
+ timeout: 10000
137
+ });
138
+
139
+ this._log('Bad answer reported successfully', 'debug');
140
+ } catch (error) {
141
+ this._log(`Failed to report bad answer: ${error.message}`, 'warn');
142
+ }
143
+ }
144
+
145
+ /**
146
+ * Первый запрос к Yandex SmartCaptcha
147
+ * @private
148
+ */
149
+ async _firstCheck() {
150
+ this._log('Performing first check request...', 'debug');
151
+
152
+ const url = `https://smartcaptcha.yandexcloud.net/check?host=${this.config.host}&sitekey=${this.config.siteKey}&href=${encodeURIComponent(this.config.siteUrl)}`;
153
+ const data = `sitekey=${this.config.siteKey}`;
154
+
155
+ const headers = {
156
+ 'Referer': `https://smartcaptcha.yandexcloud.net/backend.636bb879d1085041bc19.html?sitekey=${this.config.siteKey}&theme=light&hl=ru&host=${this.config.host}&href=${encodeURIComponent(this.config.siteUrl)}&test=false&webview=false&hideChallengeContainer=false`,
157
+ 'Content-Type': 'text/plain;charset=UTF-8',
158
+ 'Origin': 'https://smartcaptcha.yandexcloud.net',
159
+ 'Sec-Fetch-Dest': 'empty',
160
+ 'Sec-Fetch-Mode': 'cors',
161
+ 'Sec-Fetch-Site': 'same-origin'
162
+ };
163
+
164
+ const response = await this.axios.post(url, data, { headers });
165
+ return response.data;
166
+ }
167
+
168
+ /**
169
+ * Второй запрос к Yandex SmartCaptcha
170
+ * @private
171
+ */
172
+ async _secondCheck(captchaKey) {
173
+ this._log('Performing second check request...', 'debug');
174
+
175
+ const url = `https://smartcaptcha.yandexcloud.net/check?host=${this.config.host}&sitekey=${this.config.siteKey}&href=${encodeURIComponent(this.config.siteUrl)}`;
176
+ const data = `key=${captchaKey}&sitekey=${this.config.siteKey}&lang=ru&test=false&webview=false`;
177
+
178
+ const headers = {
179
+ 'Content-Type': 'text/plain;charset=UTF-8',
180
+ 'Origin': 'https://smartcaptcha.yandexcloud.net',
181
+ 'Sec-Fetch-Dest': 'empty',
182
+ 'Sec-Fetch-Mode': 'cors',
183
+ 'Sec-Fetch-Site': 'same-origin'
184
+ };
185
+
186
+ const response = await this.axios.post(url, data, { headers });
187
+ return response.data;
188
+ }
189
+
190
+ /**
191
+ * Получить изображение капчи
192
+ * @private
193
+ */
194
+ async _getImage(imageUrl) {
195
+ this._log('Downloading captcha image...', 'debug');
196
+
197
+ const response = await this.axios.get(imageUrl, {
198
+ responseType: 'arraybuffer',
199
+ headers: {
200
+ 'Referer': 'https://smartcaptcha.yandexcloud.net/'
201
+ }
202
+ });
203
+
204
+ this._log(`Image downloaded: ${response.data.length} bytes`, 'debug');
205
+ return Buffer.from(response.data);
206
+ }
207
+
208
+ /**
209
+ * Распознать капчу через XEvil
210
+ * @private
211
+ */
212
+ async _recognize(imageBuffer) {
213
+ this._log('Sending captcha to XEvil...', 'info');
214
+
215
+ const base64Image = imageBuffer.toString('base64');
216
+
217
+ const formData = new FormData();
218
+ formData.append('key', this.config.xevilApiKey);
219
+ formData.append('method', 'base64');
220
+ formData.append('body', base64Image);
221
+ formData.append('json', '1');
222
+
223
+ // Добавляем coreName если указан
224
+ if (this.config.coreName) {
225
+ formData.append('core', this.config.coreName);
226
+ this._log(`Using XEvil core: ${this.config.coreName}`, 'debug');
227
+ }
228
+
229
+ const inResponse = await axios.post(
230
+ `${this.config.xevilUrl}/in.php`,
231
+ formData,
232
+ {
233
+ headers: formData.getHeaders(),
234
+ timeout: 30000
235
+ }
236
+ );
237
+
238
+ if (inResponse.data.status !== 1) {
239
+ throw new Error(`XEvil error: ${inResponse.data.request || JSON.stringify(inResponse.data)}`);
240
+ }
241
+
242
+ this.state.captchaId = inResponse.data.request;
243
+ this._log(`Captcha sent to XEvil (ID: ${this.state.captchaId})`, 'debug');
244
+
245
+ // Ожидание результата
246
+ this._log('Waiting for XEvil to solve captcha...', 'info');
247
+
248
+ const maxAttempts = 30;
249
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
250
+ await new Promise(resolve => setTimeout(resolve, 3000));
251
+
252
+ const resResponse = await axios.get(
253
+ `${this.config.xevilUrl}/res.php`,
254
+ {
255
+ params: {
256
+ key: this.config.xevilApiKey,
257
+ action: 'get',
258
+ id: this.state.captchaId,
259
+ json: 1
260
+ },
261
+ timeout: 30000
262
+ }
263
+ );
264
+
265
+ if (resResponse.data.status === 1) {
266
+ const result = resResponse.data.request.trim();
267
+ this._log(`Captcha recognized: "${result}"`, 'info');
268
+ this.state.recognizedText = result;
269
+ return result;
270
+ }
271
+
272
+ if (resResponse.data.request !== 'CAPCHA_NOT_READY') {
273
+ throw new Error(`XEvil error: ${resResponse.data.request}`);
274
+ }
275
+
276
+ this._log(`Attempt ${attempt}/${maxAttempts}: still processing...`, 'debug');
277
+ }
278
+
279
+ throw new Error('XEvil timeout: captcha not solved in time');
280
+ }
281
+
282
+ /**
283
+ * Закодировать результат
284
+ * @private
285
+ */
286
+ _encode(text) {
287
+ const bytes = Buffer.from(text, 'utf8');
288
+ let encoded = '';
289
+
290
+ for (let i = 0; i < bytes.length; i++) {
291
+ encoded += '%' + bytes[i].toString(16).toUpperCase().padStart(2, '0');
292
+ }
293
+
294
+ return encoded;
295
+ }
296
+
297
+ /**
298
+ * Отправить результат в Yandex
299
+ * @private
300
+ */
301
+ async _submit(captchaKey, encodedResult) {
302
+ this._log('Submitting answer to Yandex...', 'info');
303
+
304
+ // Задержка для имитации человека
305
+ const delay = this.config.humanDelayMin +
306
+ Math.random() * (this.config.humanDelayMax - this.config.humanDelayMin);
307
+ this._log(`Waiting ${Math.round(delay/1000)}s before submit (human simulation)...`, 'debug');
308
+ await new Promise(resolve => setTimeout(resolve, delay));
309
+
310
+ const url = `https://smartcaptcha.yandexcloud.net/check?host=${this.config.host}&sitekey=${this.config.siteKey}&href=${encodeURIComponent(this.config.siteUrl)}`;
311
+ const data = `key=${captchaKey}&sitekey=${this.config.siteKey}&lang=ru&test=false&webview=false&rep=${encodedResult}`;
312
+
313
+ const headers = {
314
+ 'Content-Type': 'text/plain;charset=UTF-8',
315
+ 'Origin': 'https://smartcaptcha.yandexcloud.net',
316
+ 'Sec-Fetch-Dest': 'empty',
317
+ 'Sec-Fetch-Mode': 'cors',
318
+ 'Sec-Fetch-Site': 'same-origin'
319
+ };
320
+
321
+ const response = await this.axios.post(url, data, { headers });
322
+ return response.data;
323
+ }
324
+
325
+ /**
326
+ * Решить капчу
327
+ * @returns {Promise<Object>} Результат с полями status и token (spravka)
328
+ * @throws {Error} При неудаче
329
+ * @example
330
+ * const result = await solver.solve();
331
+ * console.log(result); // { status: 'ok', token: 'dD0x...' }
332
+ */
333
+ async solve() {
334
+ let imageBuffer = null;
335
+
336
+ try {
337
+ this._log('Starting captcha solving process...', 'info');
338
+
339
+ // Генерируем GUID
340
+ const guid = uuidv4();
341
+ this._log(`Generated GUID: ${guid}`, 'debug');
342
+
343
+ // Первый запрос
344
+ const firstResponse = await this._firstCheck();
345
+ if (!firstResponse.captcha?.key) {
346
+ throw new Error('No captcha key received from first request');
347
+ }
348
+ this._log('First captcha key received', 'debug');
349
+
350
+ // Второй запрос
351
+ const secondResponse = await this._secondCheck(firstResponse.captcha.key);
352
+ if (!secondResponse.captcha?.image) {
353
+ throw new Error('No captcha image URL received');
354
+ }
355
+
356
+ const captchaKey = secondResponse.captcha.key;
357
+ this._log('Second captcha key received', 'debug');
358
+
359
+ // Получаем и распознаем изображение
360
+ imageBuffer = await this._getImage(secondResponse.captcha.image);
361
+ const recognizedText = await this._recognize(imageBuffer);
362
+
363
+ // Кодируем и отправляем
364
+ const encodedResult = this._encode(recognizedText);
365
+ this._log(`Encoded result: ${encodedResult}`, 'debug');
366
+
367
+ const finalResponse = await this._submit(captchaKey, encodedResult);
368
+
369
+ // Проверяем результат
370
+ if (finalResponse.status === 'ok') {
371
+ this._log('Captcha solved successfully!', 'info');
372
+ this._saveImage(imageBuffer, recognizedText, true);
373
+
374
+ return {
375
+ status: 'ok',
376
+ token: finalResponse.token || finalResponse.key
377
+ };
378
+ } else {
379
+ // Неудача - сообщаем XEvil
380
+ await this._reportBadCaptcha();
381
+ this._saveImage(imageBuffer, recognizedText, false);
382
+
383
+ throw new Error(`Yandex rejected the answer. Recognized text: "${recognizedText}"`);
384
+ }
385
+
386
+ } catch (error) {
387
+ this._log(`Error: ${error.message}`, 'error');
388
+
389
+ if (imageBuffer && this.state.recognizedText) {
390
+ this._saveImage(imageBuffer, this.state.recognizedText, null);
391
+ }
392
+
393
+ throw error;
394
+ }
395
+ }
396
+
397
+ /**
398
+ * Решить капчу с автоматическими повторными попытками
399
+ * @param {number} [maxAttempts=3] - Максимальное количество попыток
400
+ * @param {number} [retryDelay=3000] - Задержка между попытками (мс)
401
+ * @returns {Promise<Object>} Результат с полями status и token
402
+ * @throws {Error} Если все попытки неудачны
403
+ * @example
404
+ * const result = await solver.solveWithRetry(5, 4000);
405
+ */
406
+ async solveWithRetry(maxAttempts = 3, retryDelay = 3000) {
407
+ this._log(`Will attempt to solve up to ${maxAttempts} times`, 'info');
408
+
409
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
410
+ try {
411
+ this._log(`Attempt ${attempt}/${maxAttempts}`, 'info');
412
+ const result = await this.solve();
413
+ this._log(`Successfully solved on attempt ${attempt}!`, 'info');
414
+ return result;
415
+ } catch (error) {
416
+ this._log(`Attempt ${attempt} failed: ${error.message}`, 'warn');
417
+
418
+ if (attempt < maxAttempts) {
419
+ this._log(`Waiting ${retryDelay/1000}s before retry...`, 'info');
420
+ await new Promise(resolve => setTimeout(resolve, retryDelay));
421
+ }
422
+ }
423
+ }
424
+
425
+ throw new Error(`Failed to solve captcha after ${maxAttempts} attempts`);
426
+ }
427
+ }
428
+
429
+ module.exports = YandexSmartCaptchaSolver;
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "yandex-smartcaptcha-solver",
3
+ "version": "1.0.0",
4
+ "description": "Automatic Yandex SmartCaptcha solver using XEvil OCR service",
5
+ "main": "index.js",
6
+ "scripts": {
7
+ "test": "node test/test.js",
8
+ "example": "node examples/basic.js"
9
+ },
10
+ "keywords": [
11
+ "captcha",
12
+ "yandex",
13
+ "smartcaptcha",
14
+ "captcha-solver",
15
+ "xevil",
16
+ "ocr",
17
+ "automation",
18
+ "bot"
19
+ ],
20
+ "author": "SH3EL1T",
21
+ "license": "MIT",
22
+ "repository": {
23
+ "type": "git",
24
+ "url": "https://github.com/sh3el1t/yandex-smartcaptcha-solver.git"
25
+ },
26
+ "bugs": {
27
+ "url": "https://github.com/sh3el1t/yandex-smartcaptcha-solver/issues"
28
+ },
29
+ "homepage": "https://github.com/sh3el1t/yandex-smartcaptcha-solver#readme",
30
+ "dependencies": {
31
+ "axios": "^1.6.0",
32
+ "uuid": "^9.0.0",
33
+ "form-data": "^4.0.0"
34
+ },
35
+ "devDependencies": {
36
+ "dotenv": "^16.0.0"
37
+ },
38
+ "engines": {
39
+ "node": ">=14.0.0"
40
+ },
41
+ "files": [
42
+ "index.js",
43
+ "README.md",
44
+ "LICENSE"
45
+ ]
46
+ }