Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

В программе CapMonster2, начиная с версии 2.4.0.0, появилась возможность распознавать новую ReCaptcha2.

Как это работает

Для отправки ReCaptcha2 на распознавание в CapMonster2, Вам необходимо сформировать запрос, который будет включать изображение из нескольких вариантов ответов и задание в виде дополнительного параметра. Имя параметра: «Task». Значение - вопрос самой ReCaptcha2, например «Дорожные знаки».

...

Если CapMonster2 не смог распознать пончики на более чем одной картинке (2 картинки - минимально возможное количество правильных ответов), то он присылает пустой ответ для того, чтобы Вы могли отправить эту ReCaptcha2 на сервис ручного распознавания.

Использование в ZennoPoster

Для отправки ReCaptcha2 из ZennoPoster Вы можете использовать специальный экшен Распознать ReCaptcha2:

...

Для отправки ReCaptcha2 из ZennoPoster версии выше 5.9 Вы можете использовать подготовленный нами сниппет (Для CapMonster2 версии 2.6.3+. Старый сниппет, который работал с предыдущей версией ReCaptcha2 доступен здесь):

Code Block
// Основные параметры
 
// время ожидания
var waitTime = 1500;
// количество попыток распознать
var tryRecognize = 10;
// количество попыток выбирать изменяющиеся картинки
var dynamicImagesRecognizeAttempts = 20;
// количество попыток загрузить элемент
var tryLoadElement = 60;
// получать полный ответ
bool fullAnswer = false;
// показывать сообщения о прогрессе распознавания
var needShowMessages = false;
// проверять корректность распознанного ответа
var needToCheck = true;
 
// Вспомогательные переменные
 
// вкладка
Tab tab = instance.ActiveTab;
// поздравляем, вы не робот
var success = false;
// время вышло
var timeout = false;
// задание для рекапчи 2
string task = string.Empty;
// url изображения
var src = string.Empty;
// картинка в base64
var imageString = string.Empty;
// ответ на каптчу
string answer = string.Empty;
// капча изменилась
var changed = false;
// пустой ответ
bool answerIsEmpty = false;
// изменяемая каптча
bool dynamicCaptcha = false;
// ввод каптчи несколько раз
bool notOneEnter = false;
var coincidenceReCaptcha2Index = -1;
 
// Проверка прохождения защиты
Action CheckOK= () => 
{
tab.WaitDownloading();
for (int k = 0; k < tryLoadElement; k++)
{
System.Threading.Thread.Sleep(waitTime); // подождём загрузки элементов
var check = tab.FindElementByAttribute("div", "class", "recaptcha-checkbox-checkmark", "regexp", 0);
 
// проверка исчезновения формы
var loadedForm = tab.FindElementByAttribute("div", "class", "primary-controls", "regexp", 0);
if (loadedForm.IsVoid)
{
success = true;
break;
}
else
{
int xPrimaryControlsDisplaysment = loadedForm.DisplacementInTabWindow.X;
int yPrimaryControlsDisplaysment = loadedForm.DisplacementInTabWindow.Y;
 
if (xPrimaryControlsDisplaysment < 0 || yPrimaryControlsDisplaysment < 0) // there are no visible recaptcha
{
success = true;
break;
}
if (check.IsVoid)
break;
}
 
var more = tab.FindElementByAttribute("div", "class", "rc-imageselect-error-select-more", "regexp", 0);
var wrong = tab.FindElementByAttribute("div", "class", "rc-imageselect-incorrect-response", "regexp", 0);
if (!more.IsVoid && !wrong.IsVoid)
{
var isNotVisibleMore = more.GetAttribute("outerhtml").Replace(" ","").Contains("display:none");
var isNotVisibleWrong = wrong.GetAttribute("outerhtml").Replace(" ","").Contains("display:none");
if (isNotVisibleMore && isNotVisibleWrong)
{
if (!check.IsVoid)
{
if (check.OuterHtml.Contains("style=\"\"")) 
{
success = true;
break;
}
else break;
}
}
else break;
}
if (k == (tryLoadElement - 1)) timeout = true;
 
}
};
 
// Подтверждение ответа
Action VerifyAnswer= () =>
{
project.SendInfoToLog("Проверка правильности после ввода динамической капчи", needShowMessages);
 tab.WaitDownloading();
// поиск кнопки "Подтвердить"
HtmlElement apply = tab.FindElementById("recaptcha-verify-button");
if (!apply.IsVoid) apply.Click();
// проверка правильности ответа
CheckOK();
};
 
