#!/usr/bin/env python3 import os import sys import time from base64 import b64encode import requests try: from .api import ApiClient from .exceptions.solver import ValidationException, NetworkException, TimeoutException, ApiException, \ SolverExceptions except ImportError: from api import ApiClient from twocaptcha.exceptions.solver import ValidationException, NetworkException, TimeoutException, ApiException, \ SolverExceptions class TwoCaptcha(): """ Class for interacting with the 2captcha API. This class provides methods for solving various types of CAPTCHAs, such as image CAPTCHAs, audio CAPTCHAs, reCAPTCHAs, hCAPTCHAs, and others. It handles sending CAPTCHAs to the 2captcha service and retrieving the solution. Parameters __________ API_KEY : str Your personal API key for accessing the 2captcha API. soft_id : int, optional Software ID obtained after publishing in the 2captcha software catalog. Default is 4580. callback : str, optional URL of your server to receive the result of the captcha recognition via callback. It must be registered in your 2captcha account settings. Default is None. default_timeout : int, optional The timeout (in seconds) for polling responses for normal CAPTCHAs, excluding reCAPTCHA. Default is 120. recaptcha_timeout : int, optional The timeout (in seconds) for polling responses specifically for reCAPTCHAs. Default is 600. polling_interval : int, optional The interval (in seconds) between requests to the 2captcha API for retrieving the captcha solution. Default is 10. api_client : ApiClient An instance of the ApiClient class to handle API requests. max_files : int Maximum number of files that can be sent to the API in one request. Default is 9. exceptions : SolverExceptions Custom exceptions for handling API errors. extendedResponse : bool, optional If True, enables extended responses from the 2captcha API, which provides more detailed result data. Default is None. Methods _______ normal(file, **kwargs) To bypass a normal captcha (distorted text on an image) use the following method. This method can also be used to recognize any text in an image. audio(file, lang, **kwargs) Use the following method to bypass an audio captcha (mp3 formats only). text(text, **kwargs) This method can be used to bypass a captcha that requires answering a question provided in clear text. recaptcha(sitekey, url, version='v2', enterprise=0, **kwargs) Use the following method to solve reCAPTCHA V2 or V3 and obtain a token to bypass the protection. funcaptcha(sitekey, url, **kwargs) FunCaptcha (Arkoselabs) solving method. Returns a token. geetest(gt, challenge, url, **kwargs) Method to solve GeeTest puzzle captcha. Returns a set of tokens as JSON. hcaptcha(sitekey, url, **kwargs) Use this method to solve the hCaptcha challenge. Returns a token to bypass the captcha. keycaptcha(s_s_c_user_id, s_s_c_session_id, s_s_c_web_server_sign, s_s_c_web_server_sign2, url, **kwargs) Token-based method to solve KeyCaptcha. capy(sitekey, url, **kwargs) Token-based method to bypass Capy puzzle captcha. grid(file, **kwargs) The grid method was originally called the Old reCAPTCHA V2 method. The method can be used to bypass any type of captcha where you can apply a grid on an image and click specific grid boxes. Returns numbers of boxes. canvas(file, **kwargs) The canvas method can be used when you need to draw a line around an object on an image. Returns a set of points' coordinates to draw a polygon. coordinates(file, **kwargs) The ClickCaptcha method returns the coordinates of points on the captcha image. It can be used if you need to click on particular points in the image. rotate(files, **kwargs) This method can be used to solve a captcha that asks to rotate an object. It is mostly used to bypass FunCaptcha. Returns the rotation angle. geetest_v4(captcha_id, url, **kwargs) Use this method to solve GeeTest v4. Returns the response in JSON. lemin(captcha_id, div_id, url, **kwargs) Use this method to solve the Lemin captcha. Returns JSON with an answer containing the following values: answer, challenge_id. atb_captcha(app_id, api_server, url, **kwargs) Use this method to solve atbCaptcha challenge. Returns a token to bypass the captcha. turnstile(sitekey, url, **kwargs) Use this method to solve Cloudflare Turnstile. Returns JSON with the token. amazon_waf(sitekey, iv, context, url, **kwargs) Use this method to solve Amazon WAF Captcha also known as AWS WAF Captcha is a part of Intelligent threat mitigation for Amazon AWS. Returns JSON with the token. mtcaptcha(sitekey, url, **kwargs) Use this method to solve MTCaptcha and obtain a token to bypass the protection. friendly_captcha(sitekey, url, **kwargs) Friendly Captcha solving method. Returns a token. tencent(app_id, url, **kwargs) Use this method to solve Cutcaptcha. Returns a token. cutcaptcha(misery_key, apikey, url, **kwargs) Use this method to solve Cutcaptcha. Returns the response in JSON. datadome(captcha_url, pageurl, userAgent, proxy, **kwargs) Use this method to solve DataDome captcha. cybersiara(master_url_id, pageurl, userAgent, **kwargs) Use this method to solve CyberSiARA. Returns a token. yandex_smart(self, sitekey, url, **kwargs) Wrapper for solving Yandex Smart. altcha(self, pageurl, challenge_url=None, challenge_json=None, **kwargs) Wrapper for solving Altcha Captcha. binance(self, pageurl, sitekey, validate_id, **kwargs) Wrapper for solving Binance captcha. yidun(self, sitekey, pageurl, **kwargs) Wrapper for solving Yidun captcha. hunt(self, pageurl, api_get_lib, **kwargs) Wrapper for solving Hunt captcha. alibaba(self, pageurl, scene_id, prefix, **kwargs) Wrapper for solving Alibaba captcha. tspd(self, pageurl, tspd_cookie, html_page_base64, proxy, **kwargs) Wrapper for solving TSPD captcha. basilisk(self, pageurl, sitekey, **kwargs) Wrapper for solving Basilisk captcha. solve(timeout=0, polling_interval=0, **kwargs) Sends CAPTCHA data and retrieves the result. balance() Retrieves the balance of your 2captcha account. report(id_, correct) Reports the correctness of a solved CAPTCHA. """ def __init__(self, apiKey, softId=4580, callback=None, defaultTimeout=120, recaptchaTimeout=600, pollingInterval=10, server='2captcha.com', extendedResponse=None): """ Class constructor for interacting with the 2captcha API. Parameters __________ apiKey : str Your personal API key in your account settings. softId : int, optional Your software ID obtained after publishing in 2captcha software catalog - https://2captcha.com/software. Default: 4580. callback : str, optional URL of your web server that receives the captcha recognition result. The URL should be first registered in pingback - https://2captcha.com/setting/pingback - settings of your account. Default: None. defaultTimeout : int, optional Polling timeout in seconds for all captcha types except reCAPTCHA. Defines how long the module tries to get the answer from the res.php API endpoint. Default: 120. recaptchaTimeout : int, optional Polling timeout for reCAPTCHA in seconds. Defines how long the module tries to get the answer from the res.php API endpoint. Default: 600. pollingInterval : int, optional Interval in seconds between requests to the res.php API endpoint. Setting values less than 5 seconds is not recommended. Default: 10. server : str, optional API server. You can set it to rucaptcha.com if your account is registered there. Default: 2captcha.com. extendedResponse : bool, optional Set to True to get the response with additional fields or in more practical format (enables JSON response from res.php API endpoint). Suitable for hCaptcha, ClickCaptcha, Canvas. Default: None. """ self.API_KEY = apiKey self.soft_id = softId self.callback = callback self.default_timeout = defaultTimeout self.recaptcha_timeout = recaptchaTimeout self.polling_interval = pollingInterval self.api_client = ApiClient(post_url=str(server)) self.max_files = 9 self.exceptions = SolverExceptions self.extendedResponse = extendedResponse def normal(self, file, **kwargs): '''Wrapper for solving a normal captcha (image). Parameters __________ file : file Captcha image file. * required if you submit image as a file (method=post). body : str Base64-encoded captcha image. * required if you submit image as Base64-encoded string (method=base64). phrase : int, optional 0 - captcha contains one word. 1 - captcha contains two or more words. Default: 0. numeric : int, optional 0 - not specified. 1 - captcha contains only numbers. 2 - captcha contains only letters. 3 - captcha contains only numbers OR only letters. 4 - captcha MUST contain both numbers AND letters. Default: 0 minLen : int, optional 0 - not specified. 1..20 - minimal number of symbols in captcha. Default: 0. maxLen : int, optional 0 - not specified. 1..20 - maximal number of symbols in captcha. Default: 0. caseSensitive : int, optional 0 - captcha in not case sensitive. 1 - captcha is case sensitive. Default: 0. calc : int, optional 0 - not specified. 1 - captcha requires calculation (e.g. type the result 4 + 8 = ). Default: 0. lang : str, optional Language code. See the list of supported languages https://2captcha.com/2captcha-api#language. hintText : str, optional Max 140 characters. Encoding: UTF-8. Text will be shown to worker to help him to solve the captcha correctly. For example: type red symbols only. hintImg : img, optional Max 400x150px, 100 kB. Image with instruction for solving reCAPTCHA. Not required if you're sending instruction as text with textinstructions. softId : int, optional ID of software developer. Developers who integrated their software with 2Captcha get reward: 10% of spendings of their software users. callback : str, optional URL for pingback (callback) response that will be sent when captcha is solved. URL should be registered on the server. More info here https://2captcha.com/2captcha-api#pingback. ''' method = self.get_method(file) result = self.solve(**method, **kwargs) return result def audio(self, file, lang, **kwargs): '''Wrapper for solving audio captcha. Parameters __________ body : str Base64 encoded audio file in mp3 format. Max file size: 1 MB. lang : str The language of audio record. Supported languages are: "en", "ru", "de", "el", "pt", "fr". ''' method = "audio" if not file: raise ValidationException('File is none') elif not '.' in file and len(file) > 50: body = file elif file.endswith(".mp3") and file.startswith("http"): response = requests.get(file) if response.status_code != 200: raise ValidationException(f'File could not be downloaded from url: {file}') body = b64encode(response.content).decode('utf-8') elif file.endswith(".mp3"): with open(file, "rb") as media: body = b64encode(media.read()).decode('utf-8') else: raise ValidationException('File extension is not .mp3 or it is not a base64 string.') if not lang or lang not in ("en", "ru", "de", "el", "pt", "fr"): raise ValidationException(f'Lang not in "en", "ru", "de", "el", "pt", "fr". You send {lang}') result = self.solve(body=body, method=method, lang=lang, **kwargs) return result def text(self, text, **kwargs): '''Wrapper for solving text captcha. Parameters __________ text : str Max 140 characters. Encoding: UTF-8. Text will be shown to worker to help him to solve the captcha correctly. For example: type red symbols only. lang: str, optional Language code. See the list of supported languages https://2captcha.com/2captcha-api#language. softId : int, optional ID of software developer. Developers who integrated their software with 2Captcha get reward: 10% of spendings of their software users. callback : str, optional URL for pingback (callback) response that will be sent when captcha is solved. URL should be registered on the server. More info here https://2captcha.com/2captcha-api#pingback. ''' result = self.solve(text=text, method='post', **kwargs) return result def recaptcha(self, sitekey, url, version='v2', enterprise=0, **kwargs): '''Wrapper for solving recaptcha (v2, v3). Parameters __________ sitekey : str Value of sitekey parameter you found on page. url : str Full URL of the page where you see the reCAPTCHA. domain : str, optional Domain used to load the captcha: google.com or recaptcha.net. Default: google.com. invisible : int, optional 1 - means that reCAPTCHA is invisible. 0 - normal reCAPTCHA. Default: 0. version : str, optional v3 — defines that you're sending a reCAPTCHA V3. Default: v2. enterprise : str, optional 1 - defines that you're sending reCAPTCHA Enterpise. Default: 0. action : str, optional Value of action parameter you found on page. Default: verify. score : str, only for v3, optional The score needed for resolution. Currently, it's almost impossible to get token with score higher than 0.3. Default: 0.4. data-s : str, only for v2, optional Value of data-s parameter you found on page. Curenttly applicable for Google Search and other Google services. cookies : str, only for v2, optional Your cookies that will be passed to our worker who solve the captha. We also return worker's cookies in the response if you use json=1. Format: KEY:Value, separator: semicolon, example: KEY1:Value1;KEY2:Value2; userAgent : str, only for v2, optional Your userAgent that will be passed to our worker and used to solve the captcha. softId : int, optional ID of software developer. Developers who integrated their software with 2Captcha get reward: 10% of spendings of their software users. callback : str, optional URL for pingback (callback) response that will be sent when captcha is solved. URL should be registered on the server. More info here https://2captcha.com/2captcha-api#pingback. proxy : dict, optional {'type': 'HTTPS', 'uri': 'login:password@IP_address:PORT'}. ''' params = { 'googlekey': sitekey, 'url': url, 'method': 'userrecaptcha', 'version': version, 'enterprise': enterprise, **kwargs, } result = self.solve(timeout=self.recaptcha_timeout, **params) return result def funcaptcha(self, sitekey, url, **kwargs): '''Wrapper for solving funcaptcha. Parameters __________ sitekey : str Value of pk or data-pkey parameter you found on page. url : str Full URL of the page where you see the FunCaptcha. surl : str, optional Value of surl parameter you found on page. userAgent: str, optional Tells us to use your user-agent value. data[key] : str, optional Custom data to pass to FunCaptcha. For example: data[blob]=stringValue. softId : int, optional ID of software developer. Developers who integrated their software with 2Captcha get reward: 10% of spendings of their software users. callback : str, optional URL for pingback (callback) response that will be sent when captcha is solved. URL should be registered on the server. More info here https://2captcha.com/2captcha-api#pingback. proxy : dict, optional {'type': 'HTTPS', 'uri': 'login:password@IP_address:PORT'}. ''' result = self.solve(publickey=sitekey, url=url, method='funcaptcha', **kwargs) return result def geetest(self, gt, challenge, url, **kwargs): '''Wrapper for solving geetest captcha. Parameters __________ gt : str Value of gt parameter you found on target website. challenge : str Value of challenge parameter you found on target website. url : str Full URL of the page where you see Geetest captcha. offline : num, optional In rare cases initGeetest can be called with offline parameter. If the call uses offline: true, set the value to 1. Default: 0. new_captcha : num, optional In rare cases initGeetest can be called with new_captcha parameter. If the call uses new_captcha: true, set the value to 1. Mostly used with offline parameter. userAgent : str, optional Your userAgent that will be passed to our worker and used to solve the captcha. apiServer : str, optional Value of api_server parameter you found on target website. softId : int, optional ID of software developer. Developers who integrated their software with 2Captcha get reward: 10% of spendings of their software users. callback : str, optional URL for pingback (callback) response that will be sent when captcha is solved. URL should be registered on the server. More info here https://2captcha.com/2captcha-api#pingback. proxy : dict, optional {'type': 'HTTPS', 'uri': 'login:password@IP_address:PORT'}. ''' result = self.solve(gt=gt, challenge=challenge, url=url, method='geetest', **kwargs) return result def hcaptcha(self, sitekey, url, **kwargs): '''Wrapper for solving hcaptcha. Parameters __________ sitekey : str Value of data-sitekey parameter you found on page. url : str Full URL of the page where you bypass the captcha. invisible : num, optional Use 1 for invisible version of hcaptcha. Currently it is a very rare case. Default: 0. data : str, optional Custom data that is used in some implementations of hCaptcha, mostly with invisible=1. In most cases you see it as rqdata inside network requests. Format: "data": "rqDataValue". domain : str, optional Domain used to load the captcha: hcaptcha.com or js.hcaptcha.com. Default: hcaptcha.com. softId : int, optional ID of software developer. Developers who integrated their software with 2Captcha get reward: 10% of spendings of their software users. callback : str, optional URL for pingback (callback) response that will be sent when captcha is solved. URL should be registered on the server. More info here https://2captcha.com/2captcha-api#pingback. proxy : dict, optional {'type': 'HTTPS', 'uri': 'login:password@IP_address:PORT'}. ''' result = self.solve(sitekey=sitekey, url=url, method='hcaptcha', **kwargs) return result def keycaptcha(self, s_s_c_user_id, s_s_c_session_id, s_s_c_web_server_sign, s_s_c_web_server_sign2, url, **kwargs): '''Wrapper for solving. Parameters __________ s_s_c_user_id : str Value of s_s_c_user_id parameter you found on page. s_s_c_session_id : str Value of s_s_c_session_id parameter you found on page. s_s_c_web_server_sign : str Value of s_s_c_web_server_sign parameter you found on page. s_s_c_web_server_sign2 : str Value of s_s_c_web_server_sign2 parameter you found on page. url : str Full URL of the page where you see the KeyCaptcha. softId : int, optional ID of software developer. Developers who integrated their software with 2Captcha get reward: 10% of spendings of their software users. callback : str, optional URL for pingback (callback) response that will be sent when captcha is solved. URL should be registered on the server. More info here https://2captcha.com/2captcha-api#pingback. proxy : dict, optional {'type': 'HTTPS', 'uri': 'login:password@IP_address:PORT'}. ''' params = { 's_s_c_user_id': s_s_c_user_id, 's_s_c_session_id': s_s_c_session_id, 's_s_c_web_server_sign': s_s_c_web_server_sign, 's_s_c_web_server_sign2': s_s_c_web_server_sign2, 'url': url, 'method': 'keycaptcha', **kwargs, } result = self.solve(**params) return result def capy(self, sitekey, url, **kwargs): '''Wrapper for solving capy. Parameters __________ sitekey : str The domain part of script URL you found on page. Default value: https://jp.api.capy.me/. url : str Full URL of the page where you see the captcha. api_server : str, optional The domain part of script URL you found on page. Default value: https://jp.api.capy.me/. version : str, optional The version of captcha task: "puzzle" (assemble a puzzle) or "avatar" (drag an object). Default: puzzle. softId : int, optional ID of software developer. Developers who integrated their software with 2Captcha get reward: 10% of spendings of their software users. callback : str, optional URL for pingback (callback) response that will be sent when captcha is solved. URL should be registered on the server. More info here https://2captcha.com/2captcha-api#pingback. proxy : dict, optional {'type': 'HTTPS', 'uri': 'login:password@IP_address:PORT'}. ''' result = self.solve(captchakey=sitekey, url=url, method='capy', **kwargs) return result def grid(self, file, **kwargs): '''Wrapper for solving grid captcha (image). Parameters __________ file : file Captcha image file. * required if you submit image as a file (method=post). body : str Base64-encoded captcha image. * required if you submit image as Base64-encoded string (method=base64). hintText : str Max 140 characters. Encoding: UTF-8. Text with instruction for solving reCAPTCHA. For example: select images with trees. Not required if you're sending instruction as an image with imginstructions. hintImg : img Max 400x150px, 100 kB. Image with instruction for solving reCAPTCHA. Not required if you're sending instruction as text with textinstructions. rows : int, optional Number of rows in reCAPTCHA grid. cols : itn, optional Number of columns in reCAPTCHA grid. img_type : str, optional The type of captcha to solve. Supported values: - funcaptcha: FunCaptcha where you need to click the correct square. - funcaptcha_compare: FunCaptcha where you select the square using arrows. - recaptcha: reCAPTCHA. - hcaptcha: hCaptcha. Important: You must also provide the textinstructions parameter with the original instructions in English, and send the original image files, not screenshots. previousId : str, optional Id of your previous request with the same captcha challenge. canSkip : int, optional 0 - not specified. 1 - possibly there's no images that fit the instruction. Set the value to 1 only if it's possible that there's no images matching to the instruction. We'll provide a button "No matching images" to worker, and you will receive No_matching_images as answer. Default: 0. lang: str, optional Language code. See the list of supported languages https://2captcha.com/2captcha-api#language. softId : int, optional ID of software developer. Developers who integrated their software with 2Captcha get reward: 10% of spendings of their software users. callback : str, optional URL for pingback (callback) response that will be sent when captcha is solved. URL should be registered on the server. More info here https://2captcha.com/2captcha-api#pingback. proxy : dict, optional {'type': 'HTTPS', 'uri': 'login:password@IP_address:PORT'}. ''' method = self.get_method(file) params = { 'recaptcha': 1, **method, **kwargs, } result = self.solve(**params) return result def canvas(self, file, **kwargs): '''Wrapper for solving canvas captcha (image). Parameters __________ file : file Captcha image file. * required if you submit image as a file (method=post). body : str Base64-encoded captcha image. * required if you submit image as Base64-encoded string (method=base64). hintText : str Max 140 characters. Encoding: UTF-8. Text with instruction for solving reCAPTCHA. For example: select images with trees. Not required if you're sending instruction as an image with imginstructions. hintImg : img Max 400x150px, 100 kB. Image with instruction for solving reCAPTCHA. Not required if you're sending instruction as text with textinstructions. canSkip : int, optional 0 - not specified. 1 - possibly there's no images that fit the instruction. Set the value to 1 only if it's possible that there's no images matching to the instruction. We'll provide a button "No matching images" to worker, and you will receive No_matching_images as answer. Default: 0. lang : int, optional 0 - not specified. 1 - Cyrillic captcha. 2 - Latin captcha. Default: 0. softId : int, optional ID of software developer. Developers who integrated their software with 2Captcha get reward: 10% of spendings of their software users. callback : str, optional URL for pingback (callback) response that will be sent when captcha is solved. URL should be registered on the server. More info here https://2captcha.com/2captcha-api#pingback. ''' if not ('hintText' in kwargs or 'hintImg' in kwargs): raise ValidationException( 'parameters required: hintText and/or hintImg') method = self.get_method(file) params = { 'recaptcha': 1, 'canvas': 1, **method, **kwargs, } result = self.solve(**params) return result def coordinates(self, file, **kwargs): '''Wrapper for solving coordinates captcha (image). Parameters __________ file : file Captcha image file. * required if you submit image as a file (method=post). body : str Base64-encoded captcha image. * required if you submit image as Base64-encoded string (method=base64). hintText : str Max 140 characters. Encoding: UTF-8. Text with instruction for solving the captcha. For example: click on images with ghosts. Not required if the image already contains the instruction. hintImg : img Max 400x150px, 100 kB. Image with instruction for solving reCAPTCHA. Not required if you're sending instruction as text with textinstructions. lang : str, optional Language code. See the list of supported languages https://2captcha.com/2captcha-api#language. min_clicks : int, optional The minimum number of clicks that need to be done. max_clicks : int, optional The maximum number of clicks that can be done. softId : int, optional ID of software developer. Developers who integrated their software with 2Captcha get reward: 10% of spendings of their software users. callback : str, optional URL for pingback (callback) response that will be sent when captcha is solved. URL should be registered on the server. More info here https://2captcha.com/2captcha-api#pingback. ''' method = self.get_method(file) params = { 'coordinatescaptcha': 1, **method, **kwargs, } result = self.solve(**params) return result def rotate(self, files, **kwargs): '''Wrapper for solving rotate captcha (image). Parameters __________ files : file or str Captcha image file (method=post), or a Base64-encoded captcha image string (method=base64) passed directly as this same argument. angle : int, optional Angle for one rotation step in degrees. If not defined we'll use the default value for FunCaptcha: 40 degrees. Default: 40. lang : str, optional Language code. See the list of supported languages https://2captcha.com/2captcha-api#language. hintImg : str, optional Image with instruction for worker to help him to solve captcha correctly. hintText : str, optional Text will be shown to worker to help him to to solve captcha correctly. softId : int, optional ID of software developer. Developers who integrated their software with 2Captcha get reward: 10% of spendings of their software users. callback : str, optional URL for pingback (callback) response that will be sent when captcha is solved. URL should be registered on the server. More info here https://2captcha.com/2captcha-api#pingback. proxy : dict, optional {'type': 'HTTPS', 'uri': 'login:password@IP_address:PORT'}. ''' if isinstance(files, str): payload = self.get_method(files) payload.pop('method', None) result = self.solve(method='rotatecaptcha', **payload, **kwargs) return result elif isinstance(files, dict): files = list(files.values()) files = self.extract_files(files) result = self.solve(files=files, method='rotatecaptcha', **kwargs) return result def geetest_v4(self, captcha_id, url, **kwargs): '''Wrapper for solving geetest_v4 captcha. Parameters __________ captcha_id : str Value of captcha_id parameter you found on target website. url: str Full URL of the page where you see Geetest captcha. risk_type: str, optional Value of risk_type parameter is contained in the captcha loading request. softId : int, optional ID of software developer. Developers who integrated their software with 2Captcha get reward: 10% of spendings of their software users. callback : str, optional URL for pingback (callback) response that will be sent when captcha is solved. URL should be registered on the server. More info here https://2captcha.com/2captcha-api#pingback. proxy : dict, optional {'type': 'HTTPS', 'uri': 'login:password@IP_address:PORT'}. ''' result = self.solve(captcha_id=captcha_id, url=url, method='geetest_v4', **kwargs) return result def lemin(self, captcha_id, div_id, url, **kwargs): '''Wrapper for solving Lemin Cropped Captcha. Parameters __________ captcha_id : str Value of captcha_id parameter you found on page. div_id : str The id of captcha parent div element. url : str Full URL of the page where you see the captcha. api_server : str, optional The domain part of script URL you found on page. Default value: https://api.leminnow.com/. softId : int, optional ID of software developer. Developers who integrated their software with 2Captcha get reward: 10% of spendings of their software users. callback : str, optional URL for pingback (callback) response that will be sent when captcha is solved. URL should be registered on the server. More info here https://2captcha.com/2captcha-api#pingback. proxy : dict, optional {'type': 'HTTPS', 'uri': 'login:password@IP_address:PORT'}. ''' result = self.solve(captcha_id=captcha_id, div_id=div_id, url=url, method='lemin', **kwargs) return result def atb_captcha(self, app_id, api_server, url, **kwargs): '''Wrapper for solving atbCAPTCHA. Parameters __________ app_id : str The value of appId parameter in the website source code. api_server : str The value of apiServer parameter in the website source code. url : str The full URL of target web page where the captcha is loaded. We do not open the page, not a problem if it is available only for authenticated users. proxy : dict, optional {'type': 'HTTPS', 'uri': 'login:password@IP_address:PORT'}. ''' result = self.solve(app_id=app_id, api_server=api_server, url=url, method='atb_captcha', **kwargs) return result def turnstile(self, sitekey, url, **kwargs): '''Wrapper for solving Cloudflare Turnstile. Parameters __________ sitekey : str Value of sitekey parameter you found on page. url : str Full URL of the page where you see the captcha. useragent : str User-Agent of your browser. Must match the User-Agent you use to access the site. Use only modern browsers released within the last 6 months. action : str. optional Value of optional action parameter you found on page, can be defined in data-action attribute or passed to turnstile.render call. data : str, optional The value of cData passed to turnstile.render call. Also can be defined in data-cdata attribute. pagedata : str, optional The value of the chlPageData parameter when calling turnstile.render. softId : int, optional ID of software developer. Developers who integrated their software with 2Captcha get reward: 10% of spendings of their software users. callback : str, optional URL for pingback (callback) response that will be sent when captcha is solved. URL should be registered on the server. More info here https://2captcha.com/2captcha-api#pingback. proxy : dict, optional {'type': 'HTTPS', 'uri': 'login:password@IP_address:PORT'}. ''' result = self.solve(sitekey=sitekey, url=url, method='turnstile', **kwargs) return result def amazon_waf(self, sitekey, iv, context, url, **kwargs): '''Wrapper for solving Amazon WAF. Parameters __________ sitekey : str Value of key parameter you found on the page. iv : str Value of iv parameter you found on the page. context : str Value of optional context parameter you found on page. url : str Full URL of the page where you see the captcha. challenge_script : str, optional The source URL of challenge.js script on the page. captcha_script : str, optional The source URL of captcha.js script on the page. softId : int, optional ID of software developer. Developers who integrated their software with 2Captcha get reward: 10% of spendings of their software users. callback : str, optional URL for pingback (callback) response that will be sent when captcha is solved. URL should be registered on the server. More info here https://2captcha.com/2captcha-api#pingback. proxy : dict, optional {'type': 'HTTPS', 'uri': 'login:password@IP_address:PORT'}. ''' result = self.solve(sitekey=sitekey, iv=iv, context=context, url=url, method='amazon_waf', **kwargs) return result def mtcaptcha(self, sitekey, url, **kwargs): '''Wrapper for solving MTCaptcha. Parameters __________ sitekey : str The value of sitekey parameter found on the page. url : str Full URL of the page where you solve the captcha. softId : int, optional ID of software developer. Developers who integrated their software with 2Captcha get reward: 10% of spendings of their software users. callback : str, optional URL for pingback (callback) response that will be sent when captcha is solved. URL should be registered on the server. More info here https://2captcha.com/2captcha-api#pingback. proxy : dict, optional {'type': 'HTTPS', 'uri': 'login:password@IP_address:PORT'}. ''' result = self.solve(sitekey=sitekey, url=url, method='mt_captcha', **kwargs) return result def friendly_captcha(self, sitekey, url, **kwargs): '''Wrapper for solving Friendly Captcha. Parameters __________ sitekey : str The value of data-sitekey attribute of captcha's div element on page. url : str Full URL of the page where you solve the captcha. softId : int, optional ID of software developer. Developers who integrated their software with 2Captcha get reward: 10% of spendings of their software users. callback : str, optional URL for pingback (callback) response that will be sent when captcha is solved. URL should be registered on the server. More info here https://2captcha.com/2captcha-api#pingback. proxy : dict, optional {'type': 'HTTPS', 'uri': 'login:password@IP_address:PORT'}. ''' result = self.solve(sitekey=sitekey, url=url, method='friendly_captcha', **kwargs) return result def tencent(self, app_id, url, **kwargs): '''Wrapper for solving Tencent captcha. Parameters __________ app_id : str The value of appId parameter in the website source code. url : str The full URL of target web page where the captcha is loaded. We do not open the page, not a problem if it is available only for authenticated users. softId : int, optional ID of software developer. Developers who integrated their software with 2Captcha get reward: 10% of spendings of their software users. callback : str, optional URL for pingback (callback) response that will be sent when captcha is solved. URL should be registered on the server. More info here https://2captcha.com/2captcha-api#pingback. proxy : dict, optional {'type': 'HTTPS', 'uri': 'login:password@IP_address:PORT'}. ''' result = self.solve(app_id=app_id, url=url, method="tencent", **kwargs) return result def cutcaptcha(self, misery_key, apikey, url, **kwargs): '''Wrapper for solving Friendly Captcha. Parameters __________ misery_key : str The value of CUTCAPTCHA_MISERY_KEY variable defined on page. apikey : str The value of data-apikey attribute of iframe's body. Also, the name of javascript file included on the page. url : str Full URL of the page where you solve the captcha. softId : int, optional ID of software developer. Developers who integrated their software with 2Captcha get reward: 10% of spendings of their software users. callback : str, optional URL for pingback (callback) response that will be sent when captcha is solved. URL should be registered on the server. More info here https://2captcha.com/2captcha-api#pingback. proxy : dict, optional {'type': 'HTTPS', 'uri': 'login:password@IP_address:PORT'}. ''' result = self.solve(misery_key=misery_key, api_key=apikey, url=url, method='cutcaptcha', **kwargs) return result def vkimage(self, files, steps, **kwargs): '''Wrapper for solving vkimage captcha. Parameters __________ file : str Captcha image as a file or base64. steps: str Array of steps. proxy : dict, optional {'type': 'HTTPS', 'uri': 'login:password@IP_address:PORT'}. ''' if isinstance(files, str): payload = self.get_method(files) payload.pop('method', None) result = self.solve(method='vkimage', steps=steps, **payload, **kwargs) return result elif isinstance(files, dict): files = list(files.values()) files = self.extract_files(files) result = self.solve(method='vkimage', files=files, steps=steps, **kwargs) return result def vkcaptcha(self, redirect_uri, userAgent, proxy, **kwargs): '''Wrapper for solving VK captcha using tokens. Parameters __________ redirect_uri : str The URL that is returned for requests to the captchas API. userAgent : str User-Agent of the browser that will be used by the employee when loading the captcha. proxy : dict {'type': 'HTTPS', 'uri': 'login:password@IP_address:PORT'}. ''' result = self.solve(method='vkcaptcha', redirect_uri=redirect_uri, useragent=userAgent, proxy=proxy, **kwargs) return result def captchafox(self, sitekey, pageurl, userAgent, proxy, **kwargs): '''Wrapper for solving CaptchaFox using tokens. Parameters __________ sitekey : str The sitekey parameter value found on the page or in network requests. pageurl : str Full URL of the page with captcha. userAgent : str User-Agent of the browser that will be used by the employee when loading the captcha. proxy : dict {'type': 'HTTPS', 'uri': 'login:password@IP_address:PORT'}. api_server : str, optional Default: https://cdn.captchafox.com/. Depending on the parameter value, the token format changes — it will be prefixed with MAM_. For this, you need to set the server URL to: https://s.uicdn.com/mampkg/@mamdev/core.frontend.libs.captchafox/. Two different APIs return two different tokens. Choose the one you need. ''' result = self.solve(method='captchafox', sitekey=sitekey, pageurl=pageurl, useragent=userAgent, proxy=proxy, **kwargs) return result def prosopo(self, sitekey, pageurl, **kwargs): '''Wrapper for solving Prosopo captcha using tokens. Parameters __________ sitekey : str The sitekey parameter value found on the page or in network requests. pageurl : str Full URL of the page with captcha. proxy : dict, optional {'type': 'HTTPS', 'uri': 'login:password@IP_address:PORT'}. ''' result = self.solve(method='prosopo', sitekey=sitekey, pageurl=pageurl, **kwargs) return result def temu(self, body, part1, part2, part3, **kwargs): '''Wrapper for solving Temu captcha . Parameters __________ body : str Main captcha image as a base64 string. part1 : str Tile element as a base64 string. part2 : str Tile element as a base64 string. part3 : str Tile element as a base64 string. ''' result = self.solve(method='temuimage', body=body, part1=part1, part2=part2, part3=part3, **kwargs) return result def datadome(self, captcha_url, pageurl, userAgent, proxy, **kwargs): """Wrapper for solving DataDome Captcha. Parameters __________ captcha_url: str The value of the 'src' parameter for the 'iframe' element containing the captcha on the page. pageurl: str Full URL of the page that triggers the captcha when you go to it. userAgent: str User-Agent of the browser that will be used by the employee when loading the captcha. proxy : dict {'type': 'HTTPS', 'uri': 'login:password@IP_address:PORT'}. """ result = self.solve(method='datadome', captcha_url=captcha_url, pageurl=pageurl, userAgent=userAgent, proxy=proxy, **kwargs) return result def cybersiara(self, master_url_id, pageurl, userAgent, **kwargs): '''Wrapper for solving CyberSiARA captcha. Parameters __________ master_url_id : str The value of the MasterUrlId parameter from the request to API/CyberSiara/GetCyberSiara. pageurl : str Full URL of the page with captcha. userAgent : str User-Agent of your browser. proxy : dict, optional {'type': 'HTTPS', 'uri': 'login:password@IP_address:PORT'}. ''' result = self.solve(method='cybersiara', master_url_id=master_url_id, pageurl=pageurl, userAgent=userAgent, **kwargs) return result def yandex_smart(self, sitekey, url, **kwargs): '''Wrapper for solving Yandex Smart. Parameters __________ sitekey : str The value of data-sitekey attribute of captcha's div element on page. url : str Full URL of the page where you solve the captcha. softId : int, optional ID of software developer. Developers who integrated their software with 2Captcha get reward: 10% of spendings of their software users. callback : str, optional URL for pingback (callback) response that will be sent when captcha is solved. URL should be registered on the server. More info here https://2captcha.com/2captcha-api#pingback. proxy : dict, optional {'type': 'HTTPS', 'uri': 'login:password@IP_address:PORT'}. userAgent: str, optional User-Agent of the browser that will be used by the employee when loading the captcha. ''' result = self.solve(sitekey=sitekey, url=url, method='yandex', **kwargs) return result def altcha(self, pageurl, **kwargs): '''Wrapper for solving Altcha Captcha. Parameters __________ pageurl : str Full URL of the page where you solve the captcha. challenge_url : str, optional The value of the 'challenge_url' parameter for the 'altcha-widget' element containing the captcha on the page. At least one of the parameters 'challenge_url', 'challenge_json' must be passed. challenge_json : str, optional The contents of the file from the 'challenge_url' parameter. At least one of the parameters 'challenge_url', 'challenge_json' must be passed. proxy : dict, optional {'type': 'HTTPS', 'uri': 'login:password@IP_address:PORT'}. ''' result = self.solve( pageurl=pageurl, method="altcha", **kwargs) return result def binance(self, pageurl, sitekey, validate_id, **kwargs): '''Wrapper for solving Binance captcha. Parameters __________ pageurl : str Full URL of the page where you solve the captcha. sitekey : str Value of 'bizId', 'bizType', or 'bizCode' from page requests. validate_id : str Dynamic value of 'validateId', 'securityId', or 'securityCheckResponseValidateId'. useragent : str, optional Browser User-Agent. We recommend sending a valid Windows browser string. proxy : dict, optional {'type': 'HTTPS', 'uri': 'login:password@IP_address:PORT'}. ''' result = self.solve( method="binance", pageurl=pageurl, sitekey=sitekey, validate_id=validate_id, **kwargs) return result def yidun(self, sitekey, pageurl, **kwargs): '''Wrapper for solving Yidun captcha. Parameters __________ sitekey : str The 'sitekey' value found in the website source code. pageurl : str Full URL of the page containing the captcha. yidun_get_lib : str, optional Path to the JavaScript file that loads the captcha on the page. Important: use the full URL (https://...). Recommended if the site includes challenge, hcg, or hct fields. yidun_api_server_subdomain : str, optional Yidun API server subdomain. Enter only the domain, without the https:// prefix. challenge : str, optional Usually sent in network requests during captcha initialization or display. hcg : str, optional Captcha hash used when forming the request. You can get this together with challenge. hct : int, optional Numeric timestamp or identifier used for Enterprise version validation. useragent : str, optional Browser User-Agent. We recommend sending a valid Windows browser string. proxy : dict, optional {'type': 'HTTPS', 'uri': 'login:password@IP_address:PORT'}. ''' result = self.solve( method="yidun", pageurl=pageurl, sitekey=sitekey, **kwargs) return result def hunt(self, pageurl, api_get_lib, **kwargs): '''Wrapper for solving Hunt captcha. Parameters __________ pageurl : str Full URL of the page with the captcha. api_get_lib : str Full link to the api.js file that loads the captcha on the page. data : str, optional Value of `meta.token` that the site returned after a request with X-HD. Use only for the captcha solving mode (second step). useragent : str, optional Browser User-Agent used to open the page. proxy : dict, optional {'type': 'HTTPS', 'uri': 'login:password@IP_address:PORT'}. ''' result = self.solve( method="hunt", pageurl=pageurl, api_get_lib=api_get_lib, **kwargs) return result def alibaba(self, pageurl, scene_id, prefix, **kwargs): '''Wrapper for solving Alibaba captcha. Parameters __________ pageurl : str Full URL of the page with the captcha. scene_id : str Captcha scenario identifier. prefix : str Prefix from the captcha loading request subdomain. user_id : str, optional User or session identifier on the website. user_user_id : str, optional Additional user identifier. verify_type : str, optional Verification mechanism version or type. region : str, optional Captcha processing region. user_certify_id : str, optional Verification ID for the current captcha session. api_get_lib : str, optional URL of the Alibaba Captcha JS library. useragent : str, optional Browser User-Agent used to open the page. proxy : dict, optional {'type': 'HTTPS', 'uri': 'login:password@IP_address:PORT'}. ''' result = self.solve( method="alibaba", pageurl=pageurl, scene_id=scene_id, prefix=prefix, **kwargs) return result def tspd(self, pageurl, tspd_cookie, html_page_base64, proxy, **kwargs): '''Wrapper for solving TSPD captcha. Parameters __________ pageurl : str Full URL of the page with the captcha. tspd_cookie : str Cookies received on the TSPD challenge page. html_page_base64 : str Full HTML of the challenge page, Base64 encoded. proxy : dict {'type': 'HTTPS', 'uri': 'login:password@IP_address:PORT'}. useragent : str, optional Browser User-Agent. We recommend sending a valid Windows browser string. ''' result = self.solve( method="tspd", pageurl=pageurl, tspd_cookie=tspd_cookie, html_page_base64=html_page_base64, proxy=proxy, **kwargs) return result def basilisk(self, pageurl, sitekey, **kwargs): '''Wrapper for solving Basilisk captcha. Parameters __________ pageurl : str Full URL of the page with the captcha. sitekey : str The value of the data-site-key parameter found on the page. useragent : str, optional Browser User-Agent used to open the page. proxy : dict, optional {'type': 'HTTPS', 'uri': 'login:password@IP_address:PORT'}. ''' result = self.solve( method="basilisk", pageurl=pageurl, sitekey=sitekey, **kwargs) return result def solve(self, timeout=0, polling_interval=0, **kwargs): '''Sends captcha, receives result. Parameters __________ timeout : float polling_interval : int **kwargs : dict all captcha params Returns result : string ''' id_ = self.send(**kwargs) result = {'captchaId': id_} if self.callback is None: timeout = float(timeout or self.default_timeout) sleep = int(polling_interval or self.polling_interval) code = self.wait_result(id_, timeout, sleep) if self.extendedResponse == True: new_code = { key if key != 'request' else 'code': value for key, value in code.items() if key != 'status' } result.update(new_code) else: result.update({'code': code}) return result def wait_result(self, id_, timeout, polling_interval): max_wait = time.time() + timeout while time.time() < max_wait: try: return self.get_result(id_) except NetworkException: time.sleep(polling_interval) raise TimeoutException(f'timeout {timeout} exceeded') def get_method(self, file): if not file: raise ValidationException('File required') if not '.' in file and len(file) > 50: return {'method': 'base64', 'body': file} if file.startswith('http'): img_resp = requests.get(file) if img_resp.status_code != 200: raise ValidationException(f'File could not be downloaded from url: {file}') return {'method': 'base64', 'body': b64encode(img_resp.content).decode('utf-8')} if not os.path.exists(file): raise ValidationException(f'File not found: {file}') return {'method': 'post', 'file': file} def send(self, **kwargs): """This method can be used for manual captcha submission Parameters __________ method : str The name of the method must be found in the documentation https://2captcha.com/2captcha-api kwargs: dict All captcha params Returns """ params = self.default_params(kwargs) params = self.rename_params(params) params, files = self.check_hint_img(params) response = self.api_client.in_(files=files, **params) if not response.startswith('OK|'): raise ApiException(f'cannot recognize response {response}') return response[3:] def get_result(self, id_): import json """This method can be used for manual captcha answer polling. Parameters __________ id_ : str ID of the captcha sent for solution Returns answer : text """ if self.extendedResponse == True: response = self.api_client.res(key=self.API_KEY, action='get', id=id_, json=1) response_data = json.loads(response) if response_data.get("status") == 0: raise NetworkException if not response_data.get("status") == 1: raise ApiException(f'Unexpected status in response: {response_data}') return response_data else: response = self.api_client.res(key=self.API_KEY, action='get', id=id_) if response == 'CAPCHA_NOT_READY': raise NetworkException if not response.startswith('OK|'): raise ApiException(f'cannot recognize response {response}') return response[3:] def balance(self): '''Get my balance Returns balance : float ''' response = self.api_client.res(key=self.API_KEY, action='getbalance') return float(response) def report(self, id_, correct): '''Report of solved captcha: good/bad. Parameters __________ id_ : str captcha ID correct : bool True/False Returns None. ''' rep = 'reportgood' if correct else 'reportbad' answer = self.api_client.res(key=self.API_KEY, action=rep, id=id_) return answer def rename_params(self, params): replace = { 'caseSensitive': 'regsense', 'minLen': 'min_len', 'maxLen': 'max_len', 'minLength': 'min_len', 'maxLength': 'max_len', 'hintText': 'textinstructions', 'hintImg': 'imginstructions', 'url': 'pageurl', 'score': 'min_score', 'text': 'textcaptcha', 'rows': 'recaptcharows', 'cols': 'recaptchacols', 'previousId': 'previousID', 'canSkip': 'can_no_answer', 'apiServer': 'api_server', 'softId': 'soft_id', 'callback': 'pingback', 'datas': 'data-s', } new_params = { v: params.pop(k) for k, v in replace.items() if k in params } proxy = params.pop('proxy', '') proxy and new_params.update({ 'proxy': proxy['uri'], 'proxytype': proxy['type'] }) new_params.update(params) return new_params def default_params(self, params): params.update({'key': self.API_KEY}) callback = params.pop('callback', self.callback) soft_id = params.pop('softId', self.soft_id) if callback: params.update({'callback': callback}) if soft_id: params.update({'softId': soft_id}) self.has_callback = bool(callback) return params def extract_files(self, files): if len(files) > self.max_files: raise ValidationException( f'Too many files (max: {self.max_files})') not_exists = [f for f in files if not (os.path.exists(f))] if not_exists: raise ValidationException(f'File not found: {not_exists}') files = {f'file_{e + 1}': f for e, f in enumerate(files)} return files def check_hint_img(self, params): hint = params.pop('imginstructions', None) files = params.pop('files', {}) if not hint: return params, files if not '.' in hint and len(hint) > 50: params.update({'imginstructions': hint}) return params, files if not os.path.exists(hint): raise ValidationException(f'File not found: {hint}') if not files: files = {'file': params.pop('file', {})} files.update({'imginstructions': hint}) return params, files if __name__ == '__main__': key = sys.argv[1] sol = TwoCaptcha(key)