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 need to create a request, that includes the image of 9 variants of answers and a task as an additional option. Option name: «Task». Value - the question of the recaptcha 2, 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:


// Main settings
 
// waiting timeout
var waitTime = 1000;
// recognition attempts
var tryRecognize = 3;
// attempts to load element
var tryLoadElement = 60;
// receive full answer
bool fullAnswer = true;
// show recognizing progress messages
var needShowMessages = false;
// need to check correctness of answer
var needToCheck = true;
 
// Additional variables
 
// tab
var tab = instance.ActiveTab;
// ReCaptcha image (w/out "I'm not robot" button) 
bool isNewView = true;
// congratulations, you are not robot
var success = false;
// timeout exceeded
var timeout = false;
// task for ReCaptcha 2
var task = string.Empty;
// image url
var src = string.Empty;
// image in base64 encoding
var imageString = string.Empty;
// answer to captcha
var answer = string.Empty;
// captcha has been updated
var changed = false;
// answer is empty
var answerIsEmpty = false;
var coincidenceReCaptcha2Index = -1;
 
 
// Checking protection bypass
Action CheckOK= () => {
	System.Threading.Thread.Sleep(waitTime); // waiting when elements will be loaded
	for (int k = 0; k < tryLoadElement; k++)
	{		
		var check = tab.FindElementByAttribute("div", "class", "recaptcha-checkbox-checkmark", "regexp", coincidenceReCaptcha2Index);
		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 System.Threading.Thread.Sleep(waitTime);
			}
			else break;
 
		}
		if (k == (tryLoadElement - 1)) timeout = true;
	}
};
 
Action UpdateImage= () => {
	// updating captcha if necessary
	if (!changed) 
	{
		HtmlElement reload = null;
		if (isNewView) reload = tab.FindElementById("recaptcha-reload-button");
		else reload = tab.GetDocumentByAddress("0;0").FindElementByTag("form", 1).FindChildByAttribute("input:submit", "class", "fbc-button-reload fbc-button", "regexp", 0);
 
		if (!reload.IsVoid) reload.Click();
		else timeout = true;
	}
	changed = false;
 
	for (int k = 0; k < tryLoadElement; k++)
	{
		System.Threading.Thread.Sleep(waitTime); // waiting when element will be loaded
		// searching image
		var testImage = tab.FindElementByAttribute("img", "class", "rc-image-tile", "regexp", 0);
		if (testImage.IsVoid) continue;
		// getting image url
		var newSrc = testImage.GetAttribute("src");
		// if image has been updated, then exit
		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)
			{
				coincidenceReCaptcha2Index = i;
				break;
			}
		}
	}
};
 
Action SearchReCaptcha2= () => {
	project.SendInfoToLog("Searching ReCaptcha 2", needShowMessages);
	for (int k = 0; k < tryLoadElement; k++)
	{
		VisibleIndexReCaptchaDefinition();
		if (coincidenceReCaptcha2Index < 0)
			continue;
 
		// searching "I'm not robot" button
		var notRobot = tab.FindElementByAttribute("div", "class", "recaptcha-checkbox-checkmark", "regexp", coincidenceReCaptcha2Index);
 
		// if found
		if (!notRobot.IsVoid)
		{
			// click button
			notRobot.Click();
			System.Threading.Thread.Sleep(waitTime); // pause
 
			// if entering captcha is not required
			var check = tab.FindElementByAttribute("div", "class", "recaptcha-checkbox-checkmark", "regexp", 0);
			if (!check.IsVoid)
			{
				if (check.OuterHtml.Contains("style=\"\""))
				{
					success = true;
					break;
				}
			}
 
			// waiting when the form will be loaded
			for (int j = 0; j < tryLoadElement; j++)
			{
				var loadedForm = tab.FindElementByAttribute("div", "class", "primary-controls", "regexp", 0);
				if (!loadedForm.IsVoid) break;
				else System.Threading.Thread.Sleep(waitTime); // waiting when element will be loaded
				if (j == (tryLoadElement - 1)) timeout = true;
			}
			break;
		}
		else 
		{
			// checking if this is mobile ReCaptcha
			var form = tab.FindElementByAttribute("form", "fulltag", "form", "text", 0);
			if (!form.IsVoid)
			{
				isNewView = false;
				fullAnswer = false;
				break;
			}
			else System.Threading.Thread.Sleep(waitTime); // waiting when element will be loaded
		}
		if (k == (tryLoadElement - 1)) timeout = true;
	}
};
 