Action InputNotBotText= () =>
{
tab.WaitDownloading();
var inputField = tab.FindElementByAttribute("input:text", "id", "default-response", "text", 0);
if (!inputField.IsVoid)
{
inputField.SetValue("I am not robot", "Full");
VerifyAnswer();
}
};
 
Action UpdateImage= () => 
{
project.SendInfoToLog("Обновление капчи", needShowMessages);
 
// Обновить капчу если необходимо
if (!changed) 
{
HtmlElement reload = tab.FindElementById("recaptcha-reload-button");
 
if (!reload.IsVoid)
{
reload.Click();
InputNotBotText();
}
else timeout = true;
}
changed = false;
 
for (int k = 0; k < tryLoadElement; k++)
{
System.Threading.Thread.Sleep(waitTime); // waiting for element load
// searching for the picture
var testImage = tab.FindElementByAttribute("img", "class", "rc-image-tile", "regexp", 0);
if (testImage.IsVoid) continue;
// get image url
var newSrc = testImage.GetAttribute("src");
// if the image has been changed, go out
if (newSrc != src) break;
if (k == (tryLoadElement - 1)) timeout = true;
}
};
 
Action VisibleIndexReCaptchaDefinition= () => {
tab.WaitDownloading();
var recaptchaElementsGroup = tab.FindElementsByAttribute("div", "class", "recaptcha-checkbox-checkmark", "regexp");
int length = recaptchaElementsGroup.Elements.Length;
if (length == 1)
{
coincidenceReCaptcha2Index = 0;
return;
}
 
for(int i = 0; i < length; i++)
{
var element = recaptchaElementsGroup.Elements[i];
if (!element.IsVoid)
{
int x = element.DisplacementInTabWindow.X;
int y = element.DisplacementInTabWindow.Y;
 
var suspectVisibleElement = tab.GetElementFromPoint(x, y).DisplacementInTabWindow;
if (x == suspectVisibleElement.X && y == suspectVisibleElement.Y && element.Width != 0 && element.Height != 0 && x != 0 && y != 0)
{
coincidenceReCaptcha2Index = i;
break;
}
}
}
};
 
// Поиск рекаптчи 2
Action SearchReCaptcha2= () => 
{
project.SendInfoToLog("Поиск рекапчи 2", needShowMessages);
 tab.WaitDownloading();
for (int k = 0; k < tryLoadElement; k++)
{
VisibleIndexReCaptchaDefinition();
if (coincidenceReCaptcha2Index < 0) coincidenceReCaptcha2Index = 0;
 
// поиск кнопки "Я не робот"
HtmlElement notRobot = tab.FindElementByAttribute("div", "class", "recaptcha-checkbox-checkmark", "regexp", coincidenceReCaptcha2Index);
 
// кнопка существует
if (!notRobot.IsVoid)
{
// клик по кнопке
notRobot.Click();
System.Threading.Thread.Sleep(waitTime); // pause
 
// если ввод капчи не требуется
var check = tab.FindElementByAttribute("div", "class", "recaptcha-checkbox-checkmark", "regexp", coincidenceReCaptcha2Index);
if (!check.IsVoid)
{
if (check.OuterHtml.Contains("style=\"\""))
{
success = true;
timeout = false;
break;
}
}
}
 
// форма существует
var loadedForm = tab.FindElementByAttribute("div", "class", "primary-controls", "regexp", 0);
if (!loadedForm.IsVoid)
break;
 
// подождем загрузки элементов
System.Threading.Thread.Sleep(waitTime);
if (k == (tryLoadElement - 1)) timeout = true;
}
};
 
