[Python] How can I avoid CAPTCHA with help of Playwright?

Discussão em 'Python' iniciado por Stack, Junho 28, 2025.

  1. Stack

    Stack Membro Participativo

    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[​IMG]

    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...

Compartilhe esta Página