Инструменты пользователя

Инструменты сайта


Боковая панель

Перевод этой страницы:

ru:addons:capmonster:rc2

ReCaptcha 2

С недавних пор, компания Google выпустила новую версию защиты от ботов. На веб-странице появляется кнопка «Я не робот», при нажатии на которую появляется несколько картинок, среди которых нужно выбрать все изображения, указанные в заголовке.

Выглядит это так:

Пример можно посмотреть тут: Демо-страница от google

Включение распознавания в CapMonster

В программе CapMonster 2, начиная с версии 2.4.0.0 появилась возможность распознавать новую ReCaptcha2. Функция распознавания на данный момент находится в режиме тестирования. Для нее необходимо скачать дополнительный файл (около 600МБ), который мы не стали включать в релиз.

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

Требования к системе:

1) Windows 64 bit
2) Более 2Гб RAM.

Скачать CMconnector для CapMonster 2.4.1.2 и выше:

CMconnector.exe

После загрузки, его необходимо положить в папку с программой, как показано на скриншоте:

В CapMonster с версии 2.4.0.0 и выше, у вас будет доступен модуль ZennoLab.ReCaptcha2. Он должен быть активен.



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

CapMonster 2 присылает ответ в виде строки состоящей из цифр - номеров картинок без разделителей на которые надо кликнуть. Номера указываются в порядке убывания вероятности, что на картинке изображен указанный предмет.

Например, нам надо выбрать картинки, где изображены пончики. CapMonster 2 приcлал ответ 328. Значит необходимо кликнуть на 3, 2 и 8 картинку, а затем нажать кнопку «Подтвердить». То есть, 3 картинка вероятнее всего содержит пончик, затем 2 и 8.

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

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

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


// Основные параметры
 
// Основные параметры
 
// время ожидания
var waitTime = 1000;
// количество попыток распознать
var tryRecognize = 3;
// количество попыток выбирать изменяющиеся картинки
var dynamicImagesRecognizeAttempts = 10;
// количество попыток загрузить элемент
var tryLoadElement = 60;
// получать полный ответ
bool fullAnswer = true;
// показывать сообщения о прогрессе распознавания
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= () => 
{
	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
		{
			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 UpdateImage= () => 
{
	project.SendInfoToLog("Обновление каптчи", needShowMessages);
 
	// Обновляем капчу при необходимости
	if (!changed) 
	{
		HtmlElement reload = tab.FindElementById("recaptcha-reload-button");
 
		if (!reload.IsVoid) reload.Click();
		else timeout = true;
	}
	changed = false;
 
	for (int k = 0; k < tryLoadElement; k++)
	{
		System.Threading.Thread.Sleep(waitTime); // подождём загрузки элемента
		// ищем картинку
		var testImage = tab.FindElementByAttribute("img", "class", "rc-image-tile", "regexp", 0);
		if (testImage.IsVoid) continue;
		// получаем url изображания
		var newSrc = testImage.GetAttribute("src");
		// если изображение изменилось, то выходим
		if (newSrc != src) break;
		if (k == (tryLoadElement - 1)) timeout = true;
	}
};
 
Action VisibleIndexReCaptchaDefinition= () => {
	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);
 
	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); // подождём немного
 
			// если ввод каптчи не требуется
			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= () => 
{
	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("когда изображения закончатся") || suspecttask.Contains("коли зображень уже не залишиться, натисніть \"підтвердити\"") || suspecttask.Contains("fai clic su Verifica dopo averle selezionate tutte")) dynamicCaptcha = true;
			if (suspecttask.Contains("if there are none, click skip") || suspecttask.Contains("если их нет, нажмите \"пропустить\"") || suspecttask.Contains("якщо нічого немає натисніть \"пропустити\"") || 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= () => 
{
	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;
		foreach (char c in answer)
		{
			if (fullAnswer)
				if (count == 2) break;
 
			int index = Convert.ToInt32(c.ToString()) - 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);
};
 
// Подтверждение ответа
Action VerifyAnswer= () =>
{
	project.SendInfoToLog("Проверка правильности после ввода динамической капчи", needShowMessages);
 
	// ищем кнопку "Подтвердить"
	HtmlElement apply = tab.FindElementById("recaptcha-verify-button");
	if (!apply.IsVoid) apply.Click();
	// проверим правильность ответа
	CheckOK();
};
 
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);
 
	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("Не распознано. Закончились попытки распознать, прежде чем ответ был засчитан");
 

Примечание

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

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

// время ожидания
var waitTime = 1000;
// количество попыток распознать
var tryRecognize = 3;
// количество попыток загрузить элемент
var tryLoadElement = 60;
// проверять корректность распознанного ответа
var needToCheck = true;

Все, описанные в предыдущем разделе действия, сниппет выполняет с одним уточнением: он сначала кликает на 2 картинки (минимально возможное количество правильных ответов), затем нажимает «подтвердить». Если этих ответов недостаточно, то сниппет кликает на следующую картинку, нажимает «подтвердить» и так далее.

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

В случае, когда в браузере используется старый или телефонный UserAgent, ReCaptcha2 имеет другой вид (например, отсутствует кнопка «я не робот»), клики производятся на чекбоксы каждой необходимой картинки

В зависимости от IP-адреса, с которого вы производите вышеописанные манипуляции, ReCaptcha2 может «закрыть глаза» на нехватку клика на одну из картинок или на клик на неправильную картинку. Однако, при постоянных ошибках, ReCaptcha2 может не принимать даже правильные ответы, поэтому рекомендуется использовать хорошие прокси.

Процент пробива ReCaptcha 2 при таком подходе выше, чем при способе, когда клики производятся сразу на все указанные картинки, а затем производится нажатие кнопки «Подтвердить». Но доступна и такая возможность, например, для отправки каптч в CapMonster 2 не из ZennoPoster.

Для этого нужно заменить:

bool fullAnswer = true;

на:

bool fullAnswer = false;
ru/addons/capmonster/rc2.txt · Последние изменения: 2017/03/20 18:04 — afameless