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

Datei anzeigen

@ -0,0 +1,336 @@
"""
Gmail Automatisierung - Hauptklasse
"""
import logging
import time
import random
from typing import Dict, Optional, Tuple, Any
from playwright.sync_api import Page
from social_networks.base_automation import BaseAutomation
from social_networks.gmail import gmail_selectors as selectors
from social_networks.gmail.gmail_ui_helper import GmailUIHelper
from social_networks.gmail.gmail_registration import GmailRegistration
from social_networks.gmail.gmail_login import GmailLogin
from social_networks.gmail.gmail_verification import GmailVerification
from social_networks.gmail.gmail_utils import GmailUtils
logger = logging.getLogger("gmail_automation")
class GmailAutomation(BaseAutomation):
"""
Gmail/Google Account-spezifische Automatisierung
"""
def __init__(self, **kwargs):
"""
Initialisiert die Gmail-Automatisierung
"""
super().__init__(**kwargs)
self.platform_name = "gmail"
self.ui_helper = None
self.registration = None
self.login_helper = None
self.verification = None
self.utils = None
def _initialize_helpers(self, page: Page):
"""
Initialisiert die Hilfsklassen
"""
self.ui_helper = GmailUIHelper(page, self.screenshots_dir, self.save_screenshots)
self.registration = GmailRegistration(page, self.ui_helper, self.screenshots_dir, self.save_screenshots)
self.login_helper = GmailLogin(page, self.ui_helper, self.screenshots_dir, self.save_screenshots)
self.verification = GmailVerification(page, self.ui_helper, self.email_handler, self.screenshots_dir, self.save_screenshots)
self.utils = GmailUtils()
def register_account(self, full_name: str, age: int, registration_method: str = "email",
phone_number: str = None, **kwargs) -> Dict[str, any]:
"""
Erstellt einen neuen Gmail/Google Account
Args:
full_name: Vollständiger Name für den Account
age: Alter des Benutzers
registration_method: Registrierungsmethode (nur "email" für Gmail)
phone_number: Telefonnummer (optional, aber oft erforderlich)
**kwargs: Weitere optionale Parameter
"""
try:
logger.info(f"[GMAIL AUTOMATION] register_account aufgerufen")
logger.info(f"[GMAIL AUTOMATION] full_name: {full_name}")
logger.info(f"[GMAIL AUTOMATION] age: {age}")
logger.info(f"[GMAIL AUTOMATION] phone_number: {phone_number}")
logger.info(f"[GMAIL AUTOMATION] kwargs: {kwargs}")
# Erstelle account_data aus den Parametern
account_data = {
"full_name": full_name,
"first_name": kwargs.get("first_name", full_name.split()[0] if full_name else ""),
"last_name": kwargs.get("last_name", full_name.split()[-1] if full_name and len(full_name.split()) > 1 else ""),
"age": age,
"birthday": kwargs.get("birthday", self._generate_birthday(age)),
"gender": kwargs.get("gender", random.choice(["male", "female"])),
"username": kwargs.get("username", ""),
"password": kwargs.get("password", ""),
"phone": phone_number,
"recovery_email": kwargs.get("recovery_email", "")
}
# Initialisiere Browser, falls noch nicht geschehen
logger.info(f"[GMAIL AUTOMATION] Prüfe Browser-Status...")
logger.info(f"[GMAIL AUTOMATION] self.browser: {self.browser}")
if self.browser:
logger.info(f"[GMAIL AUTOMATION] hasattr(self.browser, 'page'): {hasattr(self.browser, 'page')}")
if not self.browser or not hasattr(self.browser, 'page'):
logger.info(f"[GMAIL AUTOMATION] Browser muss initialisiert werden")
if not self._initialize_browser():
logger.error(f"[GMAIL AUTOMATION] Browser-Initialisierung fehlgeschlagen!")
return {
"success": False,
"error": "Browser konnte nicht initialisiert werden",
"message": "Browser-Initialisierung fehlgeschlagen"
}
logger.info(f"[GMAIL AUTOMATION] Browser erfolgreich initialisiert")
# Page-Objekt holen
page = self.browser.page
self._initialize_helpers(page)
# Direkt zur Registrierungs-URL navigieren
logger.info("Navigiere zur Gmail Registrierungsseite")
page.goto(selectors.REGISTRATION_URL, wait_until="networkidle")
# Warte auf vollständiges Laden der Seite
logger.info("Warte auf vollständiges Laden der Seite...")
time.sleep(random.uniform(5, 7))
# Prüfe ob wir auf der richtigen Seite sind
current_url = page.url
logger.info(f"Aktuelle URL nach Navigation: {current_url}")
# Screenshot der Startseite
self.ui_helper.take_screenshot("gmail_start_page")
# Finde und klicke auf "Konto erstellen" Button (Dropdown)
try:
# Warte bis die Seite interaktiv ist
logger.info("Warte auf vollständiges Laden der Gmail Workspace Seite...")
page.wait_for_load_state("networkidle")
time.sleep(2)
# Debug: Alle sichtbaren Links/Buttons mit "Konto" ausgeben
try:
konto_elements = page.locator("*:has-text('Konto')").all()
logger.info(f"Gefundene Elemente mit 'Konto': {len(konto_elements)}")
for i, elem in enumerate(konto_elements[:5]): # Erste 5 Elemente
try:
tag = elem.evaluate("el => el.tagName")
text = elem.inner_text()
logger.info(f"Element {i}: <{tag}> - {text}")
except:
pass
except Exception as e:
logger.debug(f"Debug-Ausgabe fehlgeschlagen: {e}")
# Schritt 1: Klicke auf "Konto erstellen" Dropdown
create_account_selectors = [
"[aria-label='Konto erstellen']",
"div[aria-label='Konto erstellen']",
"[data-g-action='create an account']",
"button:has-text('Konto erstellen')",
"a:has-text('Konto erstellen')",
"*:has-text('Konto erstellen')", # Beliebiges Element mit dem Text
"[slot='label']:has-text('Konto erstellen')" # Spezifisch für Web Components
]
clicked_dropdown = False
for selector in create_account_selectors:
try:
elements = page.locator(selector).all()
logger.info(f"Selector {selector}: {len(elements)} Elemente gefunden")
if page.locator(selector).is_visible(timeout=3000):
# Versuche normale Klick-Methode
try:
page.locator(selector).first.click()
logger.info(f"Dropdown 'Konto erstellen' geklickt mit: {selector}")
clicked_dropdown = True
break
except:
# Versuche JavaScript-Klick als Fallback
page.locator(selector).first.evaluate("el => el.click()")
logger.info(f"Dropdown 'Konto erstellen' via JS geklickt mit: {selector}")
clicked_dropdown = True
break
except Exception as e:
logger.debug(f"Fehler mit Selector {selector}: {e}")
continue
if not clicked_dropdown:
logger.error("Konnte 'Konto erstellen' Dropdown nicht finden")
self.ui_helper.take_screenshot("konto_erstellen_not_found")
return {
"success": False,
"error": "Konto erstellen Dropdown nicht gefunden",
"message": "Navigation fehlgeschlagen"
}
# Kurz warten bis Dropdown geöffnet ist
time.sleep(1)
# Schritt 2: Klicke auf "Für die private Nutzung"
private_use_selectors = [
"a[aria-label='Gmail - Für die private Nutzung']",
"a:has-text('Für die private Nutzung')",
"[data-g-action='für die private nutzung']",
"span:has-text('Für die private Nutzung')"
]
clicked_private = False
for selector in private_use_selectors:
try:
if page.locator(selector).is_visible(timeout=2000):
page.locator(selector).click()
logger.info(f"'Für die private Nutzung' geklickt mit: {selector}")
clicked_private = True
break
except:
continue
if not clicked_private:
logger.error("Konnte 'Für die private Nutzung' nicht finden")
self.ui_helper.take_screenshot("private_nutzung_not_found")
return {
"success": False,
"error": "Für die private Nutzung Option nicht gefunden",
"message": "Navigation fehlgeschlagen"
}
# Warte auf die Registrierungsseite
time.sleep(random.uniform(3, 5))
except Exception as e:
logger.error(f"Fehler beim Navigieren zur Registrierung: {e}")
# Screenshot der Registrierungsseite
self.ui_helper.take_screenshot("gmail_registration_page")
# Registrierungsprozess starten
registration_result = self.registration.start_registration_flow(account_data)
if not registration_result["success"]:
return registration_result
# Nach erfolgreicher Registrierung
logger.info("Gmail Account-Registrierung erfolgreich abgeschlossen")
return {
"success": True,
"username": registration_result.get("username"),
"password": account_data.get("password"),
"email": registration_result.get("email"),
"phone": account_data.get("phone"),
"recovery_email": account_data.get("recovery_email"),
"message": "Account erfolgreich erstellt"
}
except Exception as e:
logger.error(f"Fehler bei der Gmail-Registrierung: {str(e)}")
return {
"success": False,
"error": str(e),
"message": f"Registrierung fehlgeschlagen: {str(e)}"
}
finally:
self._close_browser()
def login(self, username: str, password: str) -> Dict[str, any]:
"""
Meldet sich bei einem bestehenden Gmail/Google Account an
"""
try:
logger.info(f"Starte Gmail Login für {username}")
# Initialisiere Browser, falls noch nicht geschehen
if not self.browser or not hasattr(self.browser, 'page'):
if not self._initialize_browser():
return {
"success": False,
"error": "Browser konnte nicht initialisiert werden",
"message": "Browser-Initialisierung fehlgeschlagen"
}
# Page-Objekt holen
page = self.browser.page
self._initialize_helpers(page)
# Login durchführen
return self.login_helper.login(username, password)
except Exception as e:
logger.error(f"Fehler beim Gmail Login: {str(e)}")
return {
"success": False,
"error": str(e),
"message": f"Login fehlgeschlagen: {str(e)}"
}
finally:
self._close_browser()
def get_account_info(self) -> Dict[str, any]:
"""
Ruft Informationen über den aktuellen Account ab
"""
# TODO: Implementierung
return {
"success": False,
"message": "Noch nicht implementiert"
}
def logout(self) -> bool:
"""
Meldet sich vom aktuellen Account ab
"""
# TODO: Implementierung
return False
def login_account(self, username_or_email: str, password: str, **kwargs) -> Dict[str, Any]:
"""
Meldet sich bei einem bestehenden Gmail Account an.
Implementiert die abstrakte Methode aus BaseAutomation.
"""
return self.login(username_or_email, password)
def verify_account(self, verification_code: str, **kwargs) -> Dict[str, Any]:
"""
Verifiziert einen Gmail Account mit einem Bestätigungscode.
Implementiert die abstrakte Methode aus BaseAutomation.
"""
try:
if self.verification:
return self.verification.verify_with_code(verification_code)
else:
return {
"success": False,
"error": "Verification helper nicht initialisiert",
"message": "Verifizierung kann nicht durchgeführt werden"
}
except Exception as e:
return {
"success": False,
"error": str(e),
"message": f"Verifizierung fehlgeschlagen: {str(e)}"
}
def _generate_birthday(self, age: int) -> str:
"""
Generiert ein Geburtsdatum basierend auf dem Alter
"""
from datetime import datetime, timedelta
today = datetime.now()
birth_year = today.year - age
# Zufälliger Tag im Jahr
random_days = random.randint(0, 364)
birthday = datetime(birth_year, 1, 1) + timedelta(days=random_days)
return birthday.strftime("%Y-%m-%d")