Action SearchTask= () => {
	project.SendInfoToLog("Searching task", needShowMessages);
	for (int k = 0; k < tryLoadElement; k++)
	{
		HtmlElement taskHe = null;
		if (isNewView) taskHe = tab.FindElementByAttribute("div", "class", "rc-imageselect-desc-wrapper", "regexp", 0);
		else taskHe = tab.FindElementByAttribute("label", "class", "fbc-imageselect-message-text", "regexp", 0);
 
		if (!isNewView && taskHe.IsVoid) taskHe = tab.FindElementByAttribute("div", "class", "fbc-imageselect-message-error", "regexp", 0);
 
		if (!taskHe.IsVoid)
		{
			task = taskHe.GetAttribute("innertext"); // getting task
			if (task.ToLower().Contains("click verify once there are none left"))
				throw new Exception("Not recognized");
 
			if (task.ToLower().Contains("street signs")) 
			{
				UpdateImage();
				continue;
			}
			break;	
		}
		else System.Threading.Thread.Sleep(waitTime); // waiting when element will be loaded
 
		if (k == (tryLoadElement - 1)) timeout = true;
	}
};
 
Action SearchImage= () => {
	project.SendInfoToLog("Searching image", needShowMessages);
	System.Threading.Thread.Sleep(waitTime * 3); // waiting when element will be loaded
	for (int k = 0; k < tryLoadElement; k++)
	{
		HtmlElement image = null;
		if (isNewView) image = tab.FindElementByAttribute("img", "class", "rc-image-tile", "regexp", 0);
		else  image = tab.FindElementByAttribute("img", "class", "fbc-imageselect-payload", "regexp", 0);
 
		// if found
		if (!image.IsVoid)
		{
			// getting image url
			src = image.GetAttribute("src");
			imageString = image.DrawToBitmap(true);
			break;
		}
		else System.Threading.Thread.Sleep(waitTime); // waiting when element will be loaded
 
		if (k == (tryLoadElement - 1)) timeout = true;
	}
};
 
Action Recognize= () => {
	project.SendInfoToLog("Recognizing", needShowMessages);
	if (!isNewView) fullAnswer = false;
	var answerString = ZennoPoster.CaptchaRecognition("CapMonster2.dll", imageString, String.Format("Task={0}&FullAnswer={1}", task, fullAnswer));
	var split = answerString.Split(new [] { "-|-" }, StringSplitOptions.RemoveEmptyEntries);
	answer = split[0];
};
 
