Решение Амазон капчи Waf Captcha на полном автомате, имея за плечами практически нулевой опыт в разработке

Небольшой эпиграф — если вы делаете инструкцию, так делайте ее до конца, а то в инструкции как решить Амазон капчу — джун ногу сломит.

Собственно к чему все это? Да к тому, что когда мне потребовалось решить капчу от Амазон, пресловутую Waf Captcha я пошел копать на сервис, которым постоянно пользуюсь при работе с Кей Коллектором, и некоторыми другими сервисами (2капча — жаль Хабр банит статьи за реферальные ссылки).

Ну и нашел там инструкцию, ссылку на которую собственно и привел выше. Как вам вероятно стало понятно из эпиграфа — я ни черта не понял, вернее я понял, что надо использовать АПИ, но на этом все…

С Селениумом было реально проще.

Главная проблема — малый таймаут, который выделяется на решение со стороны Амазона. Время на решение капчи ограничено и если ответа нет, то капча обновляется (у нее обновляются 2 параметра — iv и context).
Получается, что таймаут свежести капчи около 30 секунд, а за это время необходимо найти на странице параметры, скопировать их, вставить в код скрипта и запустить его, после этого 2капча должна ее решить и вернуть правильный ответ. Я пробовал это сделать пару безуспешных часа, вырабатывал автоматизм действий, но увы, на поиск и замену изменяемых параметров уходит не менее 12–15 секунд, и остается от 15 до 18 секунд мы решение капчи сервисом, что в нынешних реалиях звучит достаточно фантастически.

Тут нужен другой подход, искать и подставлять параметры должен скрипт, но как его написать человеку, который в своей жизни ничего сложнее Ahrefs не видел?

a9a437245504c2946666c6c62be39eeb.png

Вот именно по этой причине, я считаю, что инструкции, подобные упомянутым в статье необходимо делать более подробными, чем — «Просто используй Апи, ты че совсем куку?»

Решение

По итогу решение было найдено и заняло оно у меня примерно 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

Но я же в этих ваших интернетах уже очень долго и понимаю, что код просто так не заработает, если на компе не установленно нужных библиотек, мой нейроконсультант и тут мне помог

Изучив код, который я дал ему в виде скриншотов, он порекомендовал установить следующие пакеты

puppeteer

2captcha-ts

playwright

Единственно, я не совсем понял, нафига тут нужен 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 рекомендаций, что надо делать чтобы код заработал, но

9c6adebc8d4f2256edd7b160fa2af942.jpg

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

6b2bf2801392ec42ee99e3df68813092.jpg

Ошибка была связана с использованием синтаксиса ES6 import в Node.js. Для его использования нужно либо указать тип модуля в package.json, либо изменить расширение файла на .mjs

Мне было лень указывать тип модуля в package.json и я пошел по пути наименьшего сопротивления, тупо переименовал расширение файла index с js на mjs

Следующая ошибка была связана с подключаемым пакетом 2captcha-ts, но подробно описывать их не хочется, скажу лишь что я изменил код, отвечающий за запуск этого модуля несколько раз, добавил логирование и проверку корректности подключения файла .env

И это все равно не сработало, скрипт продолжал выдавать ошибку и упорно не хотел работать. Я сравнил скриншот и код который мне вытащил оттуда Чат и нашел небольшую опечатку, которая и была корнем проблемы.

Но, как оказалось, и это не помогло — выпала ошибка APIKEY is not defined in .env file

Это мы пофиксили добавлением нового пакета

dotenv

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')

// 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);

И скрипт заработал. Вот прям совсем. Решил капчу и продолжает ее решать при каждом запуске.

Получается будущее наступило, старик. Но это не точно

Что вам делать с этой информацией? Ну, блин, мне очень нравиться совет — живи теперь с этим. Но, советы раздавать не хочется. Смотрите сами, может пригодится кому для своих проектов…

© Habrahabr.ru