Datei anzeigen

@ -0,0 +1,157 @@
"""
Gmail Login - Handhabt den Login-Prozess
"""
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_login")
class GmailLogin:
"""
Handhabt den Gmail/Google Account Login-Prozess
"""
def __init__(self, page: Page, ui_helper: GmailUIHelper, screenshots_dir: str = None, save_screenshots: bool = True):
"""
Initialisiert den Login Handler
"""
self.page = page
self.ui_helper = ui_helper
self.screenshots_dir = screenshots_dir
self.save_screenshots = save_screenshots
def login(self, username: str, password: str) -> Dict[str, any]:
"""
Führt den Login durch
"""
try:
logger.info(f"Starte Gmail Login für {username}")
# Navigiere zur Login-Seite
self.page.goto(selectors.LOGIN_URL, wait_until="domcontentloaded")
time.sleep(random.uniform(2, 3))
self.ui_helper.take_screenshot("login_page")
# Email eingeben
if self.ui_helper.wait_for_element(selectors.LOGIN_EMAIL_INPUT, timeout=10000):
logger.info("Gebe Email-Adresse ein")
# Füge @gmail.com hinzu falls nicht vorhanden
email = username if "@" in username else f"{username}@gmail.com"
self.ui_helper.type_with_delay(selectors.LOGIN_EMAIL_INPUT, email)
time.sleep(random.uniform(0.5, 1))
# Screenshot vor dem Weiter-Klick
self.ui_helper.take_screenshot("email_entered")
# Weiter klicken
logger.info("Klicke auf Weiter")
self.ui_helper.click_with_retry(selectors.LOGIN_NEXT_BUTTON)
self.ui_helper.wait_for_loading_to_finish()
time.sleep(random.uniform(2, 3))
# Passwort eingeben
if self.ui_helper.wait_for_element(selectors.LOGIN_PASSWORD_INPUT, timeout=10000):
logger.info("Gebe Passwort ein")
self.ui_helper.type_with_delay(selectors.LOGIN_PASSWORD_INPUT, password)
time.sleep(random.uniform(0.5, 1))
# Screenshot vor dem Login
self.ui_helper.take_screenshot("password_entered")
# Login Button klicken
logger.info("Klicke auf Weiter")
self.ui_helper.click_with_retry(selectors.LOGIN_NEXT_BUTTON)
# Warte auf Navigation
self.ui_helper.wait_for_navigation()
time.sleep(random.uniform(3, 5))
# Prüfe ob Login erfolgreich war
if self._check_login_success():
logger.info("Login erfolgreich")
self.ui_helper.take_screenshot("login_success")
return {
"success": True,
"message": "Login erfolgreich"
}
else:
error_msg = self._get_error_message()
logger.error(f"Login fehlgeschlagen: {error_msg}")
self.ui_helper.take_screenshot("login_failed")
return {
"success": False,
"error": error_msg,
"message": f"Login fehlgeschlagen: {error_msg}"
}
except Exception as e:
logger.error(f"Fehler beim Login: {e}")
self.ui_helper.take_screenshot("login_error")
return {
"success": False,
"error": str(e),
"message": f"Login fehlgeschlagen: {str(e)}"
}
def _check_login_success(self) -> bool:
"""
Prüft ob der Login erfolgreich war
"""
try:
# Prüfe ob wir auf einer Google-Seite sind
current_url = self.page.url
success_indicators = [
"myaccount.google.com",
"mail.google.com",
"youtube.com",
"google.com/webhp",
"accounts.google.com/b/"
]
for indicator in success_indicators:
if indicator in current_url:
return True
# Prüfe ob Login-Formular noch sichtbar ist
if self.ui_helper.is_element_visible(selectors.LOGIN_EMAIL_INPUT):
return False
# Prüfe auf Fehlermeldung
if self.ui_helper.is_element_visible(selectors.ERROR_MESSAGE):
return False
return True
except Exception as e:
logger.warning(f"Fehler bei der Login-Prüfung: {e}")
return False
def _get_error_message(self) -> str:
"""
Holt die Fehlermeldung falls vorhanden
"""
try:
# Prüfe verschiedene Fehlermeldungs-Selektoren
error_selectors = [
selectors.ERROR_MESSAGE,
selectors.ERROR_MESSAGE_ALT,
selectors.FORM_ERROR
]
for selector in error_selectors:
if self.ui_helper.is_element_visible(selector):
error_text = self.ui_helper.get_element_text(selector)
if error_text:
return error_text
return "Login fehlgeschlagen"
except:
return "Unbekannter Fehler"

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)
}

