ZennoLab

Automate everything

User Tools

Site Tools


Sidebar

Translations of this page:

en:addons:capmonster:rc2

ReCaptcha 2

Google has recently developed new kind of protection from bots called ReCaptcha2. On websites with such protection you get “I'm not robot” option, which you have to check and then select several pictures specified in task title.

ReCaptcha2 looks like this:

Here you can get ReCaptcha2 sample: Demo-page from Google

Enabling recognition in CapMonster

CapMonster2 software starting from 2.4.0.0 version allows to recognize new ReCaptcha2. This feature is currently in beta-testing. To use it, you should download additional module CMconnector.exe, which is not included into released version. The module can be downloaded from our server.

After downloading, copy this file to the directory C:\Program Files (x86)\ZennoLab\CapMonster Pro\Progs\RC2. Thus, you will add ZennoLab.ReCaptcha2 recognition module to CapMonster2. It should be enabled.

NOTE! The module works only on Windows 64-bit system with more than 2GB RAM.

To send captcha to CapMonster 2, you should create a request that includes captcha image with several answer variants and task as additional parameter. Parameter name: «Task». Value - question in recaptcha, for example «Select all images with trains»

How it works

CapMonster2 answer to this captcha will be string with numbers - numbers of pictures that should be clicked. Numbers are sorted in decreasing probability that the picture contains specified object.

For example, you should select pictures with soup. CapMonster recognizes it as 29. That means that soup is most probably displayed on the picture #2, then picture 9. So, you should click the pictures 2,9 and then press “Verify”.

If CapMonster2 could not recognize soup on more than one picture, (2 pcitures minimum for correct response) it returns empty answer, so that you will be able to send this captcha to recognition service.

Using in ZennoPoster

To recognize ReCaptcha2 in ZennoPoster (ver 5.9+) using CapMonster2, use the following C# snippet: (This snippet should be used in Capmonster version 2.6.3+. The old snippet for previous program versions is available here)


// Main parameters
 
// waiting time
var waitTime = 1000;
// the number of recognition attempts
var tryRecognize = 3;
// the number of attempts to choose dynamic pictures
var dynamicImagesRecognizeAttempts = 10;
// the number of attempts to load the element
var tryLoadElement = 60;
// get the full answer
bool fullAnswer = true;
// show the messages about recognition progress
var needShowMessages = false;
// check correctness of the recognized answer
var needToCheck = true;
 
// Secondary variables
 
// tab
Tab tab = instance.ActiveTab;
// congratulations, you are not a robot
var success = false;
// time is over
var timeout = false;
// task for recaptcha 2
string task = string.Empty;
// image url
var src = string.Empty;
// picture in base64 format
var imageString = string.Empty;
// answer for the captcha
string answer = string.Empty;
// the captcha has been changed
var changed = false;
// empty answer
bool answerIsEmpty = false;
// dynamic captcha
bool dynamicCaptcha = false;
// input the captcha several times
bool notOneEnter = false;
var coincidenceReCaptcha2Index = -1;
 
// Checking of protection passing
Action CheckOK= () => 
{
	for (int k = 0; k < tryLoadElement; k++)
	{
		System.Threading.Thread.Sleep(waitTime); // waiting for element load
		var check = tab.FindElementByAttribute("div", "class", "recaptcha-checkbox-checkmark", "regexp", 0);
 
		// checking the form's disappearing
		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("Captcha's update", needShowMessages);
 
	// Update of the captcha if it is necessary
	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); // 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= () => {
	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;
			}
		}
	}
};
 
// Searching for recaptcha 2
Action SearchReCaptcha2= () => 
{
	project.SendInfoToLog("Searching for recaptcha 2", needShowMessages);
 
	for (int k = 0; k < tryLoadElement; k++)
	{
		VisibleIndexReCaptchaDefinition();
		if (coincidenceReCaptcha2Index < 0) coincidenceReCaptcha2Index = 0;
 
		// searching for the button "I am not a robot"
		HtmlElement notRobot = tab.FindElementByAttribute("div", "class", "recaptcha-checkbox-checkmark", "regexp", coincidenceReCaptcha2Index);
 
		// the button exists
		if (!notRobot.IsVoid)
		{
			// click to the button
			notRobot.Click();
			System.Threading.Thread.Sleep(waitTime); // pause
 
			// if input of the captcha is not necessary
			var check = tab.FindElementByAttribute("div", "class", "recaptcha-checkbox-checkmark", "regexp", coincidenceReCaptcha2Index);
			if (!check.IsVoid)
			{
				if (check.OuterHtml.Contains("style=\"\""))
				{
					success = true;
					timeout = false;
					break;
				}
			}
		}
 
		// the form exists
		var loadedForm = tab.FindElementByAttribute("div", "class", "primary-controls", "regexp", 0);
		if (!loadedForm.IsVoid)
			break;
 
		// waiting for element load
		System.Threading.Thread.Sleep(waitTime);
		if (k == (tryLoadElement - 1)) timeout = true;
	}
};
 
// searching for recaptcha 2 task
Action SearchTask= () => 
{
	project.SendInfoToLog("Searching for the task", 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"); // getting the task
			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("fai clic su Verifica dopo averle selezionate tutte")) dynamicCaptcha = true;
			if (suspecttask.Contains("if there are none, click skip") || suspecttask.Contains("if they do not exist, click \"skip\"") || suspecttask.Contains("якщо нічого немає натисніть \"пропустити\"") || suspecttask.Contains("se non ne vedi, fai clic su salta")) notOneEnter = true;
			timeout = false;
			break;	
		}
 
		System.Threading.Thread.Sleep(waitTime); // waiting for load element
		if (k == (tryLoadElement - 1)) timeout = true;
	}
};
 
