Download api.py from karakara73/rcs: direct link, hf CLI and curl.
- Browser
- Download file 12.1 kB
-
https://huggingface.co/karakara73/rcs/resolve/main/api.py
- Command line
-
hf download hf://karakara73/rcs/api.py
-
curl -L -o api.py https://huggingface.co/karakara73/rcs/resolve/main/api.py
12.1 kB
| import json | |
| import os | |
| import glob | |
| from random import uniform, randint | |
| from time import sleep | |
| from urllib.request import urlretrieve | |
| from pydub import AudioSegment | |
| from pydub.effects import normalize | |
| from selenium import webdriver | |
| from selenium.webdriver.common.action_chains import ActionChains | |
| import undetected_chromedriver as uc | |
| from selenium.common.exceptions import NoSuchElementException, TimeoutException | |
| from selenium.webdriver.common.by import By | |
| from selenium.webdriver.common.keys import Keys | |
| from selenium.webdriver.support.expected_conditions import \ | |
| presence_of_element_located as poel | |
| from selenium.webdriver.support.ui import WebDriverWait | |
| from selenium.webdriver.chrome.options import Options | |
| from selenium.webdriver.chrome.service import Service | |
| # Firefox support (Camoufox) | |
| from selenium.webdriver.firefox.options import Options as FirefoxOptions | |
| from selenium.webdriver.firefox.service import Service as GeckoService | |
| from webdriver_manager.chrome import ChromeDriverManager | |
| from webdriver_manager.firefox import GeckoDriverManager | |
| from speech_recognition import AudioFile, Recognizer | |
| from faster_whisper import WhisperModel | |
| from user_agent import generate_user_agent | |
| from colorize import Colors | |
| from proxier import Proxier | |
| class RecaptchaBypass: | |
| def __init__(self, debug=False, use_proxy=False, use_agent=False, headless=True): | |
| self.debug = debug | |
| self.use_proxy = use_proxy | |
| self.use_agent = use_agent | |
| self.headless = headless | |
| self.current_proxy = None | |
| self.proxier = Proxier() if use_proxy else None | |
| self._print_message(Colors.INFO, f'{Colors.blue}Loading Whisper model (tiny.en)...{Colors.reset}') | |
| self.whisper_model = WhisperModel("tiny.en", device="cpu", compute_type="int8") | |
| self.browser = self._get_chromedriver(use_proxy, use_agent, headless) | |
| self.wait = WebDriverWait(self.browser, 30) | |
| def _get_chromedriver(self, use_proxy, use_agent, headless): | |
| camoufox_cache = os.path.expanduser('~/.cache/camoufox') | |
| camoufox_bin = None | |
| if os.path.isdir(camoufox_cache): | |
| candidates = [ | |
| os.path.join(camoufox_cache, 'camoufox-bin'), | |
| os.path.join(camoufox_cache, 'camoufox'), | |
| os.path.join(camoufox_cache, 'browser', 'camoufox') | |
| ] | |
| for c in candidates: | |
| if os.path.isfile(c) and os.access(c, os.X_OK): | |
| camoufox_bin = c | |
| break | |
| if camoufox_bin: | |
| self._print_message(Colors.INFO, f'{Colors.purple}Camoufox binary detected {Colors.red}>{Colors.reset} {camoufox_bin}') | |
| gecko_path = '/usr/bin/geckodriver' | |
| if not os.path.exists(gecko_path): | |
| gecko_path = GeckoDriverManager().install() | |
| fox_opts = FirefoxOptions() | |
| os.environ['MOZ_NODEJS'] = '1' | |
| if headless: | |
| fox_opts.add_argument('-headless') | |
| fox_opts.binary_location = camoufox_bin | |
| fox_opts.set_preference('security.sandbox.content.level', 0) | |
| fox_opts.set_preference('dom.webdriver.enabled', False) | |
| fox_opts.set_preference('useprivacy', True) | |
| fox_opts.set_preference('general.useragent.override', generate_user_agent()) | |
| fox_opts.set_preference('intl.accept_languages', 'en-US, en') | |
| fox_opts.set_preference('media.volume_scale', '0.0') | |
| if use_proxy: | |
| proxy_str = self._setup_proxy() | |
| if '://' in proxy_str: | |
| addr = proxy_str.split('://')[1] | |
| host, port = addr.split(':') | |
| fox_opts.set_preference('network.proxy.type', 1) | |
| fox_opts.set_preference('network.proxy.http', host) | |
| fox_opts.set_preference('network.proxy.http_port', int(port)) | |
| fox_opts.set_preference('network.proxy.ssl', host) | |
| fox_opts.set_preference('network.proxy.ssl_port', int(port)) | |
| service = GeckoService(gecko_path) | |
| return webdriver.Firefox(service=service, options=fox_opts) | |
| chrome_options = Options() | |
| if headless: chrome_options.add_argument('--headless=new') | |
| return uc.Chrome(options=chrome_options) | |
| def _print_message(self, level, message): | |
| print(f'{level} {message}') | |
| def _quit_browser(self): | |
| try: self.browser.quit() | |
| except: pass | |
| def _human_mouse_movement(self): | |
| try: | |
| actions = ActionChains(self.browser) | |
| for _ in range(randint(2, 4)): | |
| actions.move_by_offset(randint(-20, 20), randint(-20, 20)).pause(uniform(0.1, 0.2)) | |
| actions.perform() | |
| except: pass | |
| def _solve_logic(self, i): | |
| if self._is_block(): | |
| return {'status': 'blocked'} | |
| # Click Checkbox | |
| self._print_message(Colors.INFO, f'{Colors.blue}Getting recaptcha checkbox..{Colors.reset}') | |
| iframe = self.wait.until(poel((By.CSS_SELECTOR, "iframe[src*='recaptcha/api2/anchor']"))) | |
| self.browser.switch_to.frame(iframe) | |
| check_box = self.wait.until(poel((By.ID, "recaptcha-anchor"))) | |
| self._human_mouse_movement() | |
| ActionChains(self.browser).move_to_element(check_box).pause(uniform(0.5, 1.0)).click().perform() | |
| self.browser.switch_to.default_content() | |
| sleep(uniform(2, 4)) | |
| if self._is_block(): | |
| return {'status': 'blocked'} | |
| # Check if solved automatically | |
| token = self._get_token_from_page() | |
| if token: return {'status': 'solved', 'token': token} | |
| # Click Audio | |
| self._print_message(Colors.INFO, f'{Colors.blue}Getting recaptcha challenge..{Colors.reset}') | |
| self.wait.until(lambda d: len(d.find_elements(By.CSS_SELECTOR, "iframe[src*='recaptcha/api2/bframe']")) > 0) | |
| iframe = self.browser.find_element(By.CSS_SELECTOR, "iframe[src*='recaptcha/api2/bframe']") | |
| self.browser.switch_to.frame(iframe) | |
| if self._is_block(): | |
| self.browser.switch_to.default_content() | |
| return {'status': 'blocked'} | |
| audio_button = self.wait.until(poel((By.ID, 'recaptcha-audio-button'))) | |
| ActionChains(self.browser).move_to_element(audio_button).pause(uniform(0.5, 1.0)).click().perform() | |
| # Get Audio URL | |
| download_link = self.wait.until(poel((By.CLASS_NAME, 'rc-audiochallenge-tdownload-link'))) | |
| audio_url = download_link.get_attribute('href') | |
| self.browser.switch_to.default_content() | |
| # Transcribe | |
| phrase_text, _ = self._audio_to_text(audio_url) | |
| self._print_message(Colors.INFO, f'{Colors.purple}Phrase Text {Colors.red}> {Colors.green}{phrase_text}{Colors.reset}') | |
| # Enter Phrase | |
| self.browser.switch_to.frame(self.browser.find_element(By.CSS_SELECTOR, "iframe[src*='recaptcha/api2/bframe']")) | |
| input_field = self.wait.until(poel((By.ID, 'audio-response'))) | |
| for char in phrase_text: | |
| input_field.send_keys(char) | |
| sleep(uniform(0.05, 0.15)) | |
| sleep(uniform(0.5, 1)) | |
| input_field.send_keys(Keys.ENTER) | |
| self.browser.switch_to.default_content() | |
| sleep(uniform(3, 5)) | |
| token = self._get_token_from_page() | |
| if token: | |
| return {'status': 'solved', 'token': token} | |
| return {'status': 'failed'} | |
| def get_token(self, url, max_retries=5): | |
| for i in range(max_retries): | |
| self._print_message(Colors.INFO, f'{Colors.blue}Token retrieval attempt {i+1}/{max_retries}..{Colors.reset}') | |
| try: | |
| if i > 0: | |
| self._quit_browser() | |
| self.browser = self._get_chromedriver(self.use_proxy, self.use_agent, self.headless) | |
| self.wait = WebDriverWait(self.browser, 30) | |
| self.browser.get(url) | |
| sleep(uniform(5, 7)) | |
| result = self._solve_logic(i) | |
| if result['status'] == 'solved': | |
| self._print_message(Colors.SUCCESS, f'Token retrieved! 📍\n{Colors.white}{result["token"]}{Colors.reset}\n') | |
| token = result['token'] | |
| self._quit_browser() | |
| return {'success': True, 'token': token} | |
| elif result['status'] == 'blocked': | |
| if self.use_proxy and self.current_proxy: self.proxier.remove_proxy(self.current_proxy) | |
| continue | |
| except Exception as e: | |
| self._print_message(Colors.FAILED, f'Error: {str(e)}') | |
| continue | |
| self._quit_browser() | |
| return {'success': False, 'error': 'Max retries reached'} | |
| def bypass_recaptcha_v2(self, url, max_retries=5): | |
| for i in range(max_retries): | |
| self._print_message(Colors.INFO, f'{Colors.blue}Bypass attempt {i+1}/{max_retries}..{Colors.reset}') | |
| try: | |
| if i > 0: | |
| self._quit_browser() | |
| self.browser = self._get_chromedriver(self.use_proxy, self.use_agent, self.headless) | |
| self.wait = WebDriverWait(self.browser, 30) | |
| self.browser.get(url) | |
| sleep(uniform(5, 7)) | |
| solve_res = self._solve_logic(i) | |
| if solve_res['status'] == 'solved': | |
| token = solve_res['token'] | |
| self._print_message(Colors.SUCCESS, 'V2 Bypassed! 📍') | |
| self._print_message(Colors.INFO, f'Token: {token[:100]}...') | |
| # Try to click submit if it's the demo page | |
| if 'google.com/recaptcha/api2/demo' in self.browser.current_url: | |
| try: | |
| submit_btn = self.browser.find_element(By.ID, 'recaptcha-demo-submit') | |
| self.browser.execute_script("arguments[0].click();", submit_btn) | |
| sleep(3) | |
| except: pass | |
| self._quit_browser() | |
| return {'success': True, 'token': token} | |
| if solve_res['status'] == 'blocked' and self.use_proxy: | |
| self.proxier.remove_proxy(self.current_proxy) | |
| self._quit_browser() | |
| except Exception as e: | |
| self._print_message(Colors.FAILED, f'Error: {str(e)}') | |
| self._quit_browser() | |
| return {'success': False} | |
| def _get_token_from_page(self): | |
| try: | |
| textarea = self.browser.find_element(By.ID, "g-recaptcha-response") | |
| token = textarea.get_attribute("value") | |
| if token and len(token) > 100: return token | |
| except: pass | |
| return None | |
| def _audio_to_text(self, audio_url): | |
| filename = 'audio.mp3' | |
| wav_output = 'audio.wav' | |
| import urllib.request | |
| opener = urllib.request.build_opener() | |
| opener.addheaders = [('User-Agent', generate_user_agent())] | |
| urllib.request.install_opener(opener) | |
| urlretrieve(audio_url, filename) | |
| AudioSegment.from_mp3(filename).export(wav_output, format='wav') | |
| segments, _ = self.whisper_model.transcribe(wav_output) | |
| phrase = " ".join([s.text for s in segments]).strip() | |
| if not self.debug: | |
| for f in [filename, wav_output]: | |
| if os.path.exists(f): os.remove(f) | |
| return phrase, wav_output | |
| def _is_block(self): | |
| try: | |
| txt = self.browser.page_source.lower() | |
| if "try again later" in txt or "automated queries" in txt: return True | |
| except: pass | |
| return None | |