Datei anzeigen

@ -0,0 +1,59 @@
"""
Gmail/Google Account UI Selektoren und URLs
"""
# URLs
BASE_URL = "https://accounts.google.com/"
REGISTRATION_URL = "https://workspace.google.com/intl/de/gmail/"
LOGIN_URL = "https://accounts.google.com/ServiceLogin"
# Name Eingabe (Erster Schritt)
FIRST_NAME_INPUT = "input[name='firstName']"
LAST_NAME_INPUT = "input[name='lastName']"
NEXT_BUTTON = "button[jsname='LgbsSe']"
NEXT_BUTTON_SPAN = "span:has-text('Weiter')"
NEXT_BUTTON_MATERIAL = "div.VfPpkd-RLmnJb" # Material Design Weiter-Button
# Geburtsdatum und Geschlecht
BIRTHDAY_DAY = "input[name='day']"
BIRTHDAY_MONTH = "select[name='month']"
BIRTHDAY_YEAR = "input[name='year']"
GENDER_SELECT = "select[name='gender']"
# Gmail-Adresse erstellen
CREATE_GMAIL_RADIO = "div[data-value='createAccount']"
GMAIL_USERNAME_INPUT = "input[name='Username']"
# Passwort
PASSWORD_INPUT = "input[name='Passwd']"
PASSWORD_CONFIRM_INPUT = "input[name='PasswdAgain']"
# Telefonnummer Verifizierung
PHONE_INPUT = "input[id='phoneNumberId']"
PHONE_COUNTRY_SELECT = "select[data-id='countryList']"
# SMS Verifizierung
SMS_CODE_INPUT = "input[name='code']"
VERIFY_BUTTON = "button:has-text('Bestätigen')"
# Recovery Email (Optional)
RECOVERY_EMAIL_INPUT = "input[name='recoveryEmail']"
SKIP_BUTTON = "button:has-text('Überspringen')"
# Nutzungsbedingungen
AGREE_BUTTON = "button:has-text('Ich stimme zu')"
TERMS_CHECKBOX = "input[type='checkbox']"
# Fehler- und Erfolgsmeldungen
ERROR_MESSAGE = "div[jsname='B34EJ'] span"
ERROR_MESSAGE_ALT = "div.LXRPh"
CAPTCHA_CONTAINER = "div.aCsJod"
# Login Seite
LOGIN_EMAIL_INPUT = "input[type='email']"
LOGIN_PASSWORD_INPUT = "input[type='password'][name='password']"
LOGIN_NEXT_BUTTON = "button:has-text('Weiter')"
# Allgemeine Elemente
LOADING_SPINNER = "div.ANuIbb"
FORM_ERROR = "div[jsname='B34EJ']"

