Небольшой эпиграф - если вы делаете инструкцию, так делайте ее до конца, а то в инструкции как решить Амазон капчу - джун ногу сломит.
Собственно к чему все это? Да к тому, что когда мне потребовалось решить капчу от Амазон, пресловутую Waf Captcha я пошел копать на сервис, которым постоянно пользуюсь при работе с Кей Коллектором, и некоторыми другими сервисами (2капча - жаль Хабр банит статьи за реферальные ссылки).
Ну и нашел там инструкцию, ссылку на которую собственно и привел выше. Как вам вероятно стало понятно из эпиграфа - я ни черта не понял, вернее я понял, что надо использовать АПИ, но на этом все...
С Селениумом было реально проще.
Главная проблема - малый таймаут, который выделяется на решение со стороны Амазона. Время на решение капчи ограничено и если ответа нет, то капча обновляется (у нее обновляются 2 параметра - iv и context).
Получается, что таймаут свежести капчи около 30 секунд, а за это время необходимо найти на странице параметры, скопировать их, вставить в код скрипта и запустить его, после этого 2капча должна ее решить и вернуть правильный ответ. Я пробовал это сделать пару безуспешных часа, вырабатывал автоматизм действий, но увы, на поиск и замену изменяемых параметров уходит не менее 12-15 секунд, и остается от 15 до 18 секунд мы решение капчи сервисом, что в нынешних реалиях звучит достаточно фантастически.
Тут нужен другой подход, искать и подставлять параметры должен скрипт, но как его написать человеку, который в своей жизни ничего сложнее Ahrefs не видел?

