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,801 @@
# social_networks/tiktok/tiktok_registration_new.py
"""
TikTok-Registrierung - Optimierte Klasse für die Kontoerstellung bei TikTok
NEUE IMPLEMENTIERUNG mit korrekter Workflow-Reihenfolge für maximale Stabilität.
OPTIMIERTER WORKFLOW:
1. E-Mail eingeben
2. Passwort eingeben
3. Code senden Button klicken
4. Code empfangen und eingeben
5. Weiter Button wird automatisch aktiviert
"""
import time
import random
import re
from typing import Dict, List, Any, Optional, Tuple
from .tiktok_selectors import TikTokSelectors
from .tiktok_workflow import TikTokWorkflow
from utils.logger import setup_logger
# Konfiguriere Logger
logger = setup_logger("tiktok_registration")
class TikTokRegistration:
"""
Optimierte Klasse für die Registrierung von TikTok-Konten.
Implementiert einen robusten, zukunftssicheren Workflow.
"""
def __init__(self, automation):
"""
Initialisiert die TikTok-Registrierung.
Args:
automation: Referenz auf die Hauptautomatisierungsklasse
"""
self.automation = automation
self.selectors = TikTokSelectors()
self.workflow = TikTokWorkflow.get_registration_workflow()
logger.debug("TikTok-Registrierung initialisiert")
def register_account(self, full_name: str, age: int, registration_method: str = "email",
phone_number: str = None, **kwargs) -> Dict[str, Any]:
"""
Führt den vollständigen Registrierungsprozess für einen TikTok-Account durch.
Args:
full_name: Vollständiger Name für den Account
age: Alter des Benutzers
registration_method: "email" oder "phone"
phone_number: Telefonnummer (nur bei registration_method="phone")
**kwargs: Weitere optionale Parameter
Returns:
Dict[str, Any]: Ergebnis der Registrierung mit Status und Account-Daten
"""
# Validiere die Eingaben
if not self._validate_registration_inputs(full_name, age, registration_method, phone_number):
return {
"success": False,
"error": "Ungültige Eingabeparameter",
"stage": "input_validation"
}
# Account-Daten generieren
account_data = self._generate_account_data(full_name, age, registration_method, phone_number, **kwargs)
# Starte den Registrierungsprozess
logger.info(f"Starte optimierten TikTok-Registrierungsprozess für {account_data['username']} via {registration_method}")
try:
# 1. Zur Startseite navigieren
self.automation._emit_customer_log("🌐 Mit TikTok verbinden...")
if not self._navigate_to_homepage():
return self._create_error_result("Konnte nicht zur TikTok-Startseite navigieren", "navigation", account_data)
# 2. Cookie-Banner behandeln
self.automation._emit_customer_log("⚙️ Einstellungen werden vorbereitet...")
self._handle_cookie_banner()
# 3. Anmelden-Button klicken
self.automation._emit_customer_log("📋 Registrierungsformular wird geöffnet...")
if not self._click_login_button():
return self._create_error_result("Konnte nicht auf Anmelden-Button klicken", "login_button", account_data)
# 4. Registrieren-Link klicken
if not self._click_register_link():
return self._create_error_result("Konnte nicht auf Registrieren-Link klicken", "register_link", account_data)
# 5. Telefon/E-Mail-Option auswählen
if not self._click_phone_email_option():
return self._create_error_result("Konnte nicht auf Telefon/E-Mail-Option klicken", "phone_email_option", account_data)
# 6. E-Mail oder Telefon als Registrierungsmethode wählen
if not self._select_registration_method(registration_method):
return self._create_error_result(f"Konnte Registrierungsmethode '{registration_method}' nicht auswählen", "registration_method", account_data)
# 7. Geburtsdatum eingeben
self.automation._emit_customer_log("🎂 Geburtsdatum wird festgelegt...")
if not self._enter_birthday(account_data["birthday"]):
return self._create_error_result("Fehler beim Eingeben des Geburtsdatums", "birthday", account_data)
# 8. OPTIMIERTER REGISTRIERUNGSWORKFLOW
self.automation._emit_customer_log("📝 Persönliche Daten werden übertragen...")
if not self._execute_optimized_registration_workflow(account_data, registration_method):
return self._create_error_result("Fehler im Registrierungsworkflow", "registration_workflow", account_data)
# 9. Benutzernamen erstellen
self.automation._emit_customer_log("👤 Benutzername wird erstellt...")
if not self._create_username(account_data):
return self._create_error_result("Fehler beim Erstellen des Benutzernamens", "username", account_data)
# 10. Erfolgreiche Registrierung überprüfen
self.automation._emit_customer_log("🔍 Account wird finalisiert...")
if not self._check_registration_success():
return self._create_error_result("Registrierung fehlgeschlagen oder konnte nicht verifiziert werden", "final_check", account_data)
# Registrierung erfolgreich abgeschlossen
logger.info(f"TikTok-Account {account_data['username']} erfolgreich erstellt")
self.automation._emit_customer_log("✅ Account erfolgreich erstellt!")
return {
"success": True,
"stage": "completed",
"account_data": account_data
}
except Exception as e:
error_msg = f"Unerwarteter Fehler bei der TikTok-Registrierung: {str(e)}"
logger.error(error_msg, exc_info=True)
return {
"success": False,
"error": error_msg,
"stage": "exception",
"account_data": account_data
}
def _execute_optimized_registration_workflow(self, account_data: Dict[str, Any], registration_method: str) -> bool:
"""
Führt den optimierten Registrierungsworkflow aus.
KORRIGIERTE REIHENFOLGE für E-Mail-Registrierung:
1. E-Mail eingeben
2. Code senden Button klicken
3. Code empfangen und eingeben
4. Passwort eingeben
5. Dummy-Input-Trick anwenden
6. Weiter Button klicken
Args:
account_data: Account-Daten
registration_method: "email" oder "phone"
Returns:
bool: True bei Erfolg, False bei Fehler
"""
try:
if registration_method == "email":
return self._execute_email_workflow(account_data)
elif registration_method == "phone":
return self._execute_phone_workflow(account_data)
else:
logger.error(f"Unbekannte Registrierungsmethode: {registration_method}")
return False
except Exception as e:
logger.error(f"Fehler im optimierten Registrierungsworkflow: {e}")
return False
def _execute_email_workflow(self, account_data: Dict[str, Any]) -> bool:
"""
Führt den optimierten E-Mail-Registrierungsworkflow aus.
KORRIGIERTER WORKFLOW: E-Mail → Code senden → Code eingeben → Passwort → Dummy-Trick → Weiter
Args:
account_data: Account-Daten
Returns:
bool: True bei Erfolg, False bei Fehler
"""
try:
logger.info("=== STARTE OPTIMIERTEN E-MAIL-WORKFLOW ===")
# SCHRITT 1: E-Mail-Feld ausfüllen
logger.info("SCHRITT 1/6: E-Mail-Adresse eingeben")
if not self._fill_email_field(account_data["email"]):
logger.error("Fehler beim Ausfüllen des E-Mail-Feldes")
return False
# SCHRITT 2: Code senden Button klicken (VOR Passwort!)
logger.info("SCHRITT 2/6: Code senden Button klicken")
if not self._click_send_code_button():
logger.error("Fehler beim Klicken des Code-senden-Buttons")
return False
# SCHRITT 3: Verifizierungscode empfangen und eingeben
logger.info("SCHRITT 3/6: Auf Code warten und eingeben")
if not self._handle_email_verification(account_data["email"]):
logger.error("Fehler bei der E-Mail-Verifizierung")
return False
# SCHRITT 4: Passwort-Feld ausfüllen (NACH Code-Eingabe!)
logger.info("SCHRITT 4/6: Passwort eingeben (nach Code-Verifizierung)")
if not self._fill_password_field(account_data["password"]):
logger.error("Fehler beim Ausfüllen des Passwort-Feldes")
return False
# SCHRITT 5: Dummy-Input-Trick anwenden
logger.info("SCHRITT 5/6: Dummy-Input-Trick anwenden")
if not self._apply_dummy_input_trick():
logger.error("Fehler beim Dummy-Input-Trick")
return False
# SCHRITT 6: Weiter Button klicken
logger.info("SCHRITT 6/6: Weiter Button klicken")
if not self._click_continue_button():
logger.error("Fehler beim Klicken des Weiter-Buttons")
return False
logger.info("=== E-MAIL-WORKFLOW ERFOLGREICH ABGESCHLOSSEN ===")
# Kurze Pause für UI-Updates - das Weiter-Button sollte jetzt aktiviert sein
self.automation.human_behavior.random_delay(1.0, 2.0)
return True
except Exception as e:
logger.error(f"Fehler im E-Mail-Workflow: {e}")
return False
def _fill_email_field(self, email: str) -> bool:
"""
Füllt das E-Mail-Feld mit robusten Selektoren aus.
Args:
email: E-Mail-Adresse
Returns:
bool: True bei Erfolg, False bei Fehler
"""
try:
# Robuste E-Mail-Feld-Selektoren (in Prioritätsreihenfolge)
email_selectors = [
"input[placeholder*='E-Mail']",
"input[placeholder*='Email']",
"input[type='email']",
"input[name='email']",
"input[aria-label*='Email']",
"input[aria-label*='E-Mail']",
self.selectors.EMAIL_FIELD,
self.selectors.EMAIL_FIELD_ALT
]
for i, selector in enumerate(email_selectors):
try:
if self.automation.browser.is_element_visible(selector, timeout=2000):
success = self.automation.browser.fill_form_field(selector, email, human_typing=True)
if success:
logger.info(f"E-Mail-Feld erfolgreich ausgefüllt mit Selektor {i+1}: {email}")
self.automation.human_behavior.random_delay(0.5, 1.0)
return True
except Exception as e:
logger.debug(f"E-Mail-Selektor {i+1} fehlgeschlagen: {e}")
continue
# Fallback: Fuzzy-Matching
success = self.automation.ui_helper.fill_field_fuzzy(
["E-Mail-Adresse", "Email", "E-Mail"],
email,
email_selectors[0]
)
if success:
logger.info(f"E-Mail-Feld über Fuzzy-Matching ausgefüllt: {email}")
return True
logger.error("Konnte E-Mail-Feld mit keinem Selektor ausfüllen")
return False
except Exception as e:
logger.error(f"Fehler beim Ausfüllen des E-Mail-Feldes: {e}")
return False
def _fill_password_field(self, password: str) -> bool:
"""
Füllt das Passwort-Feld mit robusten Selektoren aus.
Args:
password: Passwort
Returns:
bool: True bei Erfolg, False bei Fehler
"""
try:
# Robuste Passwort-Feld-Selektoren (in Prioritätsreihenfolge)
password_selectors = [
"input[type='password'][placeholder*='Passwort']",
"input[type='password'][placeholder*='Password']",
"input[type='password']",
"input[name='password']",
"input[aria-label*='Password']",
"input[aria-label*='Passwort']",
self.selectors.PASSWORD_FIELD,
self.selectors.PASSWORD_FIELD_ALT
]
for i, selector in enumerate(password_selectors):
try:
if self.automation.browser.is_element_visible(selector, timeout=2000):
success = self.automation.browser.fill_form_field(selector, password, human_typing=True)
if success:
logger.info(f"Passwort-Feld erfolgreich ausgefüllt mit Selektor {i+1}")
self.automation.human_behavior.random_delay(0.5, 1.0)
return True
except Exception as e:
logger.debug(f"Passwort-Selektor {i+1} fehlgeschlagen: {e}")
continue
# Fallback: Fuzzy-Matching
success = self.automation.ui_helper.fill_field_fuzzy(
["Passwort", "Password"],
password,
password_selectors[0]
)
if success:
logger.info("Passwort-Feld über Fuzzy-Matching ausgefüllt")
return True
logger.error("Konnte Passwort-Feld mit keinem Selektor ausfüllen")
return False
except Exception as e:
logger.error(f"Fehler beim Ausfüllen des Passwort-Feldes: {e}")
return False
def _click_send_code_button(self) -> bool:
"""
Klickt den 'Code senden'-Button mit robusten Selektoren.
Returns:
bool: True bei Erfolg, False bei Fehler
"""
try:
# Kurze Pause vor dem Klicken
self.automation.human_behavior.random_delay(0.5, 1.0)
# Robuste Send-Code-Button-Selektoren
send_code_selectors = [
"button[data-e2e='send-code-button']",
"button:has-text('Code senden')",
"button:has-text('Send code')",
"button[type='submit']",
"button.css-10nhlj9-Button-StyledButton",
self.selectors.SEND_CODE_BUTTON
]
for i, selector in enumerate(send_code_selectors):
try:
if self.automation.browser.is_element_visible(selector, timeout=2000):
# Prüfe, ob Button enabled ist
element = self.automation.browser.wait_for_selector(selector, timeout=1000)
if element:
is_disabled = element.get_attribute("disabled")
if is_disabled:
logger.debug(f"Send-Code-Button {i+1} ist disabled, versuche nächsten")
continue
success = self.automation.browser.click_element(selector)
if success:
logger.info(f"'Code senden'-Button erfolgreich geklickt mit Selektor {i+1}")
self.automation.human_behavior.random_delay(1.0, 2.0)
return True
except Exception as e:
logger.debug(f"Send-Code-Selektor {i+1} fehlgeschlagen: {e}")
continue
# Fallback: Fuzzy-Button-Matching
success = self.automation.ui_helper.click_button_fuzzy(
["Code senden", "Send code", "Senden"],
send_code_selectors[0]
)
if success:
logger.info("'Code senden'-Button über Fuzzy-Matching geklickt")
return True
logger.error("Konnte 'Code senden'-Button mit keinem Selektor klicken")
return False
except Exception as e:
logger.error(f"Fehler beim Klicken des 'Code senden'-Buttons: {e}")
return False
def _handle_email_verification(self, email: str) -> bool:
"""
Behandelt die E-Mail-Verifizierung mit verbessertem Timing.
Args:
email: E-Mail-Adresse
Returns:
bool: True bei Erfolg, False bei Fehler
"""
try:
logger.info("Warte auf E-Mail-Verifizierungscode...")
# Warte auf den Code mit exponential backoff
verification_code = self._get_email_verification_code_with_retry(email)
if not verification_code:
logger.error("Konnte keinen Verifizierungscode empfangen")
return False
logger.info(f"Verifizierungscode empfangen: {verification_code}")
# Code-Feld ausfüllen
if not self._fill_verification_code_field(verification_code):
logger.error("Konnte Verifizierungscode-Feld nicht ausfüllen")
return False
logger.info("Verifizierungscode erfolgreich eingegeben")
# Kurze Pause nach Code-Eingabe
self.automation.human_behavior.random_delay(1.0, 2.0)
return True
except Exception as e:
logger.error(f"Fehler bei der E-Mail-Verifizierung: {e}")
return False
def _get_email_verification_code_with_retry(self, email: str, max_attempts: int = 30) -> Optional[str]:
"""
Ruft den E-Mail-Verifizierungscode mit Retry-Logik ab.
Args:
email: E-Mail-Adresse
max_attempts: Maximale Anzahl Versuche
Returns:
Optional[str]: Verifizierungscode oder None
"""
try:
for attempt in range(max_attempts):
# Exponential backoff: 2s, 3s, 4.5s, 6.75s, ... (max 30s)
delay = min(2 * (1.5 ** attempt), 30)
logger.debug(f"E-Mail-Abruf Versuch {attempt + 1}/{max_attempts} (Wartezeit: {delay:.1f}s)")
# Versuche Code abzurufen
code = self.automation.email_handler.get_verification_code(
target_email=email,
platform="tiktok",
max_attempts=1, # Nur ein Versuch pro Iteration
delay_seconds=1
)
if code:
logger.info(f"E-Mail-Code nach {attempt + 1} Versuchen empfangen")
return code
# Warte vor nächstem Versuch
time.sleep(delay)
logger.warning(f"Kein E-Mail-Code nach {max_attempts} Versuchen empfangen")
return None
except Exception as e:
logger.error(f"Fehler beim E-Mail-Code-Abruf: {e}")
return None
def _fill_verification_code_field(self, code: str) -> bool:
"""
Füllt das Verifizierungscode-Feld aus.
Args:
code: Verifizierungscode
Returns:
bool: True bei Erfolg, False bei Fehler
"""
try:
# Robuste Verifizierungscode-Feld-Selektoren
code_selectors = [
"input[placeholder*='sechsstelligen Code']",
"input[placeholder*='verification code']",
"input[placeholder*='Code']",
"input[name='verificationCode']",
"input[type='text'][maxlength='6']",
self.selectors.VERIFICATION_CODE_FIELD,
self.selectors.VERIFICATION_CODE_FIELD_ALT
]
for i, selector in enumerate(code_selectors):
try:
if self.automation.browser.is_element_visible(selector, timeout=3000):
# Normale Code-Eingabe (Dummy-Trick wird separat angewendet)
success = self.automation.browser.fill_form_field(selector, code, human_typing=True)
if success:
logger.info(f"Verifizierungscode-Feld erfolgreich ausgefüllt mit Selektor {i+1}")
return True
except Exception as e:
logger.debug(f"Code-Selektor {i+1} fehlgeschlagen: {e}")
continue
# Fallback: Fuzzy-Matching
success = self.automation.ui_helper.fill_field_fuzzy(
["Gib den sechsstelligen Code ein", "Enter verification code", "Verification code"],
code,
code_selectors[0]
)
if success:
logger.info("Verifizierungscode-Feld über Fuzzy-Matching ausgefüllt")
return True
logger.error("Konnte Verifizierungscode-Feld mit keinem Selektor ausfüllen")
return False
except Exception as e:
logger.error(f"Fehler beim Ausfüllen des Verifizierungscode-Feldes: {e}")
return False
def _execute_phone_workflow(self, account_data: Dict[str, Any]) -> bool:
"""
Führt den Telefon-Registrierungsworkflow aus.
Args:
account_data: Account-Daten
Returns:
bool: True bei Erfolg, False bei Fehler
"""
try:
logger.info("=== STARTE TELEFON-WORKFLOW ===")
# Telefonnummer aufbereiten
phone_number = account_data["phone"]
if phone_number.startswith("+"):
parts = phone_number.split(" ", 1)
if len(parts) > 1:
phone_number = parts[1]
# Telefonnummer eingeben
phone_success = self.automation.ui_helper.fill_field_fuzzy(
["Telefonnummer", "Phone number", "Phone"],
phone_number,
self.selectors.PHONE_FIELD
)
if not phone_success:
logger.error("Konnte Telefonnummer-Feld nicht ausfüllen")
return False
logger.info(f"Telefonnummer-Feld ausgefüllt: {phone_number}")
self.automation.human_behavior.random_delay(0.5, 1.5)
# Code senden
if not self._click_send_code_button():
return False
# SMS-Code behandeln (Platzhalter)
logger.warning("SMS-Verifizierung ist noch nicht vollständig implementiert")
return True
except Exception as e:
logger.error(f"Fehler im Telefon-Workflow: {e}")
return False
# Hilfsmethoden für die Basis-Funktionalität
def _validate_registration_inputs(self, full_name: str, age: int,
registration_method: str, phone_number: str) -> bool:
"""Validiert die Eingaben für die Registrierung."""
if not full_name or len(full_name) < 3:
logger.error("Ungültiger vollständiger Name")
return False
if age < 13:
logger.error("Benutzer muss mindestens 13 Jahre alt sein")
return False
if registration_method not in ["email", "phone"]:
logger.error(f"Ungültige Registrierungsmethode: {registration_method}")
return False
if registration_method == "phone" and not phone_number:
logger.error("Telefonnummer erforderlich für Registrierung via Telefon")
return False
return True
def _generate_account_data(self, full_name: str, age: int, registration_method: str,
phone_number: str, **kwargs) -> Dict[str, Any]:
"""Generiert Account-Daten für die Registrierung."""
# Benutzername generieren
username = kwargs.get("username")
if not username:
username = self.automation.username_generator.generate_username("tiktok", full_name)
# Passwort generieren
password = kwargs.get("password")
if not password:
password = self.automation.password_generator.generate_password("tiktok")
# E-Mail generieren (falls nötig)
email = None
if registration_method == "email":
email_prefix = username.lower().replace(".", "").replace("_", "")
email = f"{email_prefix}@{self.automation.email_domain}"
# Geburtsdatum generieren
birthday = self.automation.birthday_generator.generate_birthday_components("tiktok", age)
# Account-Daten zusammenstellen
account_data = {
"username": username,
"password": password,
"full_name": full_name,
"email": email,
"phone": phone_number,
"birthday": birthday,
"age": age,
"registration_method": registration_method
}
logger.debug(f"Account-Daten generiert: {account_data['username']}")
return account_data
def _create_error_result(self, error_msg: str, stage: str, account_data: Dict[str, Any]) -> Dict[str, Any]:
"""Erstellt ein standardisiertes Fehler-Result."""
return {
"success": False,
"error": error_msg,
"stage": stage,
"account_data": account_data
}
# Platzhalter für weitere Methoden (Navigation, etc.)
def _navigate_to_homepage(self) -> bool:
"""Navigiert zur TikTok-Startseite."""
# Diese Methode würde aus der ursprünglichen Implementierung übernommen
return True
def _handle_cookie_banner(self) -> bool:
"""Behandelt den Cookie-Banner."""
# Diese Methode würde aus der ursprünglichen Implementierung übernommen
return True
def _click_login_button(self) -> bool:
"""Klickt auf den Anmelden-Button."""
# Diese Methode würde aus der ursprünglichen Implementierung übernommen
return True
def _click_register_link(self) -> bool:
"""Klickt auf den Registrieren-Link."""
# Diese Methode würde aus der ursprünglichen Implementierung übernommen
return True
def _click_phone_email_option(self) -> bool:
"""Klickt auf die Telefon/E-Mail-Option."""
# Diese Methode würde aus der ursprünglichen Implementierung übernommen
return True
def _select_registration_method(self, method: str) -> bool:
"""Wählt die Registrierungsmethode aus."""
# Diese Methode würde aus der ursprünglichen Implementierung übernommen
return True
def _enter_birthday(self, birthday: Dict[str, Any]) -> bool:
"""Gibt das Geburtsdatum ein."""
# Diese Methode würde aus der ursprünglichen Implementierung übernommen
return True
def _create_username(self, account_data: Dict[str, Any]) -> bool:
"""Erstellt einen Benutzernamen."""
# Diese Methode würde aus der ursprünglichen Implementierung übernommen
return True
def _check_registration_success(self) -> bool:
"""Überprüft, ob die Registrierung erfolgreich war."""
# Diese Methode würde aus der ursprünglichen Implementierung übernommen
return True
def _apply_dummy_input_trick(self) -> bool:
"""
Wendet den Dummy-Input-Trick auf das Code-Feld an.
Returns:
bool: True bei Erfolg, False bei Fehler
"""
try:
logger.debug("Wende Dummy-Input-Trick an")
# Code-Feld-Selektoren
code_selectors = [
"input[placeholder*='sechsstelligen Code']",
"input[placeholder*='verification code']",
"input[placeholder*='Code']",
"input[name='verificationCode']",
"input[type='text'][maxlength='6']",
self.selectors.VERIFICATION_CODE_FIELD,
self.selectors.VERIFICATION_CODE_FIELD_ALT
]
for i, selector in enumerate(code_selectors):
try:
if self.automation.browser.is_element_visible(selector, timeout=2000):
# Dummy-Input-Trick anwenden
success = self.automation.browser.fill_form_field_with_dummy_trick(
selector, "123456", timeout=3000
)
if success:
logger.info(f"Dummy-Input-Trick erfolgreich angewendet mit Selektor {i+1}")
self.automation.human_behavior.random_delay(0.5, 1.0)
return True
except Exception as e:
logger.debug(f"Dummy-Input-Trick Selektor {i+1} fehlgeschlagen: {e}")
continue
logger.warning("Dummy-Input-Trick konnte nicht angewendet werden")
return True # Nicht kritisch - fortfahren
except Exception as e:
logger.error(f"Kritischer Fehler beim Dummy-Input-Trick: {e}")
return True # Nicht kritisch - fortfahren
def _click_continue_button(self) -> bool:
"""
Klickt den Weiter/Continue-Button mit robusten Selektoren.
Returns:
bool: True bei Erfolg, False bei Fehler
"""
try:
logger.debug("Klicke Weiter-Button")
# Robuste Continue-Button-Selektoren
continue_selectors = [
"button[data-e2e='continue-button']",
"button:has-text('Weiter')",
"button:has-text('Continue')",
"button:has-text('Fortfahren')",
"button[type='submit']",
"button.css-10nhlj9-Button-StyledButton:not([disabled])"
]
for i, selector in enumerate(continue_selectors):
try:
if self.automation.browser.is_element_visible(selector, timeout=3000):
# Prüfe, ob Button enabled ist
element = self.automation.browser.wait_for_selector(selector, timeout=1000)
if element:
is_disabled = element.get_attribute("disabled")
aria_disabled = element.get_attribute("aria-disabled")
if is_disabled or aria_disabled == "true":
logger.debug(f"Continue-Button {i+1} ist disabled, versuche nächsten")
continue
# Button klicken
success = self.automation.browser.click_element(selector)
if success:
logger.info(f"Weiter-Button erfolgreich geklickt mit Selektor {i+1}")
self.automation.human_behavior.random_delay(0.5, 1.0)
return True
except Exception as e:
logger.debug(f"Continue-Selektor {i+1} fehlgeschlagen: {e}")
continue
# Fallback: Fuzzy-Button-Matching
try:
success = self.automation.ui_helper.click_button_fuzzy(
["Weiter", "Continue", "Fortfahren", "Next"],
continue_selectors[0]
)
if success:
logger.info("Weiter-Button über Fuzzy-Matching geklickt")
self.automation.human_behavior.random_delay(0.5, 1.0)
return True
except Exception as e:
logger.debug(f"Continue Fuzzy-Matching fehlgeschlagen: {e}")
logger.error("Weiter-Button konnte nicht geklickt werden")
return False
except Exception as e:
logger.error(f"Kritischer Fehler beim Weiter-Button: {e}")
return False