// Поиск задания рекапчи 2
Action SearchTask= () => 
{
tab.WaitDownloading();
project.SendInfoToLog("Поиск задания", needShowMessages);
dynamicCaptcha = false;
notOneEnter = false;
answer = String.Empty;
 
for (int k = 0; k < tryLoadElement; k++)
{
HtmlElement taskHe = tab.FindElementByAttribute("div", "class", "rc-imageselect-desc-wrapper", "regexp", 0);
 
if (!taskHe.IsVoid)
{
task = taskHe.GetAttribute("innertext"); // получаем задание
string suspecttask = task.ToLower();
if (suspecttask.Contains("click verify once there are none left") || suspecttask.Contains("when images will be end") ||
suspecttask.Contains("когда изображения закончатся") ||
suspecttask.Contains("коли зображень уже не залишиться, натисніть \"підтвердити\"") ||
suspecttask.Contains("cliquez sur le bouton de validation") ||
suspecttask.Contains("klicken sie") ||
suspecttask.Contains("fai clic su verifica dopo averle selezionate tutte") ||
suspecttask.Contains("gdy wybierzesz wszystkie, kliknij weryfikuj"))
dynamicCaptcha = true;
 
if (suspecttask.Contains("if there are none, click skip") ||
suspecttask.Contains("if they do not exist, click \"skip\"") ||
suspecttask.Contains("wenn du keine siehst") ||
suspecttask.Contains("s'il n'y en a aucune, cliquez sur \"ignorer\"") ||
suspecttask.Contains("если их нет, нажмите \"пропустить\"") || suspecttask.Contains("якщо нічого немає") ||
suspecttask.Contains("ich nie ma, kliknij") ||
suspecttask.Contains("se non ne vedi, fai clic su salta"))
notOneEnter = true;
timeout = false;
break;
}
 
System.Threading.Thread.Sleep(waitTime); // подождём загрузки элемента
if (k == (tryLoadElement - 1)) timeout = true;
}
};
 
// Поиск изображения
Action SearchImage= () => 
{
tab.WaitDownloading();
project.SendInfoToLog("Поиск изображения", needShowMessages);
 
for (int k = 0; k < tryLoadElement; k++)
{
HtmlElement image = null;
if (dynamicCaptcha) image = tab.FindElementByAttribute("table", "class", "rc-imageselect-table", "regexp", 0); 
else image = tab.FindElementByAttribute("img", "class", "rc-image-tile", "regexp", 0);
 
// если есть изображения
if (!image.IsVoid)
{
// получаем url изображения
if (!dynamicCaptcha) src = image.GetAttribute("src");
imageString = image.DrawToBitmap(!dynamicCaptcha);
timeout = false;
break;
}
 
System.Threading.Thread.Sleep(waitTime); // подождем загрузки элементов
if (k == (tryLoadElement - 1)) timeout = true;
}
};
 
// Распознавание
Action Recognize= () => {
project.SendInfoToLog("Распознавание", needShowMessages);
var answerString = ZennoPoster.CaptchaRecognition("CapMonster2.dll", imageString, String.Format("Task={0}&FullAnswer={1}&CapMonsterModule=ZennoLab.ReCaptcha2", task, fullAnswer));
var split = answerString.Split(new [] { "-|-" }, StringSplitOptions.RemoveEmptyEntries);
answer = split[0];
};
 
// Вводим ответ
Action InputAnswer= () => 
{
if (!String.IsNullOrEmpty(answer) && answer != "sorry")
{
        project.SendInfoToLog("Ввод ответа и проверка правильности", needShowMessages);
int count = 0;
 
        string[] answers;
if (answer.Contains(",")) 
answers = answer.Split(new [] { "," }, StringSplitOptions.RemoveEmptyEntries);
else 
{
answers = new string[answer.Length];
for (int i = 0; i < answer.Length; i++)
answers[i] = answer[i].ToString();
}
 
foreach (string c in answers)
{
if (fullAnswer)
if (count == 2) break;
 
int index = Convert.ToInt32(c) - 1;
HtmlElement he = tab.FindElementByAttribute("img", "class", "rc-image-tile", "regexp", index);
 
if (!he.IsVoid) 
{
he.Click(); //кликаем на картинку
System.Threading.Thread.Sleep(500);// подождем немного
}
if (fullAnswer) count++;
}
 
// ищем кнопку "Подтвердить"
HtmlElement apply = tab.FindElementById("recaptcha-verify-button");
if (!apply.IsVoid) apply.Click();
 
// проверим правильность ответа
CheckOK();
if (success) return;
 
// вводим оставшуюся часть ответа
if (fullAnswer)
{
for (int i = count; i < answer.Length; i++)
{
// снова ищем картинку
var testImage = tab.FindElementByAttribute("img", "class", "rc-image-tile", "regexp", 0);
if (testImage.IsVoid) break;
// получаем url изображения
var newSrc = testImage.GetAttribute("src");
// если изображение изменилось, то выходим
if (newSrc != src) break;
else changed = true;
// иначе продолжаем ввод
int index = Convert.ToInt32(answer[i].ToString()) - 1;
var he = tab.FindElementByAttribute("img", "class", "rc-image-tile", "regexp", index);
if (!he.IsVoid) 
{
he.Click();
System.Threading.Thread.Sleep(500); // подождем немного
if (!apply.IsVoid) apply.Click();
CheckOK();
if (success) return;
}
}
}
}
else answerIsEmpty = true;
};
 