Action InputAnswer= () => {
	if (!String.IsNullOrEmpty(answer) && answer != "sorry")
	{
		project.SendInfoToLog("Entering and verifying answer", needShowMessages);
		int count = 0;
		foreach (char c in answer)
		{
			if (fullAnswer)
			{
				if (count == 2) break;
			}
			int index;
 
			HtmlElement he = null;	
			if (isNewView)
			{
				index = Convert.ToInt32(c.ToString()) - 1;
				he = tab.FindElementByAttribute("img", "class", "rc-image-tile", "regexp", index);
			}
			else
			{
				string attrValue = "fbc-imageselect-checkbox-" + c;
				he = tab.FindElementByAttribute("input:checkbox", "class", attrValue, "regexp", 0);
			}
 
			if (!he.IsVoid) 
			{
				he.Click(); //click picture
				System.Threading.Thread.Sleep(waitTime);// pause
			}
			if (fullAnswer) count++;
		}
 
		// searching "Verify" button
		HtmlElement apply = null;
		if (isNewView) apply = tab.FindElementById("recaptcha-verify-button");
		else apply = tab.GetDocumentByAddress("0;0").FindElementByTag("form", 0).FindChildByAttribute("input:submit", "fulltag", "input:submit", "text", 0);
 
		if (!apply.IsVoid) apply.Click();
 
		// checking if answer is correct
		if (isNewView)
		{
			CheckOK();
			if (success) return;
 
			// entering remained part of answer
			if (fullAnswer)
			{
				for (int i = count; i < answer.Length; i++)
				{
					// searching image again
					var testImage = tab.FindElementByAttribute("img", "class", "rc-image-tile", "regexp", 0);
					if (testImage.IsVoid) break;
					// getting image url
					var newSrc = testImage.GetAttribute("src");
					// if image has been changed, then exit
					if (newSrc != src) break;
					else changed = true;
					// else continue entering
					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(waitTime); // pause
						if (!apply.IsVoid) apply.Click();
						CheckOK();
						if (success) return;
					}
				}
			}
		}
	}
	else answerIsEmpty = true;
};
 
// Additonal actions for old type ReCaptcha 
Action ActsOldView= () => {
	System.Threading.Thread.Sleep(waitTime * 3); // waiting when element will be loaded
	// checking if there is a mistake in recognition
	HtmlElement he = tab.FindElementByAttribute("img", "class", "fbc-imageselect-payload", "regexp", 0);
	if (!he.IsVoid) 
	{
		return;
	}
 
	string txt = string.Empty;
	// searching text to insert
	for (int k = 0; k < tryLoadElement; k++)
	{
		HtmlElement heGetText = tab.FindElementByAttribute("textarea", "dir", "ltr", "regexp", 0);
		if (!heGetText.IsVoid)
		{
			txt = heGetText.GetAttribute("value");
			break;	
		}
		else 
		{
			System.Threading.Thread.Sleep(waitTime); // pause
			continue;
		}
		if (k == (tryLoadElement - 1)) timeout = true;
	}
 
	// searching field to insert text
	for (int k = 0; k < tryLoadElement; k++)
	{
		HtmlElement hePutText = tab.FindElementByAttribute("textarea", "id", "g-recaptcha-response", "regexp", 0);
		if (!hePutText.IsVoid)
		{
			hePutText.SetValue(txt, "None", false);
			break;	
		}
		else 
		{
			System.Threading.Thread.Sleep(waitTime); // pause
			continue;
		}
		if (k == (tryLoadElement - 1)) timeout = true;
	}
 
	// pressing "Verify"
	for (int k = 0; k < tryLoadElement; k++)
	{
		var submit = tab.FindElementByAttribute("input:submit", "fulltag", "input:submit", "regexp", 0);
		if (!submit.IsVoid)
		{
			submit.Click();
			break;
		}
		else 
		{
			System.Threading.Thread.Sleep(waitTime); // pause
			continue;
		}
		if (k == (tryLoadElement - 1)) timeout = true;
	}
	success = true;
};
 
SearchReCaptcha2();
if (timeout) throw new Exception("Element loading timeout has been exceeded");
 
for (int i = 0; i < tryRecognize; i++)
{
	SearchTask();
	if (timeout) break;
	SearchImage();
	if (timeout) break;
	Recognize();
	InputAnswer();
 
	if (!needToCheck) return "ok";
 
	if (answerIsEmpty)
	{
		answerIsEmpty = false;
		UpdateImage();
		continue;
	}
 
	if (!isNewView) ActsOldView();
	if (timeout) break;
 
	if (success) return "ok";
 
	if (i != (tryRecognize - 1)) UpdateImage();
	if (timeout) break;
}
 
if (timeout) throw new Exception("Element loading timeout has been exceeded");
else throw new Exception("Not recognized");

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: 2016/12/09 10:30 by afameless