Datei anzeigen

@ -0,0 +1,151 @@
"""
Gmail UI Helper - Hilfsfunktionen für UI-Interaktionen
"""
import logging
import time
import random
import os
from typing import Optional
from playwright.sync_api import Page, ElementHandle
logger = logging.getLogger("gmail_ui_helper")
class GmailUIHelper:
"""
Hilfsklasse für Gmail UI-Interaktionen
"""
def __init__(self, page: Page, screenshots_dir: str = None, save_screenshots: bool = True):
"""
Initialisiert den UI Helper
"""
self.page = page
self.screenshots_dir = screenshots_dir or "logs/screenshots"
self.save_screenshots = save_screenshots
# Screenshot-Verzeichnis erstellen falls nötig
if self.save_screenshots and not os.path.exists(self.screenshots_dir):
os.makedirs(self.screenshots_dir)
def take_screenshot(self, name: str) -> Optional[str]:
"""
Erstellt einen Screenshot
"""
if not self.save_screenshots:
return None
try:
timestamp = int(time.time())
filename = f"{name}_{timestamp}.png"
filepath = os.path.join(self.screenshots_dir, filename)
self.page.screenshot(path=filepath)
logger.debug(f"Screenshot gespeichert: {filepath}")
return filepath
except Exception as e:
logger.warning(f"Fehler beim Erstellen des Screenshots: {e}")
return None
def wait_for_element(self, selector: str, timeout: int = 30000) -> bool:
"""
Wartet auf ein Element
"""
try:
self.page.wait_for_selector(selector, timeout=timeout)
return True
except Exception as e:
logger.error(f"Element {selector} nicht gefunden nach {timeout}ms")
return False
def type_with_delay(self, selector: str, text: str, delay_min: float = 0.05, delay_max: float = 0.15):
"""
Tippt Text mit menschenähnlicher Verzögerung
"""
try:
element = self.page.locator(selector)
element.click()
for char in text:
element.type(char)
time.sleep(random.uniform(delay_min, delay_max))
except Exception as e:
logger.error(f"Fehler beim Tippen in {selector}: {e}")
raise
def click_with_retry(self, selector: str, max_attempts: int = 3) -> bool:
"""
Klickt auf ein Element mit Wiederholungsversuchen
"""
for attempt in range(max_attempts):
try:
self.page.click(selector)
return True
except Exception as e:
logger.warning(f"Klick-Versuch {attempt + 1} fehlgeschlagen: {e}")
if attempt < max_attempts - 1:
time.sleep(random.uniform(1, 2))
return False
def scroll_to_element(self, selector: str):
"""
Scrollt zu einem Element
"""
try:
self.page.locator(selector).scroll_into_view_if_needed()
time.sleep(random.uniform(0.5, 1))
except Exception as e:
logger.warning(f"Fehler beim Scrollen zu {selector}: {e}")
def is_element_visible(self, selector: str) -> bool:
"""
Prüft ob ein Element sichtbar ist
"""
try:
return self.page.locator(selector).is_visible()
except:
return False
def get_element_text(self, selector: str) -> Optional[str]:
"""
Holt den Text eines Elements
"""
try:
return self.page.locator(selector).text_content()
except Exception as e:
logger.warning(f"Fehler beim Lesen des Texts von {selector}: {e}")
return None
def select_dropdown_option(self, selector: str, value: str):
"""
Wählt eine Option aus einem Dropdown
"""
try:
self.page.select_option(selector, value)
time.sleep(random.uniform(0.3, 0.6))
except Exception as e:
logger.error(f"Fehler beim Auswählen von {value} in {selector}: {e}")
raise
def wait_for_navigation(self, timeout: int = 30000):
"""
Wartet auf Navigation
"""
try:
self.page.wait_for_load_state("networkidle", timeout=timeout)
except Exception as e:
logger.warning(f"Navigation-Timeout nach {timeout}ms: {e}")
def wait_for_loading_to_finish(self):
"""
Wartet bis Ladeanimation verschwunden ist
"""
try:
# Warte bis der Loading Spinner nicht mehr sichtbar ist
from social_networks.gmail import gmail_selectors as selectors
if self.is_element_visible(selectors.LOADING_SPINNER):
self.page.wait_for_selector(selectors.LOADING_SPINNER, state="hidden", timeout=10000)
time.sleep(random.uniform(0.5, 1))
except:
pass

