- Токеном
- Прокликиванием картинок
- Через расширение
Что нам с вами нужно для успешного решения капчи:
- Уметь читать документацию API сервисов для решения капч, составлять запросы и обрабатывать ответы
- Уметь получать задание и картинку со страницы
Разбираемся с составлением запросов
Весь процесс будем рассматривать на примере Capmonster.cloud. Освоив работу с ним, вы сможете работать и с любым другим сервисом по решению капч.
Первым делом заходим на страницу с описанием API. Для этого достаточно вбить в поисковик «API название сервиса». Для capmonster.cloud - https://zennolab.atlassian.net/wiki/spaces/APIS/pages/589825
По сути нам с вами нужно сделать всего два запроса:
- Создать задачу
- Получить результат решения
Перейдем на страницу создания задачи и посмотрим, что там есть.
1 – урл, куда надо отправлять запрос
2 – тип данных. Почти всегда это json
3 – какие параметры надо передавать.
4 – тип параметра. Если это string, то заключаем в двойные кавычки. Если написано «объект», значит внутрь него будут вложены другие параметры
5 – обязательный или нет. Если не передать обязательный параметр, мы получим ошибку.
6 – описание
Давайте сразу перейдем в PM и заполним кубик POST запроса
1-урл (https://api.capmonster.cloud/createTask)
2-тип данных. Т.к. у нас в документации было прописано json, мы прописываем application/json
3 – тело запроса в формате JSON. JSON – это текстовый формат обмена данными. Заполняется в фигурных скобках в формате {“ключ”:”значение”}. Обратите внимание, что task у нас объект, поэтому в качестве значения выступает другой объект (поэтому я поставил фигурные скобки, но пока не заполнил содержимое). Также обратите внимание на значение ключа clientkey – оно будет подставлено из переменной cfg_apikey
4 – переменная, куда ляжет ответ от сервиса capmonster.cloud.
Чтобы заполнить task, нам надо перейти на страницу с нужной капчей. В нашем случае это FunCaptcha. Но сначала небольшое отступление.
Recaptcha, hCaptcha, FunCaptcha можно решить двумя способами – токеном и кликами. В первом случае решение идет токеном, т.е. вам будет прислан ответ в «текстовом» виде, который вы самостоятельно должны вставить на страницу и отправить сайту. Во втором случае вы высылаете сервису картинку, а он говорит, куда вам надо кликнуть. Мы работаем с вариантом №2.
Название нужного нам способа ComplexImageTask - https://zennolab.atlassian.net/wiki/spaces/APIS/pages/2293497857/ComplexImageTask+Funcaptcha+Funcaptcha
Обратите внимание на параметры imageUrls и imagesBase64. В данном случае нам на выбор дается один из двух вариантов: либо мы высылаем массив урл (которые ведут на изображения), либо сами картинки в формате base64. Мы будем пользоваться вариантом №2. Давайте перейдем в PM и заполним содержимое нашего task
C#:
{
"clientKey": "{-Variable.cfg_apiKey-}",
"task": {
"type": "ComplexImageTask",
"class": "funcaptcha",
"imageUrls": [
"{-Variable.images-}"
],
"metadata": {
"Task": "{-Variable.issue-}"
}
}
}
И не забудьте создать переменные, которые мы использовали в кубиках (нажимаем на плюсик): cfg_apiKey, images, issue, taskId.
Добываем задание и картинку
Достать эти данные можно двумя способами: через трафик и через содержимое страницы. Скорее всего вы будете работать именно с трафиком, но поначалу может быть сложновато, если раньше вы этого не делали.
В трафике отображаются все запросы, посылаемые браузером. Мы можем вытаскивать оттуда любые данные, в том числе и картинки. Давайте сначала потренируемся, а потом займемся уже капчей. Будем вытаскивать вот эту картинку и заголовок с сайта nashcsgo.com
Включаем окно трафика
Прописываем в кубике c# (выполняем это 1 раз перед началом работы с сайтом, чтобы не было проблем в zp)
C#:
instance.UseTrafficMonitoring = true;
Выбираем img, чтобы отображались только картинки(1), жмём по любой картинке(2), выбираем preview, чтобы видеть сами картинки (3) и находим ту, что нам нужна.
Жмём на Headers(1) и забираем урл картинки (2)
Теперь отыщем наш заголовок. Для этого прям там же жмем ctrl+f и в появившемся окне вводим наш заголовок. Жмем enter
Жмём на найденное совпадение (3). Жёлтым подчеркнут наш заголовок. Жмём на headers, чтобы забрать урл.
Теперь займёмся перебором всего трафика. Наша задача – выцепить два урл, которые мы с вами нашли и достать тело (т.е. то, что во вкладке response).
Сначала создайте две переменные - img_base64 для картинки и issue
переходим в кубик c#.
C#:
var traffic = instance.ActiveTab.GetTraffic();
project.SendInfoToLog($"количество запросов в трафике - {traffic.Count().ToString()}");
foreach (var t in traffic)
{
//если в урл содержится images/skinsmin.jpg (картинка)
if(t.Url.Contains("images/skinsmin.jpg"))
{
project.SendInfoToLog("нашли картинку");
//дожидаемся полной прогрузки тела запроса
t.WaitResponse(30, 2);
//сохраняем в переменную "images" в формате base64 (создайте переменную вручную!)
var imageBytes = t.ResponseBody;
project.Variables["images"].Value = Convert.ToBase64String(imageBytes);
//сохраняем на пк (этого делать не нужно, это просто для самопроверки)
File.WriteAllBytes(project.Directory + @"\1.jpg", imageBytes);
}
//если урл равен https://nashcsgo.com/
if(t.Url == "https://nashcsgo.com/")
{
project.SendInfoToLog("нашли заголовок");
t.WaitResponse(30, 2);
//сохраняем в переменную "issue" тело запроса
var imageBytes = t.ResponseBody;
project.Variables["issue"].Value = Encoding.UTF8.GetString(imageBytes, 0, imageBytes.Length);
}
}
//проверка на пустоту и выход по ошибке
if(string.IsNullOrWhiteSpace(project.Variables["images"].Value)) throw new Exception("картинка не найдена");
if(string.IsNullOrWhiteSpace(project.Variables["issue"].Value)) throw new Exception("заголовок не найден");
Хотел бы заострить ваше внимание на одном важном моменте – после того, как вы выполните этот код трафик будет очищен. Нет, визуально вы всё ещё будете его видеть, но если выполнить код ещё раз – то он уже не сработает. Важно держать это в голове.
Например, вы зашли на страницу с капчей. Запускаете код, что-то не работает, вы правите и снова запускаете – вообще всё перестает работать. Что за фигня? Просто трафик очистился. Вам нужно заново дойти до страницы с капчей и потом уже снова запустить свой код. Обход для этого есть, но там возникают другие проблемы и лучше просто смириться с подобным неудобством.
Так, если что-то непонятно, лучше проделайте всё сами, ну а мы перейдем уже к капче. Тут будем делать тоже самое (почти). Выставляем в настройках английский профиль, т.к. нам нужно отсылать задание именно на английском языке
Перейдем на github.com и начнем процесс регистрации, пока не дойдем до капчи. Откройте также chromeDevTools и вкладку Network, чтобы мы могли отыскать картинку.
Что мы здесь видим? Во-первых, нам отдаётся изображение целиком, так что никаких дополнительным манипуляций не нужно. Во-вторых, нам подходят два урл: rtig/image и blob. Нам нужен rtig/image. Почему? Потому что blob не отображается в мониторе трафика. Почему? Вопрос не ко мне.
C#:
var traffic = instance.ActiveTab.GetTraffic();
project.Variables["images"].Value = "";
project.SendInfoToLog($"количество запросов в трафике - {traffic.Count().ToString()}");
foreach (var t in traffic)
{
if(t.Url.Contains("rtig/image"))
{
project.SendInfoToLog("нашли картинку");
t.WaitResponse(30, 2);
var imageBytes = t.ResponseBody;
project.Variables["images"].Value = Convert.ToBase64String(imageBytes);
File.WriteAllBytes(project.Directory + @"\1.jpg", imageBytes);
}
}
//проверка на пустоту и выход по ошибке
if(string.IsNullOrWhiteSpace(project.Variables["images"].Value)) throw new Exception("картинка не найдена");
C#:
//находим элемент с заданием
var issue = instance.ActiveTab.FindElementByXPath("//*[@id='root']//h2/span", 0);
if(issue.IsVoid) throw new Exception(«не нашли задание на странице»);
//убираем <strong>, </strong>, (1 of *) и пробелы и сохр в переменную issue
string noStrong = issue.InnerHtml.Replace("<strong>", "").Replace("</strong>","").Trim();
project.Variables["issue"].Value = noStrong.Replace(Regex.Match(noStrong, @”\(.*\)”).Value, @"").Trim();
project.SendInfoToLog("получили задание – " + project.Variables["issue"].Value);
C#:
//достаем наш урл
var imgBlob = instance.ActiveTab.FindElementByXPath("//img[@aria-live='assertive']", 0);
if(imgBlob.IsVoid) throw new Exception("не нашли картинку");
string styleBlob = imgBlob.GetAttribute("style");
string linkBlob = Regex.Match(styleBlob, @"blob:.*(?="")").Value;
if(string.IsNullOrWhiteSpace(linkBlob)) throw new Exception("не смогли достать урл картинки регуляркой");
//открываем в новой вкладке
instance.NewTab("1");
instance.ActiveTab.Navigate(linkBlob);
instance.ActiveTab.WaitDownloading();
Thread.Sleep(1000);
//сохраняем на пк
Bitmap b = new Bitmap(instance.ActiveTab.FindElementByXPath("//img", 0).DrawAsBitmap(true));
b.Save(project.Directory + @"\1.jpg", System.Drawing.Imaging.ImageFormat.Jpeg);
b.Dispose();
//считываем с пк
byte[] massByte = File.ReadAllBytes(project.Directory + @"\1.jpg");
string base64 = Convert.ToBase64String(massByte);
return base64;
Отправка на распознование и получение результата
Зайдите в личный кабинет capmonster.cloud, скопируйте ключ и вставьте в переменную cfg_apikey
Теперь у нас есть всё необходимое для отправки на сервис capmonster.cloud. Выполняем наш кубик create и смотрим, что нам прислали в ответ. Чтобы проверить, найдите запрос в трафике, нажмите по нему два раза мышкой и перейдите на вкладку ответ. Если там error id=0, значит всё ок
Сделаем проверку на то, что errorId == 0. Если это не так, то выйдем по ошибке и выведем сообщение в лог. Я делаю регулярками (это неправильно, но мне так привычнее), вы можете делать как вам удобно (с помощью кубика json)
errorId\":0
Достаем taskId из ответа и кладем в переменную taskId. Ставим паузу в 1 сек и делаем запрос на получение ответа.
(?<="taskId":)\d+
Тут вы можете получить следующие ответы:
- Ready – капча решена
- Processing – в процессе решения
- ERROR_CAPTCHA_UNSOLVABLE – сервис не может решить капчу
Нам нужно сделать обработку для всех трех вариантов (если непонятно сделайте себе на кубиках).
C#:
//проверяем на ERROR_CAPTCHA_UNSOLVABLE
string errorUnsolvable = Regex.Match(project.Variables["getResult"].Value, @"ERROR_CAPTCHA_UNSOLVABLE").Value;
if(!string.IsNullOrWhiteSpace(errorUnsolvable)) throw new Exception("ERROR_CAPTCHA_UNSOLVABLE");
//проверяем статус
string status = Regex.Match(project.Variables["getResult"].Value, @"(?<=status"":"").*?(?="")").Value;
if(string.IsNullOrEmpty(status)) throw new Exception("не смогли извлечь status из ответа - " + project.Variables["getResult"].Value);
switch(status)
{
//получили processing
case "processing":
project.SendInfoToLog("капча в процессе решения");
project.Variables["statusSolution"].Value = "processing";
break;
//получили ready
case "ready":
project.SendInfoToLog("капча решена");
project.Variables["statusSolution"].Value = "ready";
break;
default:
throw new Exception("не смогли определить статус (не processing и не ready) - " + status);
}
Сразу скажу, что ERROR_CAPTCHA_UNSOLVABLE не так, чтобы редкое явление. Тяжелые задания сервисы вообще не решают и не будут решать. Легкими заданиями считаются те, где нужно повернуть что-то в направлении руки и самих вариантов не больше 5. Ещё недавно это были животные и capmonster.cloud успешно их решал, но сейчас, как видим, картинки обновили и capmonster.cloud с ними не справляется. Возможно, на момент выхода статьи нейросеть уже будет обучена и сможет решать такие задания.
Чтобы попадались легкие задания используйте хорошие прокси и движок хромиум.
Так что далее вам придется поверить мне на слово. Вам придет ответ такого вида:
{"solution":{"answer":[false,false,false,false,false,true],"metadata":null},"cost":0.00015,"status":"ready","errorId":0,"errorCode":null,"errorDescription":null}
Там где true – это нужная нам картинка. Соответственно, нам надо с вами посчитать, какая она. После этого жмем по стрелке нужное количество раз и отправляем ответ.
C#:
//узнаем сколько раз надо кликнуть по стрелке
project.Json.FromString(project.Variables["getResult"].Value);
var otv = project.Json.solution.answer.ToString().Split(',');
string countClickCapmonster = Convert.ToString(otv.Length - 1);
if(string.IsNullOrWhiteSpace(countClickCapmonster)) throw new Exception("не смогли получить сколько раз надо кликать по стрелке вправо CapmonsterCloud");
project.SendInfoToLog($"нужно кликнуть {countClickCapmonster} раз");
//находим стрелку вправо
HtmlElement rightArrow = instance.ActiveTab.FindElementByXPath("(//a/*/*[name()='circle']/following-sibling::*)[last()]|(//a/*/*[name()='circle'])[last()]", 0);
if(rightArrow.IsVoid) throw new Exception("не найдена стрелка для переключения картинок");
//щелкаем нужное количество раз
for(int i=0;i<Convert.ToInt32(countClickCapmonster);i++)
{
rightArrow.Click();
Thread.Sleep(1000);
}
//жмем submit
var buttonSubmit = instance.ActiveTab.FindElementByXPath("//button[text()='Submit']", 0);
if(buttonSubmit.IsVoid) throw new Exception("не найдена кнопка submit");
buttonSubmit.Click();
Thread.Sleep(3000);
project.SendInfoToLog("нажали на нужное изображение");
Теперь надо определить есть ли ещё задания. Если да, то снова ищем картинку в трафике и отправляем на сервис. Если нет, тогда определяем, успешно ли мы решили капчу и действуем исходя из этого (если неудачно, можем попытаться снова или можно выйти по ошибке)
//если стрелка вправо есть, значит задания ещё есть
HtmlElement rightArrow = instance.ActiveTab.FindElementByXPath("(//a/*/*[name()='circle']/following-sibling::*)[last()]|(//a/*/*[name()='circle'])[last()]", 0);
if(!rightArrow.IsVoid)
{
project.SendInfoToLog("задания ещё есть, продолжаем решать");
project.Variables["status"].Value = "process";
return "";
}
//решено неверно
HtmlElement notRight = instance.ActiveTab.FindElementByXPath("//h2[contains(text(), 'That was not quite right.')]", 0);
if(!notRight.IsVoid)
{
project.SendInfoToLog("капча была решена неверно");
project.Variables["status"].Value = "notRight";
return "";
}
//галочка
var galka = instance.ActiveTab.FindElementByXPath("//img[contains(@src, 'thub-api.arkoselabs.com/cdn/fc/assets/style-manager/assets')]", 0);
if(!galka.IsVoid)
{
project.SendInfoToLog("капча решена верно");
project.Variables["status"].Value = "ready";
return "";
}
//если не смогли опрелелить
project.Variables["status"].Value = "unknown";
C#:
//если стрелка вправо есть, значит задания ещё есть
HtmlElement rightArrow = instance.ActiveTab.FindElementByXPath("(//a/*/*[name()='circle']/following-sibling::*)[last()]|(//a/*/*[name()='circle'])[last()]", 0);
if(!rightArrow.IsVoid)
{
project.SendInfoToLog("задания ещё есть, продолжаем решать");
project.Variables["status"].Value = "process";
return "";
}
//решено неверно
HtmlElement notRight = instance.ActiveTab.FindElementByXPath("//h2[contains(text(), 'That was not quite right.')]", 0);
if(!notRight.IsVoid)
{
project.SendInfoToLog("капча была решена неверно");
project.Variables["status"].Value = "notRight";
return "";
}
//галочка
var galka = instance.ActiveTab.FindElementByXPath("//img[contains(@src, 'thub-api.arkoselabs.com/cdn/fc/assets/style-manager/assets')]", 0);
if(!galka.IsVoid)
{
project.SendInfoToLog("капча решена верно");
project.Variables["status"].Value = "ready";
return "";
}
//если не смогли опрелелить
project.Variables["status"].Value = "unknown";
Заработок на решении капч
5 октября я на форуме разместил тему о продаже плагина для решения FunCaptcha. За прошедшее время было 23 продажи на общую сумму 71 000 руб + было пара индивидуальных заказов. Размещался я только на этом форуме. Вроде бы неплохо, но есть несколько нюансов:
- Не считая пары человек, взявших плагин на месяц, последняя продажа с форума была 6 ноября.
- 15 продаж для меня сделал партнер, т.е. мне просто повезло. Человек предложил приводить клиентов за часть дохода, и я согласился. Если бы не он, у меня было бы всего 8 продаж.
Я тут ни на что не рассчитывал и добавил его больше по приколу. Какого же было моё удивление, когда я в один из дней увидел у себя на балансе $30. Поначалу я даже не мог врубиться, откуда они взялись и только потом до меня дошло, что я же размещал идентификатор. Сейчас у меня на балансе $130. Не так уж и плохо с 23 клиентов.
Вот тут lord_alfred поделился своими цифрами, можете также глянуть. У capmonster.cloud также есть партнерка, но нужно написать в саппорт, чтобы вам дали доступ. Так что этот вариант также не стоит списывать со счетов.
На этом всё. Для закрепления материала также можете посмотреть видео, где мы разбираемся с Recaptcha.
- Номер конкурса статей
- Двадцатый конкурс статей
Вложения
-
22 КБ Просмотры: 120
-
22,6 КБ Просмотры: 70
Для запуска проектов требуется программа ZennoPoster или ZennoDroid.
Это основное приложение, предназначенное для выполнения автоматизированных шаблонов действий (ботов).
Подробнее...
Для того чтобы запустить шаблон, откройте нужную программу. Нажмите кнопку «Добавить», и выберите файл проекта, который хотите запустить.
Подробнее о том, где и как выполняется проект.
Последнее редактирование модератором: