ReCaptcha2
Please read the Terms of Use for Materials on ZennoLab
Table of contents
Description
Added in version 2.4.0.0.
ReCaptcha2 is a bot protection released by Google. A button "I'm not a robot" appears on the web page, when you click on it, several pictures appear, among which you need to select all the images indicated in the title.
It looks like this:
You can see an example of ReCaptcha2 on the Demo page from Google.
How it works
To send ReCaptcha2 for recognition to CapMonster2, you need to create a request that will include an image from several answer options and a task as an additional parameter. Parameter name: "Task". The meaning is a question of ReCaptcha2 itself, for example "Cars".
CapMonster2 sends a response in the form of a string consisting of numbers - numbers of pictures without separators that you need to click on. The numbers are indicated in descending order of probability that the picture shows the specified item.
For example, we need to select pictures with cars. CapMonster2 sent a reply 456. So you need to click on the 4th, 5th and 6th picture, and then click the "Confirm" button. That is, picture 4 most likely contains a car, then 5 and 6.
If CapMonster2 was unable to recognize a car in more than one picture (2 pictures is the minimum possible number of correct answers), then it sends an empty answer so that you can send this ReCaptcha2 to the manual recognition service.
Usage in ZennoPoster
To send ReCaptcha2 from ZennoPoster, you can use the special Recognize ReCaptcha2 action:
In the action, you can change the recognition parameters that are used in the snippet below.
Also ReCaptcha2 can be recognized through SiteKey specifying SiteKey and page URL.
To send ReCaptcha2 from ZennoPoster version higher than 5.9.0.0, you can use the snippet we have prepared:
// Main settings
// wait time
var waitTime = 1500;
// number of attempts to recognize
var tryRecognize = 10;
// number of attempts to select changing pictures
var dynamicImagesRecognizeAttempts = 20;
// number of attempts to load an element
var tryLoadElement = 60;
// get full response
bool fullAnswer = false;
// show messages about the progress of recognition
var needShowMessages = false;
// check the correctness of the recognized response
var needToCheck = true;
// Auxiliary 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;
// image in base64
var imageString = string.Empty;
// answer to captcha
string answer = string.Empty;
// captcha has changed
var changed = false;
// empty answer
bool answerIsEmpty = false;
// variable captcha
bool dynamicCaptcha = false;
// enter captcha several times
bool notOneEnter = false;
var coincidenceReCaptcha2Index = -1;
// Checking the passage of protection
Action CheckOK = () =>
{
tab.WaitDownloading ();
for (int k = 0; k <tryLoadElement; k ++)
{
System.Threading.Thread.Sleep (waitTime); // wait for the elements to load
var check = tab.FindElementByAttribute ("div", "class", "recaptcha-checkbox-checkmark", "regexp", 0);
// check if the form disappears
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;
}
};
// Confirm response
Action VerifyAnswer = () =>
{
project.SendInfoToLog ("Validation after entering dynamic captcha", needShowMessages);
tab.WaitDownloading ();
// search for the "Confirm" button
HtmlElement apply = tab.FindElementById ("recaptcha-verify-button");
if (! apply.IsVoid) apply.Click ();
// check if the answer is correct
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 ("Captcha update", needShowMessages);
// Update captcha if necessary
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;
}
}
}
};
// Search for recaptcha 2
Action SearchReCaptcha2 = () =>
{
project.SendInfoToLog ("Search for recaptcha 2", needShowMessages);
tab.WaitDownloading ();
for (int k = 0; k <tryLoadElement; k ++)
{
VisibleIndexReCaptchaDefinition ();
if (coincidenceReCaptcha2Index <0) coincidenceReCaptcha2Index = 0;
// search for the "I'm not a robot" button
HtmlElement notRobot = tab.FindElementByAttribute ("div", "class", "recaptcha-checkbox-checkmark", "regexp", coincidenceReCaptcha2Index);
// button exists
if (! notRobot.IsVoid)
{
// click on the button
notRobot.Click ();
System.Threading.Thread.Sleep (waitTime); // pause
// if captcha input is not required
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;
// wait for the elements to load
System.Threading.Thread.Sleep (waitTime);
if (k == (tryLoadElement - 1)) timeout = true;
}
};
// Search for recaptcha job 2
Action SearchTask = () =>
{
tab.WaitDownloading ();
project.SendInfoToLog ("Job Search", 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"); // get 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 ("when the images run out") ||
suspecttask.Contains ("if the image is no longer overshadowed, press \" confirm \ "") ||
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 ("if not, click \" skip \ "") || suspecttask.Contains ("yakscho nichogo nema |") ||
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); // wait for the element to load
if (k == (tryLoadElement - 1)) timeout = true;
}
};
// Search for an image
Action SearchImage = () =>
{
tab.WaitDownloading ();
project.SendInfoToLog ("Image Search", 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 are images
if (! image.IsVoid)
{
// get the url of the image
if (! dynamicCaptcha) src = image.GetAttribute ("src");
imageString = image.DrawToBitmap (! dynamicCaptcha);
timeout = false;
break;
}
System.Threading.Thread.Sleep (waitTime); // wait for the elements to 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];
};
// Enter the answer
Action InputAnswer = () =>
{
if (! String.IsNullOrEmpty (answer) && answer! = "sorry")
{
project.SendInfoToLog ("Response input and validation", 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 on the picture
System.Threading.Thread.Sleep (500); // wait a bit
}
if (fullAnswer) count ++;
}
// looking for the "Confirm" button
HtmlElement apply = tab.FindElementById ("recaptcha-verify-button");
if (! apply.IsVoid) apply.Click ();
// check if the answer is correct
CheckOK ();
if (success) return;
// enter the rest of the answer
if (fullAnswer)
{
for (int i = count; i <answer.Length; i ++)
{
// look for a picture again
var testImage = tab.FindElementByAttribute ("img", "class", "rc-image-tile", "regexp", 0);
if (testImage.IsVoid) break;
// get the url of the image
var newSrc = testImage.GetAttribute ("src");
// if the image has changed, then exit
if (newSrc! = src) break;
else changed = true;
// otherwise continue typing
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); // wait a bit
if (! apply.IsVoid) apply.Click ();
CheckOK ();
if (success) return;
}
}
}
}
else answerIsEmpty = true;
};
// Enter the answer
Action InputDynamicAnswer = () =>
{
project.SendInfoToLog ("Entering dynamic captcha response", 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 on the picture
he.Click ();
// wait a bit
System.Threading.Thread.Sleep (500);
}
}
// wait a little more
System.Threading.Thread.Sleep (waitTime * 2);
};
// Enter the answer
Action InputDynamicAnswer2 = () =>
{
project.SendInfoToLog ("Entering dynamic captcha response", 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 on the picture
he.Click ();
// wait a bit
System.Threading.Thread.Sleep (500);
}
}
// wait a little more
System.Threading.Thread.Sleep (waitTime * 2);
};
SearchReCaptcha2 ();
if (success)
return "ok";
if (timeout) throw new Exception ("Element loading timeout");
for (int i = 0; i <tryRecognize; i ++)
{
project.SendInfoToLog (String.Format ("Attempt #: {0}", i + 1), needShowMessages);
InputNotBotText ();
SearchTask ();
if (timeout) break;
// additional verification
CheckOK ();
if (success) return "ok";
int count = 0;
// if captcha is mutable
if (dynamicCaptcha)
{
while (count <dynamicImagesRecognizeAttempts)
{
if (count> 0)
System.Threading.Thread.Sleep (waitTime * 3); // wait for the disappearing images to load
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 ("Element loading timeout");
else throw new Exception ("Not recognized. Out of attempts to recognize before the answer was valid");
Note
The snippet can perform any number of attempts to recognize ReCaptcha2. Also, if you use slow proxies, you can increase the waiting time for items to load, the number of load attempts and setting the need to check the correctness of the recognized answer. To do this, you can change the parameters:
// wait time
var waitTime = 3000;
// number of attempts to recognize
var tryRecognize = 10;
// number of attempts to select changing pictures
var dynamicImagesRecognizeAttempts = 20;
// number of attempts to load an element
var tryLoadElement = 60;
// get full answer
bool fullAnswer = false;
// get messages about the progress of recognition
var needShowMessages = false;
// check the correctness of the recognized response
var needToCheck = true;
Depending on the IP address from which you perform the above manipulations, ReCaptcha2 may "close its eyes" to the lack of a click on one of the pictures or to a click on the wrong picture. However, with constant errors, ReCaptcha2 may not accept even correct answers, so it is recommended to use good proxies.