Datei anzeigen

@ -0,0 +1,122 @@
"""
Gmail Utils - Utility-Funktionen für Gmail
"""
import logging
import random
import string
from typing import Optional
logger = logging.getLogger("gmail_utils")
class GmailUtils:
"""
Utility-Funktionen für Gmail/Google Accounts
"""
@staticmethod
def generate_gmail_username(first_name: str, last_name: str) -> str:
"""
Generiert einen Gmail-kompatiblen Benutzernamen
"""
# Basis aus Vor- und Nachname
first_clean = ''.join(c.lower() for c in first_name if c.isalnum())
last_clean = ''.join(c.lower() for c in last_name if c.isalnum())
# Verschiedene Varianten
variants = [
f"{first_clean}{last_clean}",
f"{first_clean}.{last_clean}",
f"{last_clean}{first_clean}",
f"{first_clean[0]}{last_clean}",
f"{first_clean}{last_clean[0]}"
]
# Wähle eine zufällige Variante
base = random.choice(variants)
# Füge zufällige Zahlen hinzu
random_suffix = ''.join(random.choices(string.digits, k=random.randint(2, 4)))
return f"{base}{random_suffix}"
@staticmethod
def generate_secure_password(length: int = 16) -> str:
"""
Generiert ein sicheres Passwort für Google-Anforderungen
- Mindestens 8 Zeichen
- Mischung aus Buchstaben, Zahlen und Symbolen
"""
# Stelle sicher dass alle Zeichentypen enthalten sind
password_chars = []
# Mindestens 2 Kleinbuchstaben
password_chars.extend(random.choices(string.ascii_lowercase, k=2))
# Mindestens 2 Großbuchstaben
password_chars.extend(random.choices(string.ascii_uppercase, k=2))
# Mindestens 2 Zahlen
password_chars.extend(random.choices(string.digits, k=2))
# Mindestens 2 Sonderzeichen
special_chars = "!@#$%^&*"
password_chars.extend(random.choices(special_chars, k=2))
# Fülle mit zufälligen Zeichen auf
remaining_length = length - len(password_chars)
all_chars = string.ascii_letters + string.digits + special_chars
password_chars.extend(random.choices(all_chars, k=remaining_length))
# Mische die Zeichen
random.shuffle(password_chars)
return ''.join(password_chars)
@staticmethod
def is_valid_gmail_address(email: str) -> bool:
"""
Prüft ob eine Gmail-Adresse gültig ist
"""
if not email.endswith("@gmail.com"):
return False
username = email.split("@")[0]
# Gmail-Regeln:
# - 6-30 Zeichen
# - Buchstaben, Zahlen und Punkte
# - Muss mit Buchstabe oder Zahl beginnen
# - Kein Punkt am Anfang oder Ende
# - Keine aufeinanderfolgenden Punkte
if len(username) < 6 or len(username) > 30:
return False
if not username[0].isalnum() or not username[-1].isalnum():
return False
if ".." in username:
return False
# Prüfe erlaubte Zeichen
for char in username:
if not (char.isalnum() or char == "."):
return False
return True
@staticmethod
def format_phone_for_google(phone: str, country_code: str = "+1") -> str:
"""
Formatiert eine Telefonnummer für Google
"""
# Entferne alle nicht-numerischen Zeichen
phone_digits = ''.join(c for c in phone if c.isdigit())
# Wenn die Nummer bereits mit Ländercode beginnt
if phone.startswith("+"):
return phone
# Füge Ländercode hinzu
return f"{country_code}{phone_digits}"

