diff --git a/monitor.py b/monitor.py index e37f5fc..fa6be36 100644 --- a/monitor.py +++ b/monitor.py @@ -450,90 +450,99 @@ class ApplicationHandler: await apply_btn.click() await asyncio.sleep(3) await page.wait_for_load_state("networkidle") - logger.info("[HOWOGE] Clicked button, waiting for form...") + logger.info("[HOWOGE] Clicked button, starting multi-step form process...") - # Scroll down the page to reveal checkboxes - await page.evaluate("window.scrollBy(0, 500)") - await asyncio.sleep(1) - logger.info("[HOWOGE] Scrolled down to reveal checkboxes") + # HOWOGE has a multi-step form (typically 3-4 steps): + # Each step has a checkbox that must be clicked, then "Weiter" button + # Final step has the actual contact form - # Screenshot after clicking (before checkboxes) - screenshot_path = DATA_DIR / f"howoge_form_{listing['id']}.png" - await page.screenshot(path=str(screenshot_path), full_page=True) - logger.info(f"[HOWOGE] Saved form screenshot to {screenshot_path}") + max_steps = 6 # safety limit + for step in range(1, max_steps + 1): + logger.info(f"[HOWOGE] Processing step {step}") - # HOWOGE requires clicking checkboxes before the form fields become visible - # Look for and click all required checkboxes - checkboxes_clicked = 0 - checkbox_selectors = [ - 'input[type="checkbox"]', - '.checkbox input', - 'input[name*="datenschutz" i]', - 'input[name*="privacy" i]', - 'input[name*="einwillig" i]', - 'input[name*="zustimmung" i]', - 'input[name*="accept" i]', - ] + # Scroll down to reveal checkboxes + await page.evaluate("window.scrollBy(0, 300)") + await asyncio.sleep(0.5) - for selector in checkbox_selectors: - checkboxes = await page.query_selector_all(selector) + # Check if we've reached the form (email field is visible) + email_field = await page.query_selector('input[name*="email" i]') + if email_field and await email_field.is_visible(): + logger.info("[HOWOGE] Email field is visible - form is ready!") + break + + # Find and click any visible unchecked checkboxes + checkboxes = await page.query_selector_all('input[type="checkbox"]') + clicked_checkbox = False for checkbox in checkboxes: try: if await checkbox.is_visible() and not await checkbox.is_checked(): - await checkbox.scroll_into_view_if_needed() - await checkbox.click() - checkboxes_clicked += 1 - logger.info(f"[HOWOGE] Clicked checkbox") - await asyncio.sleep(0.3) + # Use JavaScript click to avoid viewport issues + await checkbox.evaluate("el => el.click()") + clicked_checkbox = True + logger.info(f"[HOWOGE] Clicked checkbox in step {step}") + await asyncio.sleep(0.5) except Exception as e: logger.debug(f"[HOWOGE] Checkbox click failed: {e}") - if checkboxes_clicked > 0: - logger.info(f"[HOWOGE] Clicked {checkboxes_clicked} checkboxes") - await asyncio.sleep(1) + if clicked_checkbox: + await asyncio.sleep(1) # Wait for page to update after checkbox - # Screenshot after clicking checkboxes - screenshot_path = DATA_DIR / f"howoge_after_checkboxes_{listing['id']}.png" + # Screenshot this step + screenshot_path = DATA_DIR / f"howoge_step{step}_{listing['id']}.png" await page.screenshot(path=str(screenshot_path), full_page=True) - logger.info(f"[HOWOGE] Saved after-checkboxes screenshot") - # Scroll back up to find the form fields - await page.evaluate("window.scrollTo(0, 0)") - await asyncio.sleep(0.5) + # Look for visible "Weiter" button and click it + weiter_btns = await page.query_selector_all('button:has-text("Weiter")') + weiter_clicked = False + for btn in weiter_btns: + try: + if await btn.is_visible(): + await btn.click() + weiter_clicked = True + logger.info(f"[HOWOGE] Clicked 'Weiter' button in step {step}") + await asyncio.sleep(2) + await page.wait_for_load_state("networkidle") + break + except Exception as e: + logger.debug(f"[HOWOGE] Weiter click failed: {e}") - # Fill in the contact form - # Look for name fields (Vorname, Nachname) - vorname_field = await page.query_selector('input[name*="vorname" i], input[name*="firstname" i], input[placeholder*="Vorname" i], input#vorname') - nachname_field = await page.query_selector('input[name*="nachname" i], input[name*="lastname" i], input[name*="surname" i], input[placeholder*="Nachname" i], input#nachname') - email_field = await page.query_selector('input[type="email"], input[name*="email" i], input[name*="mail" i]') + if not weiter_clicked and not clicked_checkbox: + logger.warning(f"[HOWOGE] No action possible in step {step}, breaking") + break + + # Now try to fill the form + logger.info("[HOWOGE] Attempting to fill form fields...") + + # Look for name fields - HOWOGE uses firstName/lastName + vorname_field = await page.query_selector('input[name*="firstName" i], input[name*="vorname" i]') + nachname_field = await page.query_selector('input[name*="lastName" i], input[name*="nachname" i]') + email_field = await page.query_selector('input[type="email"], input[name*="email" i]') form_filled = False - if vorname_field: - await vorname_field.scroll_into_view_if_needed() - await asyncio.sleep(0.2) + if vorname_field and await vorname_field.is_visible(): await vorname_field.fill(FORM_VORNAME) logger.info(f"[HOWOGE] Filled Vorname: {FORM_VORNAME}") form_filled = True + else: + logger.warning("[HOWOGE] Vorname field not found or not visible") - if nachname_field: - await nachname_field.scroll_into_view_if_needed() - await asyncio.sleep(0.2) + if nachname_field and await nachname_field.is_visible(): await nachname_field.fill(FORM_NACHNAME) logger.info(f"[HOWOGE] Filled Nachname: {FORM_NACHNAME}") form_filled = True + else: + logger.warning("[HOWOGE] Nachname field not found or not visible") - if email_field: - await email_field.scroll_into_view_if_needed() - await asyncio.sleep(0.2) + if email_field and await email_field.is_visible(): await email_field.fill(FORM_EMAIL) logger.info(f"[HOWOGE] Filled Email: {FORM_EMAIL}") form_filled = True + else: + logger.warning("[HOWOGE] Email field not found or not visible") # Also look for phone field phone_field = await page.query_selector('input[type="tel"], input[name*="telefon" i], input[name*="phone" i]') - if phone_field: - await phone_field.scroll_into_view_if_needed() - await asyncio.sleep(0.2) + if phone_field and await phone_field.is_visible(): await phone_field.fill(FORM_PHONE) logger.info(f"[HOWOGE] Filled Phone: {FORM_PHONE}") @@ -543,8 +552,8 @@ class ApplicationHandler: logger.info(f"[HOWOGE] Saved filled form screenshot to {screenshot_path2}") if form_filled: - # Look for submit button - submit_btn = await page.query_selector('button[type="submit"], input[type="submit"], button:has-text("Absenden"), button:has-text("Senden"), button:has-text("Anfrage")') + # Look for submit button - HOWOGE uses "Anfrage senden" + submit_btn = await page.query_selector('button:has-text("Anfrage senden"), button:has-text("Absenden"), button:has-text("Senden"), button[type="submit"]') if submit_btn and await submit_btn.is_visible(): logger.info("[HOWOGE] Found submit button, clicking...") await submit_btn.click() @@ -557,7 +566,7 @@ class ApplicationHandler: logger.info(f"[HOWOGE] Saved post-submit screenshot to {screenshot_path3}") content = await page.content() - if "erfolgreich" in content.lower() or "gesendet" in content.lower() or "danke" in content.lower(): + if "erfolgreich" in content.lower() or "gesendet" in content.lower() or "danke" in content.lower() or "bestätigung" in content.lower(): result["success"] = True result["message"] = "Application submitted successfully" logger.info("[HOWOGE] Success! Confirmation message detected") @@ -571,8 +580,8 @@ class ApplicationHandler: logger.warning("[HOWOGE] Could not find submit button") else: result["success"] = False - result["message"] = "Could not find form fields to fill" - logger.warning("[HOWOGE] No form fields found") + result["message"] = "Could not find form fields to fill after navigating steps" + logger.warning("[HOWOGE] No form fields found after multi-step navigation") else: result["message"] = "No application button found" logger.warning("[HOWOGE] Could not find 'Besichtigung vereinbaren' button")