Вот именно по этой причине, я считаю, что инструкции, подобные упомянутым в статье необходимо делать более подробными, чем - "Просто используй Апи, ты че совсем куку?"
Решение
По итогу решение было найдено и заняло оно у меня примерно 3 часа времени. Рассказываю, как же джуну решить Амазон капчу на полном автомате.
Нам понадобится GPT Chat и в моем случае видео распознавания Амазон капчи (вам оно не понадобится, так как я дам вам уже готовый собранный файл).
Видео я взял у знакомого проггера, но он запретил его выкладывать в паблик, так как оно не обезличено.
Но вы же не отстанете от меня,будете просить пруфы, а я потом подсяду на антидепресанты, что мне никто не верит, поэтому я воспроизвел это видео в самом конце, когда получил готовый скрипт и срадостью приложу его в самом конце этого текста, в качестве демонстрации моей бесконечной преданости аудитории!
Итак, поехали по порядку:
Я взял видео, сделал 3 скриншота и загрузил их в GPT Chat и попросил его переписать мне этот код текстом.
В видео было несколько файлов, но показано только содержимое 2 из них - index.js и inject.js - с них я и начал.
Не буду утомлять вас расшифровкой скринов (там пришлось немного повозиться и собрать код со скриншотов в единое целое но по итогу я получил два вот таких куска кода для двух файлов:
// index.js
import { launch } from 'puppeteer'
import { Captcha } from '2captcha-ts'
import { readFileSync } from 'fs'
const solver = new Captcha(process.env.APIKEY)
const target = 'УРЛ сайта где встречается капча'
const example = async () => {
const browser = await launch({
headless: false,
devtools: true
})
const [page] = await browser.pages()
const preloadFile = readFileSync('./inject.js', 'utf8')
await page.evaluateOnNewDocument(preloadFile)
// Here we intercept the console messages to catch the message logged by inject.js script
page.on('console', async (msg) => {
const txt = msg.text()
if (txt.includes('intercepted-params:')) {
const params = JSON.parse(txt.replace('intercepted-params:', ''))
const wafParams = {
pageurl: target,
sitekey: params.key,
iv: params.iv,
context: params.context,
challenge_script: params.challenge_script,
captcha_script: params.captcha_script
}
console.log(wafParams)
try {
console.log('Solving the captcha...')
const res = await solver.solveRecaptchaV2(wafParams)
console.log(`Solved the captcha ${res.id}`)
console.log(res)
console.log('Using the token...')
await page.evaluate(token => {
window.localStorage.inputCaptchaToken(token)
}, res.data.captcha.voucher)
console.log(e)
} catch (e) {
console.log(e)
}
}
})
await page.goto(target)
// Additional code to interact with the page after captcha is solved might be here...
}
example()
И второй файл inject.js
console.clear = () => console.log('Console was cleared')
const i = setInterval(() => {
if (window.CaptchaScript) {
clearInterval(i)
let params = gokProps
Array.from(document.querySelectorAll('script')).forEach(s => {
const src = s.getAttribute('src')
if (src && src.includes('captcha.js')) params.captcha_script = src
if (src && src.includes('challenge.js')) params.challenge_script = src
})
console.log('intercepted-params: ' + JSON.stringify(params))
}
}, 5)
Естественно, я уточнил у Чата, как мне заставить код работать, на что получил рекомендацию использовать стандартную команду
node index.js
Но я же в этих ваших интернетах уже очень долго и понимаю, что код просто так не заработает, если на компе не установленно нужных библиотек, мой нейроконсультант и тут мне помог
Изучив код, который я дал ему в виде скриншотов, он порекомендовал установить следующие пакеты
Единственно, я не совсем понял, нафига тут нужен playwright, но кто я такой, чтобы сомневаться в компетенции Чата.
И соответсвенно код установки npm install puppeteer 2captcha-ts playwright (правда у меня через VS Code не получилось их поставить все вместе, вероятно виной всему кривые руки, я ставил по одному и через консоль)
npm install puppeteer
npm install 2captcha-ts
npm install playwright
Дальше интереснее, так как все что было до этого этапа я так или иначе знаю, а вот следующий блок для меня реально темный лес и я просто делаю то, что говорит мне мой нейроконсультант.
Итак, для корректной работы кода понадобился файл с кодировкой .env, причем он может быть без названия, а в этом файле должны быть следующие данные:
APIKEY=your_2captcha_api_key
Понятно, что вместо параметра your_2captcha_api_key
я подставил свой ключ с сервиса.
Дальше было еще 6 рекомендаций, что надо делать чтобы код заработал, но

Соответсвенно первый запуск и первая ошибка.

Ошибка была связана с использованием синтаксиса ES6 import в Node.js. Для его использования нужно либо указать тип модуля в package.json, либо изменить расширение файла на .mjs
.
Мне было лень указывать тип модуля в package.json и я пошел по пути наименьшего сопротивления, тупо переименовал расширение файла index с js на mjs.
Следующая ошибка была связана с подключаемым пакетом 2captcha-ts
, но подробно описывать их не хочется, скажу лишь что я изменил код, отвечающий за запуск этого модуля несколько раз, добавил логирование и проверку корректности подключения файла .env
.
И это все равно не сработало, скрипт продолжал выдавать ошибку и упорно не хотел работать. Я сравнил скриншот и код который мне вытащил оттуда Чат и нашел небольшую опечатку, которая и была корнем проблемы.
Но, как оказалось, и это не помогло - выпала ошибка APIKEY is not defined in .env file
Это мы пофиксили добавлением нового пакета:
npm install dotenv
После этого встреилось еще пару опечаток, которые Чат пытался решить через изменения структуры кода, но надо было просто внимательно сравнить скриншот и сам код.
И в конце концов код файла index.js из вот такого:
// index.js
import { launch } from 'puppeteer'
import { Captcha } from '2captcha-ts'
import { readFileSync } from 'fs'
const solver = new Captcha(process.env.APIKEY)
const target = 'УРЛ сайта где встречается капча'
const example = async () => {
const browser = await launch({
headless: false,
devtools: true
})
const [page] = await browser.pages()
const preloadFile = readFileSync('./inject.js', 'utf8')
await page.evaluateOnNewDocument(preloadFile)
// Here we intercept the console messages to catch the message logged by inject.js script
page.on('console', async (msg) => {
const txt = msg.text()
if (txt.includes('intercepted-params:')) {
const params = JSON.parse(txt.replace('intercepted-params:', ''))
const wafParams = {
pageurl: target,
sitekey: params.key,
iv: params.iv,
context: params.context,
challenge_script: params.challenge_script,
captcha_script: params.captcha_script
}
console.log(wafParams)
try {
console.log('Solving the captcha...')
const res = await solver.solveRecaptchaV2(wafParams)
console.log(`Solved the captcha ${res.id}`)
console.log(res)
console.log('Using the token...')
await page.evaluate(token => {
window.localStorage.inputCaptchaToken(token)
}, res.data.captcha.voucher)
console.log(e)
} catch (e) {
console.log(e)
}
}
})
await page.goto(target)
// Additional code to interact with the page after captcha is solved might be here...
}
example()
Превратился в вот такой index.mjs
// index.js
import 'dotenv/config';
import { launch } from 'puppeteer'
import Captcha from '2captcha-ts';
import { readFileSync } from 'fs'
// Проверка наличия APIKEY в .env
if (!process.env.APIKEY) {
console.error("APIKEY is not defined in .env file");
process.exit(1); // Завершение выполнения, если ключ не найден
}
const solver = new Captcha.Solver(process.env.APIKEY);
const target = 'УРЛ сайта где встречается капча'
const example = async () => {
const browser = await launch({
headless: false,
devtools: true
})
const [page] = await browser.pages()
const preloadFile = readFileSync('./inject.js', 'utf8')
await page.evaluateOnNewDocument(preloadFile)
// Here we intercept the console messages to catch the message logged by inject.js script
page.on('console', async (msg) => {
const txt = msg.text()
if (txt.includes('intercepted-params:')) {
const params = JSON.parse(txt.replace('intercepted-params:', ''))
const wafParams = {
pageurl: target,
sitekey: params.key,
iv: params.iv,
context: params.context,
challenge_script: params.challenge_script,
captcha_script: params.captcha_script
}
console.log(wafParams)
try {
console.log('Solving the captcha...')
const res = await solver.amazonWaf(wafParams)
console.log(`Solved the captcha ${res.id}`)
console.log(res)
console.log('Using the token...')
await page.evaluate(async (token) => {
await ChallengeScript.submitCaptcha(token);
window.location.reload ()
}, res.data.captcha_voucher);
} catch (e) {
console.log(e)
}
} else {
return
}
})
await page.goto(target)
// Additional code to interact with the page after captcha is solved might be here...
}
example()
В коде выше не забудьте подставить верный урл, где требуется решение (если будете применять).
А из вот такого inject.js
console.clear = () => console.log('Console was cleared')
const i = setInterval(() => {
if (window.CaptchaScript) {
clearInterval(i)
let params = gokProps
Array.from(document.querySelectorAll('script')).forEach(s => {
const src = s.getAttribute('src')
if (src && src.includes('captcha.js')) params.captcha_script = src
if (src && src.includes('challenge.js')) params.challenge_script = src
})
console.log('intercepted-params: ' + JSON.stringify(params))
}
}, 5)
В вот такой inject.js
// console.clear = () => console.log('Console was cleared')
let counter = 0;
const MAX_ATTEMPTS = 2000; // Примерно 10 секунд при интервале в 5 мс
console.log('Начинаем поиск CaptchaScript...');
const i = setInterval(() => {
console.log(`Попытка ${counter}: Проверяем наличие CaptchaScript...`);
if (window.CaptchaScript || counter > MAX_ATTEMPTS) {
clearInterval(i);
if (!window.CaptchaScript) {
console.log('CaptchaScript не найден');
} else {
console.log('CaptchaScript найден');
let params = gokuProps;
Array.from(document.querySelectorAll('script')).forEach(s => {
const src = s.getAttribute('src');
if (src && src.includes('captcha.js')) params.captcha_script = src;
if (src && src.includes('challenge.js')) params.challenge_script = src;
});
console.log('intercepted-params: ' + JSON.stringify(params));
}
}
counter++;
}, 5);
И скрипт заработал. Вот прям совсем. Решил капчу и продолжает ее решать при каждом запуске.
Получается будущее наступило, старик. Но это не точно.
Что вам делать с этой информацией? Ну, блин, мне очень нравиться совет - живи теперь с этим. Но, советы раздавать не хочется. Смотрите сами, может пригодится кому для своих проектов...