Datei anzeigen

@ -0,0 +1,230 @@
"""
Gmail Verification - Handhabt die Verifizierungsprozesse
"""
import logging
import time
import random
from typing import Dict, Optional
from playwright.sync_api import Page
from social_networks.gmail import gmail_selectors as selectors
from social_networks.gmail.gmail_ui_helper import GmailUIHelper
from utils.email_handler import EmailHandler
logger = logging.getLogger("gmail_verification")
class GmailVerification:
"""
Handhabt die Gmail/Google Account Verifizierung
"""
def __init__(self, page: Page, ui_helper: GmailUIHelper, email_handler: EmailHandler = None,
screenshots_dir: str = None, save_screenshots: bool = True):
"""
Initialisiert den Verification Handler
"""
self.page = page
self.ui_helper = ui_helper
self.email_handler = email_handler
self.screenshots_dir = screenshots_dir
self.save_screenshots = save_screenshots
def handle_phone_verification(self, account_data: Dict[str, str]) -> Dict[str, any]:
"""
Handhabt die Telefonnummer-Verifizierung
"""
try:
logger.info("Starte Telefon-Verifizierung")
# Warte auf Telefonnummer-Eingabefeld
if not self.ui_helper.wait_for_element(selectors.PHONE_INPUT, timeout=10000):
logger.info("Telefonnummer-Eingabefeld nicht gefunden")
return {
"success": True,
"message": "Keine Telefon-Verifizierung erforderlich"
}
self.ui_helper.take_screenshot("phone_verification_page")
# Telefonnummer eingeben
phone = account_data.get("phone", "")
if not phone:
logger.warning("Keine Telefonnummer vorhanden, überspringe wenn möglich")
# Versuche zu überspringen
if self.ui_helper.is_element_visible(selectors.SKIP_BUTTON):
self.ui_helper.click_with_retry(selectors.SKIP_BUTTON)
time.sleep(random.uniform(2, 3))
return {"success": True}
else:
return {
"success": False,
"error": "Telefonnummer erforderlich aber nicht vorhanden",
"message": "Telefonnummer wird benötigt"
}
logger.info(f"Gebe Telefonnummer ein: {phone}")
# Telefonnummer eingeben
self.ui_helper.type_with_delay(selectors.PHONE_INPUT, phone)
time.sleep(random.uniform(1, 2))
# Screenshot vor dem Absenden
self.ui_helper.take_screenshot("phone_entered")
# Absenden
if self.ui_helper.wait_for_element(selectors.NEXT_BUTTON, timeout=5000):
logger.info("Sende Telefonnummer ab")
self.ui_helper.click_with_retry(selectors.NEXT_BUTTON)
self.ui_helper.wait_for_loading_to_finish()
time.sleep(random.uniform(3, 5))
# Warte auf SMS-Code Eingabefeld
if self.ui_helper.wait_for_element(selectors.SMS_CODE_INPUT, timeout=15000):
logger.info("SMS-Code Eingabefeld gefunden")
self.ui_helper.take_screenshot("sms_code_page")
# Hier würde normalerweise der SMS-Code abgerufen werden
sms_code = self._get_sms_code(phone)
if not sms_code:
logger.error("Kein SMS-Code erhalten")
return {
"success": False,
"error": "Kein SMS-Code erhalten",
"message": "SMS-Verifizierung fehlgeschlagen"
}
# SMS-Code eingeben
logger.info(f"Gebe SMS-Code ein: {sms_code}")
self.ui_helper.type_with_delay(selectors.SMS_CODE_INPUT, sms_code)
time.sleep(random.uniform(1, 2))
# Code bestätigen
if self.ui_helper.wait_for_element(selectors.VERIFY_BUTTON, timeout=5000):
logger.info("Bestätige SMS-Code")
self.ui_helper.click_with_retry(selectors.VERIFY_BUTTON)
else:
# Versuche alternativen Button
self.ui_helper.click_with_retry(selectors.NEXT_BUTTON)
self.ui_helper.wait_for_loading_to_finish()
time.sleep(random.uniform(3, 5))
# Prüfe auf Erfolg
if self._check_verification_success():
logger.info("Telefon-Verifizierung erfolgreich")
self.ui_helper.take_screenshot("verification_success")
return {
"success": True,
"message": "Verifizierung erfolgreich"
}
else:
error_msg = self._get_verification_error()
logger.error(f"Verifizierung fehlgeschlagen: {error_msg}")
return {
"success": False,
"error": error_msg,
"message": f"Verifizierung fehlgeschlagen: {error_msg}"
}
else:
logger.info("Kein SMS-Code erforderlich")
return {
"success": True,
"message": "Telefon-Verifizierung abgeschlossen"
}
except Exception as e:
logger.error(f"Fehler bei der Telefon-Verifizierung: {e}")
self.ui_helper.take_screenshot("verification_error")
return {
"success": False,
"error": str(e),
"message": f"Verifizierung fehlgeschlagen: {str(e)}"
}
def handle_captcha(self) -> Dict[str, any]:
"""
Handhabt Captcha-Herausforderungen
"""
try:
logger.info("Prüfe auf Captcha")
if self.ui_helper.is_element_visible(selectors.CAPTCHA_CONTAINER):
logger.warning("Captcha erkannt - manuelle Lösung erforderlich")
self.ui_helper.take_screenshot("captcha_detected")
# TODO: Implementiere Captcha-Lösung
return {
"success": False,
"error": "Captcha erkannt",
"message": "Manuelle Captcha-Lösung erforderlich"
}
return {
"success": True,
"message": "Kein Captcha vorhanden"
}
except Exception as e:
logger.error(f"Fehler bei der Captcha-Prüfung: {e}")
return {
"success": False,
"error": str(e)
}
def _get_sms_code(self, phone: str) -> Optional[str]:
"""
Ruft den SMS-Code ab
TODO: Implementierung für echte SMS-Code Abfrage
"""
logger.warning("SMS-Code Abruf noch nicht implementiert - verwende Platzhalter")
# In einer echten Implementierung würde hier der SMS-Code
# von einem SMS-Service abgerufen werden
return "123456" # Platzhalter
def _check_verification_success(self) -> bool:
"""
Prüft ob die Verifizierung erfolgreich war
"""
try:
# Prüfe ob wir weitergeleitet wurden
current_url = self.page.url
if any(indicator in current_url for indicator in ["myaccount", "mail.google", "youtube"]):
return True
# Prüfe ob SMS-Code Feld noch sichtbar ist
if self.ui_helper.is_element_visible(selectors.SMS_CODE_INPUT):
# Prüfe auf Fehlermeldung
if self.ui_helper.is_element_visible(selectors.ERROR_MESSAGE):
return False
# Wenn kein Fehler aber noch SMS-Code Feld, warten wir noch
return False
return True
except Exception as e:
logger.warning(f"Fehler bei der Verifizierungs-Prüfung: {e}")
return False
def _get_verification_error(self) -> str:
"""
Holt die Fehlermeldung falls vorhanden
"""
try:
error_selectors = [
selectors.ERROR_MESSAGE,
selectors.ERROR_MESSAGE_ALT,
selectors.FORM_ERROR
]
for selector in error_selectors:
if self.ui_helper.is_element_visible(selector):
error_text = self.ui_helper.get_element_text(selector)
if error_text:
return error_text
return "Verifizierung fehlgeschlagen"
except:
return "Unbekannter Fehler"

