""" Gmail Registrierung - Handhabt den Registrierungsprozess """ import logging import time import random from typing import Dict from playwright.sync_api import Page from social_networks.gmail import gmail_selectors as selectors from social_networks.gmail.gmail_ui_helper import GmailUIHelper logger = logging.getLogger("gmail_registration") class GmailRegistration: """ Handhabt den Gmail/Google Account Registrierungsprozess """ def __init__(self, page: Page, ui_helper: GmailUIHelper, screenshots_dir: str = None, save_screenshots: bool = True): """ Initialisiert die Registrierung """ self.page = page self.ui_helper = ui_helper self.screenshots_dir = screenshots_dir self.save_screenshots = save_screenshots def _click_next_button(self) -> bool: """ Versucht den Weiter-Button mit verschiedenen Selektoren zu klicken """ logger.info("Versuche Weiter-Button zu klicken") # Liste von Selektoren zum Ausprobieren selectors_to_try = [ ("span[jsname='V67aGc']:has-text('Weiter')", "parent_click"), # Der exakte Span mit jsname ("button:has(span.VfPpkd-vQzf8d:has-text('Weiter'))", "click"), # Button der den Span enthält ("button:has(div.VfPpkd-RLmnJb)", "click"), # Button mit dem Material Ripple div (selectors.NEXT_BUTTON, "click"), (selectors.NEXT_BUTTON_MATERIAL, "parent_click"), (selectors.NEXT_BUTTON_SPAN, "click"), ("button:has-text('Weiter')", "click"), ("button:has-text('Next')", "click") ] for selector, method in selectors_to_try: try: if method == "click": if self.ui_helper.wait_for_element(selector, timeout=2000): self.ui_helper.click_with_retry(selector) logger.info(f"Erfolgreich geklickt mit Selektor: {selector}") return True elif method == "parent_click": if self.ui_helper.wait_for_element(selector, timeout=2000): # Versuche verschiedene Parent-Ebenen for parent_level in ['..', '../..', '../../..']: try: self.page.locator(selector).locator(parent_level).click() logger.info(f"Erfolgreich Parent geklickt mit Selektor: {selector} und Level: {parent_level}") return True except: continue except Exception as e: logger.debug(f"Konnte nicht mit Selektor {selector} klicken: {e}") continue # Letzter Versuch mit Playwright's get_by_role try: self.page.get_by_role("button", name="Weiter").click() logger.info("Erfolgreich mit get_by_role geklickt") return True except: pass logger.error("Konnte Weiter-Button nicht finden/klicken") return False def start_registration_flow(self, account_data: Dict[str, str]) -> Dict[str, any]: """ Startet den Registrierungsflow """ try: logger.info("Starte Gmail Registrierungsflow") # Schritt 1: Name eingeben name_result = self._fill_name_form(account_data) if not name_result["success"]: return name_result # Schritt 2: Geburtsdatum und Geschlecht birthday_result = self._fill_birthday_gender(account_data) if not birthday_result["success"]: return birthday_result # Schritt 3: Gmail-Adresse wählen/erstellen gmail_result = self._create_gmail_address(account_data) if not gmail_result["success"]: return gmail_result # Schritt 4: Passwort festlegen password_result = self._set_password(account_data) if not password_result["success"]: return password_result # Schritt 5: Telefonnummer (optional/erforderlich) phone_result = self._handle_phone_verification(account_data) if not phone_result["success"]: return phone_result # Schritt 6: Recovery Email (optional) recovery_result = self._handle_recovery_email(account_data) if not recovery_result["success"]: return recovery_result # Schritt 7: Nutzungsbedingungen akzeptieren terms_result = self._accept_terms() if not terms_result["success"]: return terms_result return { "success": True, "username": gmail_result.get("username"), "email": gmail_result.get("email"), "message": "Registrierung erfolgreich abgeschlossen" } except Exception as e: logger.error(f"Fehler im Registrierungsflow: {e}") self.ui_helper.take_screenshot("registration_error") return { "success": False, "error": str(e), "message": f"Registrierung fehlgeschlagen: {str(e)}" } def _fill_name_form(self, account_data: Dict[str, str]) -> Dict[str, any]: """ Füllt das Namensformular aus """ try: logger.info("Fülle Namensformular aus") # Screenshot der aktuellen Seite self.ui_helper.take_screenshot("before_name_form_search") # Warte kurz, damit die Seite vollständig lädt time.sleep(2) # Debug: Aktuelle URL ausgeben current_url = self.page.url logger.info(f"Aktuelle URL: {current_url}") # Versuche Cookie-Banner zu schließen, falls vorhanden try: # Suche nach typischen Cookie-Akzeptieren-Buttons cookie_selectors = [ "button:has-text('Alle akzeptieren')", "button:has-text('Accept all')", "button:has-text('Akzeptieren')", "button:has-text('Accept')", "[aria-label='Alle akzeptieren']" ] for selector in cookie_selectors: try: if self.page.locator(selector).is_visible(timeout=1000): self.page.locator(selector).click() logger.info(f"Cookie-Banner geschlossen mit: {selector}") time.sleep(1) break except: continue except Exception as e: logger.debug(f"Kein Cookie-Banner gefunden oder Fehler: {e}") # Versuche verschiedene Selektoren für das Vorname-Feld first_name_selectors = [ selectors.FIRST_NAME_INPUT, "input[aria-label='Vorname']", "input[aria-label='First name']", "#firstName", "input[type='text'][autocomplete='given-name']" ] first_name_found = False for selector in first_name_selectors: if self.ui_helper.wait_for_element(selector, timeout=3000): first_name_found = True selectors.FIRST_NAME_INPUT = selector # Update für diesen Durchlauf logger.info(f"Vorname-Feld gefunden mit Selektor: {selector}") break if not first_name_found: # Screenshot bei Fehler self.ui_helper.take_screenshot("name_form_not_found_error") return { "success": False, "error": "Namensformular nicht gefunden", "message": "Registrierungsseite konnte nicht geladen werden" } # Vorname eingeben first_name = account_data.get("first_name", "") logger.info(f"Gebe Vorname ein: {first_name}") self.ui_helper.type_with_delay(selectors.FIRST_NAME_INPUT, first_name) time.sleep(random.uniform(0.5, 1)) # Nachname eingeben - versuche verschiedene Selektoren last_name_selectors = [ selectors.LAST_NAME_INPUT, "input[aria-label='Nachname']", "input[aria-label='Last name']", "#lastName", "input[type='text'][autocomplete='family-name']" ] last_name = account_data.get("last_name", "") logger.info(f"Gebe Nachname ein: {last_name}") for selector in last_name_selectors: try: if self.ui_helper.wait_for_element(selector, timeout=2000): self.ui_helper.type_with_delay(selector, last_name) logger.info(f"Nachname eingegeben mit Selektor: {selector}") break except: continue time.sleep(random.uniform(0.5, 1)) # Screenshot vor dem Weiter-Klick self.ui_helper.take_screenshot("name_form_filled") # Weiter Button klicken if not self._click_next_button(): return { "success": False, "error": "Konnte Weiter-Button nicht klicken", "message": "Navigation fehlgeschlagen" } self.ui_helper.wait_for_loading_to_finish() time.sleep(random.uniform(2, 3)) return { "success": True, "message": "Namensformular ausgefüllt" } except Exception as e: logger.error(f"Fehler beim Ausfüllen des Namensformulars: {e}") return { "success": False, "error": str(e) } def _fill_birthday_gender(self, account_data: Dict[str, str]) -> Dict[str, any]: """ Füllt Geburtsdatum und Geschlecht aus """ try: logger.info("Fülle Geburtsdatum und Geschlecht aus") # Warte auf Formular if not self.ui_helper.wait_for_element(selectors.BIRTHDAY_DAY, timeout=10000): logger.warning("Geburtsdatum-Formular nicht gefunden, überspringe...") return {"success": True} # Geburtsdatum ausfüllen birthday = account_data.get("birthday", "1990-01-15") year, month, day = birthday.split("-") # Tag eingeben logger.info(f"Gebe Geburtstag ein: {day}") self.ui_helper.type_with_delay(selectors.BIRTHDAY_DAY, day.lstrip("0")) time.sleep(random.uniform(0.3, 0.6)) # Monat auswählen logger.info(f"Wähle Geburtsmonat: {month}") month_value = str(int(month)) # Entferne führende Null self.ui_helper.select_dropdown_option(selectors.BIRTHDAY_MONTH, month_value) time.sleep(random.uniform(0.3, 0.6)) # Jahr eingeben logger.info(f"Gebe Geburtsjahr ein: {year}") self.ui_helper.type_with_delay(selectors.BIRTHDAY_YEAR, year) time.sleep(random.uniform(0.3, 0.6)) # Geschlecht auswählen gender = account_data.get("gender", "male").lower() gender_value = "1" if gender == "male" else "2" # 1=männlich, 2=weiblich logger.info(f"Wähle Geschlecht: {gender}") self.ui_helper.select_dropdown_option(selectors.GENDER_SELECT, gender_value) time.sleep(random.uniform(0.5, 1)) # Screenshot vor dem Weiter-Klick self.ui_helper.take_screenshot("birthday_gender_filled") # Weiter klicken logger.info("Klicke auf Weiter") self._click_next_button() self.ui_helper.wait_for_loading_to_finish() time.sleep(random.uniform(2, 3)) return { "success": True, "message": "Geburtsdatum und Geschlecht ausgefüllt" } except Exception as e: logger.error(f"Fehler beim Ausfüllen von Geburtsdatum/Geschlecht: {e}") return { "success": False, "error": str(e) } def _create_gmail_address(self, account_data: Dict[str, str]) -> Dict[str, any]: """ Erstellt die Gmail-Adresse """ try: logger.info("Erstelle Gmail-Adresse") # Warte auf Gmail-Erstellungsseite time.sleep(random.uniform(2, 3)) self.ui_helper.take_screenshot("gmail_creation_page") # Prüfe ob wir einen Benutzernamen eingeben können if self.ui_helper.wait_for_element(selectors.GMAIL_USERNAME_INPUT, timeout=10000): username = account_data.get("username", "") if not username: # Generiere einen Benutzernamen from social_networks.gmail.gmail_utils import GmailUtils utils = GmailUtils() username = utils.generate_gmail_username( account_data.get("first_name", ""), account_data.get("last_name", "") ) logger.info(f"Gebe Gmail-Benutzernamen ein: {username}") self.ui_helper.type_with_delay(selectors.GMAIL_USERNAME_INPUT, username) time.sleep(random.uniform(1, 2)) # Weiter klicken self.ui_helper.click_with_retry(selectors.NEXT_BUTTON) self.ui_helper.wait_for_loading_to_finish() time.sleep(random.uniform(2, 3)) # Prüfe auf Fehler (Benutzername bereits vergeben) if self.ui_helper.is_element_visible(selectors.ERROR_MESSAGE): error_text = self.ui_helper.get_element_text(selectors.ERROR_MESSAGE) logger.warning(f"Benutzername-Fehler: {error_text}") # TODO: Implementiere alternative Benutzernamen-Vorschläge return { "success": True, "username": username, "email": f"{username}@gmail.com" } return { "success": True, "message": "Gmail-Adresse erstellt" } except Exception as e: logger.error(f"Fehler beim Erstellen der Gmail-Adresse: {e}") return { "success": False, "error": str(e) } def _set_password(self, account_data: Dict[str, str]) -> Dict[str, any]: """ Setzt das Passwort """ try: logger.info("Setze Passwort") # Warte auf Passwort-Formular if not self.ui_helper.wait_for_element(selectors.PASSWORD_INPUT, timeout=10000): return { "success": False, "error": "Passwort-Formular nicht gefunden" } password = account_data.get("password", "") if not password: # Generiere ein sicheres Passwort from social_networks.gmail.gmail_utils import GmailUtils utils = GmailUtils() password = utils.generate_secure_password() # Passwort eingeben logger.info("Gebe Passwort ein") self.ui_helper.type_with_delay(selectors.PASSWORD_INPUT, password) time.sleep(random.uniform(0.5, 1)) # Passwort bestätigen if self.ui_helper.wait_for_element(selectors.PASSWORD_CONFIRM_INPUT, timeout=5000): logger.info("Bestätige Passwort") self.ui_helper.type_with_delay(selectors.PASSWORD_CONFIRM_INPUT, password) time.sleep(random.uniform(0.5, 1)) # Screenshot vor dem Weiter-Klick self.ui_helper.take_screenshot("password_set") # Weiter klicken self.ui_helper.click_with_retry(selectors.NEXT_BUTTON) self.ui_helper.wait_for_loading_to_finish() time.sleep(random.uniform(2, 3)) return { "success": True, "message": "Passwort gesetzt" } except Exception as e: logger.error(f"Fehler beim Setzen des Passworts: {e}") return { "success": False, "error": str(e) } def _handle_phone_verification(self, account_data: Dict[str, str]) -> Dict[str, any]: """ Handhabt die Telefonnummer-Verifizierung (falls erforderlich) """ try: logger.info("Prüfe auf Telefonnummer-Verifizierung") # Prüfe ob Telefonnummer erforderlich ist if not self.ui_helper.wait_for_element(selectors.PHONE_INPUT, timeout=5000): logger.info("Telefonnummer nicht erforderlich") return {"success": True} # Wenn Telefonnummer optional ist, überspringe if self.ui_helper.is_element_visible(selectors.SKIP_BUTTON): logger.info("Überspringe Telefonnummer") self.ui_helper.click_with_retry(selectors.SKIP_BUTTON) time.sleep(random.uniform(2, 3)) return {"success": True} # Telefonnummer eingeben falls vorhanden phone = account_data.get("phone", "") if phone: logger.info(f"Gebe Telefonnummer ein: {phone}") self.ui_helper.type_with_delay(selectors.PHONE_INPUT, phone) time.sleep(random.uniform(1, 2)) # Weiter klicken self.ui_helper.click_with_retry(selectors.NEXT_BUTTON) self.ui_helper.wait_for_loading_to_finish() # TODO: SMS-Verifizierung implementieren logger.warning("SMS-Verifizierung noch nicht implementiert") return { "success": True, "message": "Telefonnummer-Schritt abgeschlossen" } except Exception as e: logger.error(f"Fehler bei der Telefonnummer-Verifizierung: {e}") return { "success": False, "error": str(e) } def _handle_recovery_email(self, account_data: Dict[str, str]) -> Dict[str, any]: """ Handhabt die Recovery-Email (optional) """ try: logger.info("Prüfe auf Recovery-Email") # Prüfe ob Recovery-Email Feld vorhanden ist if not self.ui_helper.wait_for_element(selectors.RECOVERY_EMAIL_INPUT, timeout=5000): logger.info("Recovery-Email nicht vorhanden") return {"success": True} # Überspringe wenn möglich if self.ui_helper.is_element_visible(selectors.SKIP_BUTTON): logger.info("Überspringe Recovery-Email") self.ui_helper.click_with_retry(selectors.SKIP_BUTTON) time.sleep(random.uniform(2, 3)) else: # Recovery-Email eingeben falls vorhanden recovery_email = account_data.get("recovery_email", "") if recovery_email: logger.info(f"Gebe Recovery-Email ein: {recovery_email}") self.ui_helper.type_with_delay(selectors.RECOVERY_EMAIL_INPUT, recovery_email) time.sleep(random.uniform(1, 2)) # Weiter klicken self.ui_helper.click_with_retry(selectors.NEXT_BUTTON) self.ui_helper.wait_for_loading_to_finish() return { "success": True, "message": "Recovery-Email Schritt abgeschlossen" } except Exception as e: logger.error(f"Fehler bei der Recovery-Email: {e}") return { "success": False, "error": str(e) } def _accept_terms(self) -> Dict[str, any]: """ Akzeptiert die Nutzungsbedingungen """ try: logger.info("Akzeptiere Nutzungsbedingungen") # Warte auf Nutzungsbedingungen time.sleep(random.uniform(2, 3)) self.ui_helper.take_screenshot("terms_page") # Scrolle nach unten (simuliere Lesen) self.page.evaluate("window.scrollTo(0, document.body.scrollHeight)") time.sleep(random.uniform(2, 4)) # Akzeptiere Button suchen und klicken if self.ui_helper.wait_for_element(selectors.AGREE_BUTTON, timeout=10000): logger.info("Klicke auf 'Ich stimme zu'") self.ui_helper.click_with_retry(selectors.AGREE_BUTTON) self.ui_helper.wait_for_loading_to_finish() time.sleep(random.uniform(3, 5)) # Screenshot nach Registrierung self.ui_helper.take_screenshot("registration_complete") return { "success": True, "message": "Nutzungsbedingungen akzeptiert" } except Exception as e: logger.error(f"Fehler beim Akzeptieren der Nutzungsbedingungen: {e}") return { "success": False, "error": str(e) }