// searching for the image
Action SearchImage= () => 
{
	project.SendInfoToLog("Searching for the image", 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 there is the image
		if (!image.IsVoid)
		{
			// getting the image url
			if (!dynamicCaptcha) src = image.GetAttribute("src");
			imageString = image.DrawToBitmap(!dynamicCaptcha);
			timeout = false;
			break;
		}
 
		System.Threading.Thread.Sleep(waitTime); // waiting for element load
		if (k == (tryLoadElement - 1)) timeout = true;
	}
};
 
// Recognition
Action Recognize= () => {
	project.SendInfoToLog("Recognition", 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];
};
 
//Input the answer
Action InputAnswer= () => 
{
	if (!String.IsNullOrEmpty(answer) && answer != "sorry")
	{
        project.SendInfoToLog("Input the answer and checking of correctness", 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(); //click to the image
				System.Threading.Thread.Sleep(500);// pause
			}
			if (fullAnswer) count++;
		}
 
		// searching for the button "Submit"
		HtmlElement apply = tab.FindElementById("recaptcha-verify-button");
		if (!apply.IsVoid) apply.Click();
 
		// checking correctness of the answer
		CheckOK();
		if (success) return;
 
		// input the other part of the answer
		if (fullAnswer)
		{
			for (int i = count; i < answer.Length; i++)
			{
				// searching for the picture again
				var testImage = tab.FindElementByAttribute("img", "class", "rc-image-tile", "regexp", 0);
				if (testImage.IsVoid) break;
				// getting the image url
				var newSrc = testImage.GetAttribute("src");
				// if the image has been changed, go out
				if (newSrc != src) break;
				else changed = true;
				// otherwise to continue the insertion
				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); // pause
					if (!apply.IsVoid) apply.Click();
					CheckOK();
					if (success) return;
				}
			}
		}
	}
	else answerIsEmpty = true;
};
 
//Input the answer
Action InputDynamicAnswer= () => 
{
	project.SendInfoToLog("Input the answer of dynamic captcha", 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) 
		{
			//click to the image
			he.Click();
			// pause
			System.Threading.Thread.Sleep(500);
		}
	}
 
	// pause
	System.Threading.Thread.Sleep(waitTime*2);
};
 
//Input the answer
Action InputDynamicAnswer2= () => 
{
	project.SendInfoToLog("Input the answer of dynamic captcha", 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) 
		{
			//click to the image
			he.Click();
			// pause
			System.Threading.Thread.Sleep(500);
		}
	}
 
	// pause
	System.Threading.Thread.Sleep(waitTime*2);
};
 
// Confirmation of the answer
Action VerifyAnswer= () =>
{
	project.SendInfoToLog("Checking correctness after input of dynamic captcha", needShowMessages);
 
	// searching for the button "Submit"
	HtmlElement apply = tab.FindElementById("recaptcha-verify-button");
	if (!apply.IsVoid) apply.Click();
	// checking correctness of the answer
	CheckOK();
};
 
SearchReCaptcha2();
if (success)
	return "ok";
 
if (timeout) throw new Exception("Waiting time of element load is over");
 
for (int i = 0; i < tryRecognize; i++)
{
	project.SendInfoToLog(String.Format("Попытка №:{0}", i+1), needShowMessages);
 
	SearchTask();
	if (timeout) break;
 
	// Additional checking
	CheckOK();
	if (success) return "ok";
 
	int count = 0;
 
	// if captcha is dynamic
	if (dynamicCaptcha)
	{
		while (count < dynamicImagesRecognizeAttempts)
		{
			if (count > 0)
				System.Threading.Thread.Sleep(waitTime * 3); // waiting for load of disappearing images
 
			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("Waiting time of element load is over");
else throw new Exception("It has not been recognized. The recognition attempts has ended, before the answer has been counted");

NOTE

Currently CapMonster 2 supports only english, russian and ukrainian language ReCaptcha.

The snippet allows to perform any number of attempts to recognize captcha. Also, if you use slow proxies, you can increase loading elements waiting timeout and number of attempts to load elements. For it you should change the following parameters:

// waiting timeout
var waitTime = 1000;
// recognition attempts
var tryRecognize = 3;
// attempt to load element
var tryLoadElement = 60;
// need to check correctness of answer
var needToCheck = true;

One note about snippet operation: at first, it clicks two pictures (munimum for correct response), then presses “Verify”. If pictures are not enough, it clicks one more and presses “Verify”, and so on.

This is the best way, as ReCaptcha2 sometimes accepts answer without one picture or with extra picture. Thus, you can avoid possible mistakes.

In case you use old or mobile user-agents, ReCaptcha2 will look differently. It won't display “I'm not robot” button, so the snippet will click checkboxes on captcha pictures.

Depending on your ip-address, ReCaptcha2 may accept answer without or with extra picture. However, if you make mistakes regularly, it won't accept even correct answers. So, we recommend to use reliable proxies.

The probablilty to break ReCaptcha2 in the described way is higher than clicking all specified pictures and only then pressing “Verify”. However, the second variant is also possible. For example, if you are going to send ReCaptcha2 to CapMonster2 from other software.

For it you should replace:

bool fullAnswer = true;

with:

bool fullAnswer = false;
en/addons/capmonster/rc2.txt · Last modified: 2017/04/25 11:20 by vladz