Datei anzeigen

@ -0,0 +1,44 @@
"""
Gmail Workflow - Workflow-Definitionen für Gmail/Google Accounts
"""
# Workflow-Schritte für Gmail
REGISTRATION_WORKFLOW = [
"navigate_to_registration",
"fill_name_form",
"fill_birthday_gender",
"create_gmail_address",
"set_password",
"handle_phone_verification",
"handle_recovery_email",
"accept_terms",
"verify_account_creation"
]
LOGIN_WORKFLOW = [
"navigate_to_login",
"enter_email",
"enter_password",
"handle_2fa_if_needed",
"verify_login_success"
]
# Timeouts in Sekunden
TIMEOUTS = {
"page_load": 30,
"element_wait": 10,
"verification_wait": 60,
"sms_wait": 120,
"captcha_wait": 300
}
# Fehler-Nachrichten
ERROR_MESSAGES = {
"username_taken": "Dieser Nutzername ist bereits vergeben",
"invalid_phone": "Ungültige Telefonnummer",
"invalid_code": "Der eingegebene Code ist ungültig",
"too_many_attempts": "Zu viele Versuche",
"account_suspended": "Dieses Konto wurde gesperrt",
"captcha_required": "Bitte lösen Sie das Captcha",
"age_restriction": "Sie müssen mindestens 13 Jahre alt sein"
}