I am trying to login to familysearch.org with help of python and Playwright library. Problem -- I see a CAPTCHA (attached image) when I am using my python script. Was trying playwright_stealth to overcome CAPTCH but it didn't help My code #!/usr/bin/env python3 """ FamilySearch Login Script using Playwright Stealth """ import asyncio import os from playwright.async_api import async_playwright from playwright_stealth import Stealth import time class FamilySearchLogin: def __init__(self, headless: bool = False): self.headless = headless self.browser = None self.page = None self.playwright = None async def start_browser(self): """Start the browser and create a new page with stealth mode""" self.playwright = await async_playwright().start() self.browser = await self.playwright.chromium.launch( headless=self.headless, args=[ '--no-sandbox', '--disable-blink-features=AutomationControlled', '--disable-dev-shm-usage', '--disable-web-security', '--disable-features=VizDisplayCompositor', '--disable-background-timer-throttling', '--disable-backgrounding-occluded-windows', '--disable-renderer-backgrounding', '--disable-field-trial-config', '--disable-ipc-flooding-protection' ] ) context = await self.browser.new_context( viewport={'width': 1920, 'height': 1080}, user_agent='Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36', locale='en-US', timezone_id='America/New_York' ) self.page = await context.new_page() # Apply stealth mode stealth = Stealth() await stealth.apply_stealth_async(self.page) # Additional stealth measures await self.page.add_init_script(""" Object.defineProperty(navigator, 'webdriver', { get: () => undefined, }); // Override permissions const originalQuery = window.navigator.permissions.query; window.navigator.permissions.query = (parameters) => ( parameters.name === 'notifications' ? Promise.resolve({ state: Notification.permission }) : originalQuery(parameters) ); // Override plugins Object.defineProperty(navigator, 'plugins', { get: () => [1, 2, 3, 4, 5], }); // Override languages Object.defineProperty(navigator, 'languages', { get: () => ['en-US', 'en'], }); // Override connection Object.defineProperty(navigator, 'connection', { get: () => ({ effectiveType: '4g', rtt: 50, downlink: 10, saveData: false }), }); """) async def navigate_to_login(self): """Navigate to the FamilySearch login page""" login_url = "https://ident.familysearch.org/ru/identity/login/?state=https://www.familysearch.org/ru/" print(f"Navigating to: {login_url}") # Add random delays to appear more human-like await asyncio.sleep(1 + (time.time() % 2)) await self.page.goto(login_url, wait_until='networkidle') # Random wait time await asyncio.sleep(2 + (time.time() % 3)) print("Successfully loaded FamilySearch login page") async def handle_captcha_checkbox(self): """Handle the 'I'm not a robot' checkbox if present""" try: captcha_selectors = [ 'iframe[title*="reCAPTCHA"]', 'iframe[src*="recaptcha"]', '.recaptcha-checkbox', '#recaptcha-anchor', 'iframe[title*="robot"]', 'iframe[title*="captcha"]' ] for selector in captcha_selectors: try: captcha_frame = await self.page.query_selector(selector) if captcha_frame: print(f"Found captcha element: {selector}") if 'iframe' in selector: frame = await captcha_frame.content_frame() if frame: checkbox = await frame.query_selector('.recaptcha-checkbox-border') if checkbox: print("Clicking 'I'm not a robot' checkbox...") # Human-like click with random delay await asyncio.sleep(0.5 + (time.time() % 1)) await checkbox.click() await asyncio.sleep(2 + (time.time() % 2)) return True else: print("Clicking 'I'm not a robot' checkbox...") await asyncio.sleep(0.5 + (time.time() % 1)) await captcha_frame.click() await asyncio.sleep(2 + (time.time() % 2)) return True except Exception as e: continue print("No captcha checkbox found or already completed") return False except Exception as e: print(f"Error handling captcha: {e}") return False async def fill_login_form(self, username: str, password: str): """Fill in the login form with credentials using human-like behavior""" try: print("Filling login form...") await self.page.wait_for_load_state('networkidle') # Find username field username_selectors = [ 'input[name="username"]', 'input[name="email"]', 'input[type="email"]', 'input[placeholder*="email"]', 'input[placeholder*="Email"]', 'input[id*="username"]', 'input[id*="email"]' ] username_field = None for selector in username_selectors: try: username_field = await self.page.query_selector(selector) if username_field: break except: continue if not username_field: print("Could not find username field") return False # Human-like typing for username await username_field.click() await asyncio.sleep(0.2) await username_field.fill("") await asyncio.sleep(0.1) for char in username: await username_field.type(char) await asyncio.sleep(0.05 + (time.time() % 0.1)) print("Username filled") await asyncio.sleep(0.5 + (time.time() % 1)) # Find password field password_selectors = [ 'input[name="password"]', 'input[type="password"]', 'input[placeholder*="password"]', 'input[placeholder*="Password"]', 'input[id*="password"]' ] password_field = None for selector in password_selectors: try: password_field = await self.page.query_selector(selector) if password_field: break except: continue if not password_field: print("Could not find password field") return False # Human-like typing for password await password_field.click() await asyncio.sleep(0.2) await password_field.fill("") await asyncio.sleep(0.1) for char in password: await password_field.type(char) await asyncio.sleep(0.05 + (time.time() % 0.1)) print("Password filled") await asyncio.sleep(0.5 + (time.time() % 1)) return True except Exception as e: print(f"Error filling login form: {e}") return False async def submit_login(self): """Submit the login form""" try: print("Submitting login form...") submit_selectors = [ 'button[type="submit"]', 'input[type="submit"]', 'button:has-text("Sign In")', 'button:has-text("Login")', 'button:has-text("Войти")', 'button:has-text("Вход")', 'button[class*="submit"]', 'button[class*="login"]' ] submit_button = None for selector in submit_selectors: try: submit_button = await self.page.query_selector(selector) if submit_button: break except: continue if not submit_button: print("Could not find submit button") return False # Human-like click with random delay await asyncio.sleep(0.5 + (time.time() % 1)) await submit_button.click() print("Login form submitted") # Wait for navigation with random delay await asyncio.sleep(3 + (time.time() % 3)) return True except Exception as e: print(f"Error submitting login form: {e}") return False async def check_login_success(self): """Check if login was successful""" try: await asyncio.sleep(2 + (time.time() % 2)) current_url = self.page.url print(f"Current URL: {current_url}") if "familysearch.org" in current_url and "login" not in current_url: print("Login appears to be successful!") return True else: print("Login may have failed - still on login page") return False except Exception as e: print(f"Error checking login status: {e}") return False async def login(self, username: str, password: str): """Complete login process""" try: await self.start_browser() await self.navigate_to_login() await self.handle_captcha_checkbox() if not await self.fill_login_form(username, password): return False if not await self.submit_login(): return False success = await self.check_login_success() if success: print("Login completed successfully!") return True else: print("Login failed or requires manual intervention") return False except Exception as e: print(f"Error during login process: {e}") return False async def close(self): """Close browser and cleanup""" if self.browser: await self.browser.close() if self.playwright: await self.playwright.stop() async def main(): """Main function to run the login script""" username = os.getenv('FAMILYSEARCH_USERNAME') password = os.getenv('FAMILYSEARCH_PASSWORD') if not username: username = input("Enter FamilySearch username/email: ") if not password: password = input("Enter FamilySearch password: ") login_handler = FamilySearchLogin(headless=False) try: success = await login_handler.login(username, password) if success: print("Login successful! You can now interact with the page.") input("Press Enter to close the browser...") else: print("Login failed. Please check your credentials and try again.") except Exception as e: print(f"An error occurred: {e}") finally: await login_handler.close() if __name__ == "__main__": asyncio.run(main()) Continue reading...