Skip to content

Instantly share code, notes, and snippets.

@Panthere
Last active June 24, 2020 15:09
Show Gist options
  • Save Panthere/606dbf5566c4224310f29633a7d59dcc to your computer and use it in GitHub Desktop.
Save Panthere/606dbf5566c4224310f29633a7d59dcc to your computer and use it in GitHub Desktop.
2captcha C# Implementation
public class CaptchaResult
{
#region Fields
/// <summary>
/// Captcha ID as provided by 2captcha
/// </summary>
public string ID;
/// <summary>
/// Token required to submit to the site
/// </summary>
public string Response;
/// <summary>
/// Is true if the captcha has been solved successfully. If false, Response is null
/// </summary>
public bool HasSolved;
private string _apiKey;
#endregion
#region Constructors
public CaptchaResult(string res, string id, string apiKey, bool hasSolved = false)
{
Response = res;
ID = id;
HasSolved = hasSolved;
_apiKey = apiKey;
}
#endregion
#region Public Members
/// <summary>
/// Report the captcha as being invalid to 2captcha
/// </summary>
/// <returns>Captcha report submitted successfully</returns>
public bool ReportInvalid()
{
try
{
using (WebClient wc = new WebClient())
{
return wc.DownloadString(string.Format("{0}?key={1}&action=reportbad&id={2}", TwoCaptcha.RES_URL, _apiKey, ID)) == "OK_REPORT_RECORDED";
}
}
catch (Exception ex)
{
#if DEBUG
Debug.WriteLine("ReportInvalid: {0}", ex);
#endif
return false;
}
}
#endregion
}
public class TwoCaptcha
{
#region Consts
public const string IN_URL = "http://2captcha.com/in.php";
public const string RES_URL = "http://2captcha.com/res.php";
#endregion
#region Public Fields
/// <summary>
/// Site key from recaptcha for the site
/// </summary>
public string SiteKey;
/// <summary>
/// 2captcha API key
/// </summary>
public string APIKey;
/// <summary>
/// Site URL or domain to send to 2captcha
/// </summary>
public string SiteURL;
/// <summary>
/// Max amount of poll tries before it is marked as not solved
/// </summary>
public int MaxPollTries = 15;
/// <summary>
/// Max submit tries before it returns null
/// </summary>
public int MaxSubmitTries = 15;
#endregion
#region Properties
/// <summary>
/// The proxy sent to 2captcha when requesting a captcha to be solved
/// </summary>
public WebProxy AccessProxy
{
get;
set;
}
#endregion
#region Constructors
/// <summary>
/// Creates a new instance of the 2captcha api without setting a proxy
/// </summary>
/// <param name="siteKey">ReCaptcha Site Key</param>
/// <param name="siteUrl">Url from the site for the site key</param>
public TwoCaptcha(string apiKey, string siteKey, string siteUrl)
: this(apiKey, siteKey, siteUrl, null)
{
}
/// <summary>
/// Creates a new instance of the 2captcha api
/// </summary>
/// <param name="apiKey">2captcha API Key</param>
/// <param name="siteKey">ReCaptcha Site Key</param>
/// <param name="siteUrl">Url from the site for the site key</param>
/// <param name="accessProxy">Proxy to send to 2captcha for external use</param>
public TwoCaptcha(string apiKey, string siteKey, string siteUrl, WebProxy accessProxy)
{
SiteKey = siteKey;
SiteURL = siteUrl;
APIKey = apiKey;
AccessProxy = accessProxy;
}
#endregion
#region Public Members
/// <summary>
/// Solve a new Google NoCaptcha for the provided site using the provided proxy.
/// </summary>
/// <returns>CaptchaResult containing the token required</returns>
public CaptchaResult SolveCaptcha()
{
CaptchaResult captchaId = GetCaptchaID();
if (captchaId == null)
return null;
// Kill me, yeah, I know, wow, thread.sleep in 2016
Thread.Sleep(5000);
return PollCaptchaID(captchaId);
}
#endregion
#region Private Members
private CaptchaResult PollCaptchaID(CaptchaResult captchaId)
{
int attemptsMax = MaxPollTries;
while ((attemptsMax--) > 0)
{
try
{
using (WebClient wc = new WebClient())
{
string resp = wc.DownloadString(string.Format("{0}?key={1}&action=get&id={2}", RES_URL, APIKey, captchaId.ID));
if (resp.Contains("OK|"))
{
captchaId.HasSolved = true;
captchaId.Response = resp.Split('|')[1];
return captchaId;
}
// apparently will only be sent after 90 seconds is up
else if (resp == "ERROR_CAPTCHA_UNSOLVABLE")
{
return captchaId;
}
}
}
catch (Exception ex)
{
#if DEBUG
Debug.WriteLine("PollCaptchaID {0}: {1}", attemptsMax, ex);
#endif
}
// Change to what you like, 2captcha are pretty slow, so expect some heavy waiting
Thread.Sleep(5000);
}
return captchaId;
}
private CaptchaResult GetCaptchaID()
{
NameValueCollection nvc = new NameValueCollection();
string formattedProxy = string.Format("{0}:{1}", AccessProxy.Address.DnsSafeHost, AccessProxy.Address.Port);
nvc.Add("key", APIKey);
nvc.Add("method", "userrecaptcha");
nvc.Add("googlekey", SiteKey);
nvc.Add("proxy", formattedProxy);
nvc.Add("proxytype", "http");
nvc.Add("pageurl", SiteURL);
int attemptsMax = MaxSubmitTries;
// Guess what, you're mad and I'm not
// People prefer a while loop over goto's these days, idk why
// They're all the same in the end
while ((attemptsMax--) > 0)
{
try
{
using (WebClient wc = new WebClient())
{
string resp = Encoding.UTF8.GetString(wc.UploadValues(string.Format("{0}", IN_URL), nvc));
if (resp.StartsWith("OK|"))
{
return new CaptchaResult(null, resp.Split('|')[1], APIKey);
}
else
{
return null;
}
}
}
catch (Exception ex)
{
#if DEBUG
Debug.WriteLine("GetCaptchaID: {0}", ex);
#endif
}
Thread.Sleep(1500);
}
return null;
}
#endregion
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment