From 3ab79893c3d1e7b8ccacc9f2f277e1f916028b1f Mon Sep 17 00:00:00 2001 From: Edward Betts Date: Wed, 18 Feb 2026 12:35:03 +0000 Subject: [PATCH] Handle Google CAPTCHA by opening headed browser for manual solve Also wait for [data-attrid="Price"] instead of #center_col to ensure the finance widget has rendered before parsing. Co-Authored-By: Claude Sonnet 4.6 --- google_stocks/__init__.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/google_stocks/__init__.py b/google_stocks/__init__.py index 444bacd..c532271 100644 --- a/google_stocks/__init__.py +++ b/google_stocks/__init__.py @@ -96,18 +96,26 @@ class Index: accept_cookies(page) stay_signed_out(page) - expect(page.locator("#center_col")).to_be_visible() + if page.locator("#recaptcha, #captcha-form").count() > 0: + captcha_url = page.url + context.close() + browser.close() + + print("Google is showing a CAPTCHA. Solve it in the browser window...", flush=True) + browser = playwright.chromium.launch(headless=False) + context = browser.new_context(storage_state=auth_file) + page = context.new_page() + page.goto(captcha_url, wait_until="domcontentloaded") + + page.wait_for_selector('[data-attrid="Price"]', timeout=120000) html = page.content() - context.storage_state(path=auth_file) filename = data_filename("serp") with open(filename, "w") as out: out.write(html) self.parse_html(html) - page.close() - context.storage_state(path=auth_file) context.close() browser.close()