//Вводим ответ
Action InputDynamicAnswer= () => 
{
project.SendInfoToLog("Ввод ответа динамической каптчи", needShowMessages);
 
string[] answers;
if (answer.Contains(",")) 
answers = answer.Split(new [] { "," }, StringSplitOptions.RemoveEmptyEntries);
else 
{
answers = new string[answer.Length];
for (int i = 0; i < answer.Length; i++)
answers[i] = answer[i].ToString();
}
 
foreach (string number in answers)
{
int index = Convert.ToInt32(number) - 1;
HtmlElement he = tab.FindElementByAttribute("img", "class", "rc-image-tile", "regexp", index);
if (he.IsVoid) he = tab.FindElementByAttribute("div", "class", "rc-image-tile-wrapper", "regexp", index);
if (!he.IsVoid) 
{
//кликаем на картинку
he.Click();
// подождём немного
System.Threading.Thread.Sleep(500);
}
}
 
// подождём еще немного
System.Threading.Thread.Sleep(waitTime*2);
};
 
//Вводим ответ
Action InputDynamicAnswer2= () => 
{
project.SendInfoToLog("Ввод ответа динамической каптчи", needShowMessages);
 
string[] answers = answer.Split(new [] { "," }, StringSplitOptions.RemoveEmptyEntries);
foreach (string number in answers)
{
int index = Convert.ToInt32(number) - 1;
HtmlElement he = tab.FindElementByAttribute("img", "class", "rc-image-tile", "regexp", index);
if (!he.IsVoid) 
{
//кликаем на картинку
he.Click();
// подождём немного
System.Threading.Thread.Sleep(500);
}
}
 
// подождём еще немного
System.Threading.Thread.Sleep(waitTime*2);
};
 
SearchReCaptcha2();
if (success)
return "ok";
 
if (timeout) throw new Exception("Вышло время ожидания загрузки элемента");
 
for (int i = 0; i < tryRecognize; i++)
{
project.SendInfoToLog(String.Format("Попытка №:{0}", i+1), needShowMessages);
 
InputNotBotText();
SearchTask();
if (timeout) break;
 
// дополнительная проверка
CheckOK();
if (success) return "ok";
 
int count = 0;
 
// если капча изменяемая
if (dynamicCaptcha)
{
while (count < dynamicImagesRecognizeAttempts)
{
if (count > 0)
System.Threading.Thread.Sleep(waitTime * 3); // подождём загрузки исчезающих изображений
 
SearchImage();
if (timeout) break;
Recognize();
if (!String.IsNullOrEmpty(answer) && answer != "sorry") InputDynamicAnswer();
else 
{
VerifyAnswer();
CheckOK();
if (!success) answerIsEmpty = true;
break;
}
count++;
}
}
else
{
if (notOneEnter)
{
while (notOneEnter && !dynamicCaptcha && count < dynamicImagesRecognizeAttempts)
{
SearchImage();
if (timeout) break;
Recognize();
if (!String.IsNullOrEmpty(answer) && answer != "sorry") InputDynamicAnswer2();
VerifyAnswer();
timeout = false;
if (success) break;
SearchTask();
if (timeout) break;
count++;
}
}
else
{
SearchImage();
if (timeout) break;
Recognize();
InputAnswer();
}
}
if (timeout) break;
 
if (!needToCheck) return "ok";
 
if (answerIsEmpty)
{
answerIsEmpty = false;
UpdateImage();
continue;
}
 
if (success) return "ok";
 
if (i != (tryRecognize - 1)) UpdateImage();
if (timeout) break;
}
 
if (timeout) throw new Exception("Вышло время ожидания загрузки элемента");
else throw new Exception("Не распознано. Закончились попытки распознать, прежде чем ответ был засчитан");
 

Примечание

Сниппет может выполнять любое количество попыток разгадать ReCaptcha2. Также, если Вы используете медленные прокси, можно увеличить время ожидания загрузки элементов, количество попыток загрузки и настройка необходимости проверки правильности распознанного ответа. Для этого Вы можете менять параметры:

...