Dieser Commit ist enthalten in:
Claude Project Manager
2025-08-01 23:50:28 +02:00
Commit 04585e95b6
290 geänderte Dateien mit 64086 neuen und 0 gelöschten Zeilen

Datei anzeigen

@ -0,0 +1,548 @@
"""
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)
}