# social_networks/x/x_registration.py """ X (Twitter) Registrierung - Klasse für die Kontoerstellung bei X """ import time import random import re from typing import Dict, List, Any, Optional, Tuple from .x_selectors import XSelectors from .x_workflow import XWorkflow from utils.logger import setup_logger # Konfiguriere Logger logger = setup_logger("x_registration") class XRegistration: """ Klasse für die Registrierung von X-Konten. Enthält alle Methoden zur Kontoerstellung. """ def __init__(self, automation): """ Initialisiert die X-Registrierung. Args: automation: Referenz auf die Hauptautomatisierungsklasse """ self.automation = automation # Browser wird direkt von automation verwendet self.selectors = XSelectors() self.workflow = XWorkflow.get_registration_workflow() logger.debug("X-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 X-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 """ # Browser wird direkt von automation verwendet # 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) # Account-Daten als Instanzvariable speichern für späteren Zugriff self._current_account_data = account_data # Starte den Registrierungsprozess logger.info(f"Starte X-Registrierung für {account_data['username']} via {registration_method}") try: # 1. Zur Startseite navigieren self.automation._emit_customer_log("🌐 Mit X verbinden...") if not self._navigate_to_homepage(): return { "success": False, "error": "Konnte nicht zur X-Startseite navigieren", "stage": "navigation", "account_data": account_data } # 2. Cookie-Banner behandeln self.automation._emit_customer_log("⚙️ Einstellungen werden vorbereitet...") self._handle_cookie_banner() # 3. Account erstellen Button klicken self.automation._emit_customer_log("📋 Registrierungsformular wird geöffnet...") if not self._click_create_account_button(): return { "success": False, "error": "Konnte nicht auf Account erstellen Button klicken", "stage": "create_account_button", "account_data": account_data } # 4. Registrierungsformular ausfüllen (Name und E-Mail) self.automation._emit_customer_log("📝 Persönliche Daten werden übertragen...") if not self._fill_initial_registration_form(account_data): return { "success": False, "error": "Fehler beim Ausfüllen des initialen Registrierungsformulars", "stage": "initial_registration_form", "account_data": account_data } # 5. Geburtsdatum eingeben self.automation._emit_customer_log("🎂 Geburtsdatum wird festgelegt...") if not self._enter_birthday(account_data["birthday"]): return { "success": False, "error": "Fehler beim Eingeben des Geburtsdatums", "stage": "birthday", "account_data": account_data } # 6. Weiter klicken nach Geburtsdatum if not self._click_next_after_birthday(): return { "success": False, "error": "Fehler beim Fortfahren nach Geburtsdatum", "stage": "next_after_birthday", "account_data": account_data } # 7. Zweiter Weiter-Button (Einstellungen) if not self._click_next_settings(): return { "success": False, "error": "Fehler beim Fortfahren in den Einstellungen", "stage": "next_settings", "account_data": account_data } # 8. E-Mail-Verifizierung self.automation._emit_customer_log("📧 E-Mail-Verifizierung wird durchgeführt...") # Screenshot vor Verifizierung self.automation._take_screenshot("before_verification") verification_code = self._get_verification_code(account_data["email"]) if not verification_code: return { "success": False, "error": "Konnte keinen Verifizierungscode erhalten", "stage": "verification_code", "account_data": account_data } # Screenshot nach Code-Abruf self.automation._take_screenshot("after_code_retrieval") if not self._enter_verification_code(verification_code): # Screenshot bei Fehler self.automation._take_screenshot("verification_input_error") return { "success": False, "error": "Fehler beim Eingeben des Verifizierungscodes", "stage": "enter_verification_code", "account_data": account_data } # 9. Passwort festlegen self.automation._emit_customer_log("🔐 Passwort wird festgelegt...") if not self._enter_password(account_data["password"]): return { "success": False, "error": "Fehler beim Festlegen des Passworts", "stage": "password", "account_data": account_data } # 10. Profilbild überspringen self.automation._emit_customer_log("🖼️ Profilbild-Schritt wird übersprungen...") if not self._skip_profile_picture(): logger.warning("Konnte Profilbild-Schritt nicht überspringen, fahre trotzdem fort") # 11. Benutzername überspringen (X generiert automatisch einen) self.automation._emit_customer_log("👤 Benutzername-Schritt wird übersprungen...") if not self._skip_username(): logger.warning("Konnte Benutzername-Schritt nicht überspringen, fahre trotzdem fort") # 12. Benachrichtigungen überspringen self.automation._emit_customer_log("🔔 Benachrichtigungen werden übersprungen...") if not self._skip_notifications(): logger.warning("Konnte Benachrichtigungen nicht überspringen, fahre trotzdem fort") # 13. Erfolgreiche Registrierung überprüfen self.automation._emit_customer_log("🔍 Account wird finalisiert...") if not self._check_registration_success(): return { "success": False, "error": "Registrierung fehlgeschlagen oder konnte nicht verifiziert werden", "stage": "final_check", "account_data": account_data } # Registrierung erfolgreich abgeschlossen final_username = account_data.get('x_generated_username', account_data.get('username', 'unbekannt')) logger.info(f"X-Account {final_username} ({account_data['email']}) erfolgreich erstellt") self.automation._emit_customer_log(f"✅ Account erfolgreich erstellt! Benutzername: @{final_username}") return { "success": True, "stage": "completed", "account_data": account_data } except Exception as e: error_msg = f"Unerwarteter Fehler bei der X-Registrierung: {str(e)}" logger.error(error_msg, exc_info=True) return { "success": False, "error": error_msg, "stage": "exception", "account_data": account_data } def _validate_registration_inputs(self, full_name: str, age: int, registration_method: str, phone_number: str) -> bool: """ Validiert die Eingaben für die Registrierung. 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") Returns: bool: True wenn alle Eingaben gültig sind, False sonst """ # Name validieren if not full_name or len(full_name.strip()) < 2: logger.error("Ungültiger Name für die Registrierung") return False # Alter validieren (X erfordert mindestens 13 Jahre) if age < 13: logger.error("Alter muss mindestens 13 Jahre sein für X") return False # Registrierungsmethode validieren if registration_method not in ["email", "phone"]: logger.error(f"Ungültige Registrierungsmethode: {registration_method}") return False # Telefonnummer validieren, falls benötigt 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 die notwendigen Account-Daten für die Registrierung. Args: full_name: Vollständiger Name age: Alter registration_method: "email" oder "phone" phone_number: Telefonnummer (optional) **kwargs: Weitere optionale Parameter Returns: Dict[str, Any]: Generierte Account-Daten """ # Geburtsdatum generieren birthday = self.automation.birthday_generator.generate_birthday_components("x", age) # Passwort generieren password = kwargs.get("password") or self.automation.password_generator.generate_password() # E-Mail generieren (auch wenn per Telefon registriert wird, für spätere Verwendung) email = kwargs.get("email") or self._generate_email(full_name) # Benutzername generieren (X generiert automatisch einen, aber wir bereiten einen vor) username = kwargs.get("username") or self.automation.username_generator.generate_username(full_name) account_data = { "full_name": full_name, "username": username, "email": email, "password": password, "birthday": birthday, "age": age, "registration_method": registration_method } if phone_number: account_data["phone_number"] = phone_number logger.debug(f"Account-Daten generiert: {account_data['username']}") return account_data def _generate_email(self, full_name: str) -> str: """ Generiert eine E-Mail-Adresse basierend auf dem Namen. Args: full_name: Vollständiger Name Returns: str: Generierte E-Mail-Adresse """ # Entferne Sonderzeichen und konvertiere zu lowercase clean_name = re.sub(r'[^a-zA-Z0-9]', '', full_name.lower()) # Füge zufällige Ziffern hinzu random_suffix = ''.join([str(random.randint(0, 9)) for _ in range(4)]) # Erstelle E-Mail email = f"{clean_name}{random_suffix}@{self.automation.email_domain}" logger.debug(f"E-Mail generiert: {email}") return email def _navigate_to_homepage(self) -> bool: """ Navigiert zur X-Startseite. Returns: bool: True bei Erfolg, False bei Fehler """ try: page = self.automation.browser.page # Zur X-Startseite navigieren logger.info("Navigiere zur X-Startseite") page.goto("https://x.com/", wait_until="domcontentloaded", timeout=30000) # Warte auf Seitenladung self.automation.human_behavior.random_delay(2, 4) # Screenshot self.automation._take_screenshot("x_homepage") # Log current URL to verify we're on the right page current_url = page.url logger.info(f"Aktuelle URL: {current_url}") # Check if page loaded correctly if "x.com" not in current_url and "twitter.com" not in current_url: logger.error(f"Unerwartete URL: {current_url}") return False return True except Exception as e: logger.error(f"Fehler beim Navigieren zur X-Startseite: {e}") return False def _handle_cookie_banner(self): """ Behandelt eventuelle Cookie-Banner. """ try: page = self.automation.browser.page # Versuche Cookie-Banner zu akzeptieren (wenn vorhanden) cookie_selectors = [ "button:has-text('Accept all')", "button:has-text('Alle akzeptieren')", "button:has-text('Accept')", "button:has-text('Akzeptieren')" ] for selector in cookie_selectors: try: if page.is_visible(selector): # is_visible hat kein timeout parameter logger.info(f"Cookie-Banner gefunden: {selector}") page.click(selector) self.automation.human_behavior.random_delay(1, 2) break except: continue except Exception as e: logger.debug(f"Kein Cookie-Banner gefunden oder Fehler: {e}") def _click_create_account_button(self) -> bool: """ Klickt auf den "Account erstellen" Button. Returns: bool: True bei Erfolg, False bei Fehler """ try: page = self.automation.browser.page # Warte auf und klicke "Account erstellen" Button # Versuche mehrere Selektoren für bessere Robustheit create_account_selectors = [ 'text="Account erstellen"', # Am robustesten - findet jeden klickbaren Text 'span:has-text("Account erstellen")', # Falls der Text in einem span ist 'div[dir="ltr"] >> text="Account erstellen"', # Spezifischer '[role="button"]:has-text("Account erstellen")' # Falls es ein button role hat ] logger.info("Warte auf 'Account erstellen' Button") # Versuche jeden Selektor button_found = False for selector in create_account_selectors: try: # Warte kurz, um sicherzustellen, dass die Seite geladen ist page.wait_for_timeout(500) # Versuche wait_for_selector statt is_visible für bessere Zuverlässigkeit element = page.wait_for_selector(selector, timeout=3000, state="visible") if element: create_account_selector = selector button_found = True logger.info(f"Button gefunden mit Selektor: {selector}") break except Exception as e: logger.debug(f"Selektor {selector} nicht gefunden: {e}") continue if not button_found: logger.error("'Account erstellen' Button nicht gefunden") return False page.wait_for_selector(create_account_selector, timeout=5000) # Menschliches Verhalten simulieren self.automation.human_behavior.random_delay(0.5, 1.5) # Screenshot vor dem Klick self.automation._take_screenshot("before_account_create_click") # Button klicken page.click(create_account_selector) logger.info("'Account erstellen' Button geklickt") # Screenshot nach dem Klick self.automation.human_behavior.random_delay(1, 2) self.automation._take_screenshot("after_account_create_click") # Warte auf Formular self.automation.human_behavior.random_delay(1, 2) return True except Exception as e: logger.error(f"Fehler beim Klicken auf 'Account erstellen': {e}") return False def _fill_initial_registration_form(self, account_data: Dict[str, Any]) -> bool: """ Füllt das initiale Registrierungsformular aus (Name und E-Mail). Args: account_data: Account-Daten Returns: bool: True bei Erfolg, False bei Fehler """ try: page = self.automation.browser.page # Name eingeben name_selectors = [ 'input[name="name"]', 'input[autocomplete="name"]', 'input[placeholder*="Name"]', 'input[data-testid="ocfEnterTextTextInput"]', # X-spezifischer Selektor 'input[type="text"]:first-of-type' ] name_entered = False for selector in name_selectors: try: element = page.wait_for_selector(selector, timeout=2000, state="visible") if element: logger.info(f"Name-Input gefunden mit Selektor: {selector}") # Klicke zuerst auf das Feld element.click() self.automation.human_behavior.random_delay(0.3, 0.5) # Lösche eventuell vorhandenen Inhalt element.fill('') # Tippe den Namen langsam ein for char in account_data['full_name']: element.type(char) self.automation.human_behavior.random_delay(0.05, 0.15) # Zwischen Zeichen logger.info(f"Name eingegeben: {account_data['full_name']}") name_entered = True self.automation.human_behavior.random_delay(0.5, 1) break except Exception as e: logger.debug(f"Selektor {selector} nicht gefunden: {e}") continue if not name_entered: logger.error("Konnte Name nicht eingeben") return False # E-Mail eingeben email_selectors = [ 'input[name="email"]', 'input[autocomplete="email"]', 'input[type="email"]', 'input[placeholder*="Mail"]', 'input[placeholder*="mail"]', 'input[data-testid="ocfEnterTextTextInput"]:nth-of-type(2)' ] email_entered = False for selector in email_selectors: try: element = page.wait_for_selector(selector, timeout=2000, state="visible") if element: logger.info(f"E-Mail-Input gefunden mit Selektor: {selector}") # Klicke zuerst auf das Feld element.click() self.automation.human_behavior.random_delay(0.3, 0.5) # Lösche eventuell vorhandenen Inhalt element.fill('') # Tippe die E-Mail langsam ein for char in account_data['email']: element.type(char) self.automation.human_behavior.random_delay(0.05, 0.15) # Zwischen Zeichen logger.info(f"E-Mail eingegeben: {account_data['email']}") email_entered = True self.automation.human_behavior.random_delay(0.5, 1) break except Exception as e: logger.debug(f"Selektor {selector} nicht gefunden: {e}") continue if not email_entered: logger.error("Konnte E-Mail nicht eingeben") return False return True except Exception as e: logger.error(f"Fehler beim Ausfüllen des Registrierungsformulars: {e}") return False def _enter_birthday(self, birthday: Dict[str, int]) -> bool: """ Gibt das Geburtsdatum in die Dropdown-Felder ein. Args: birthday: Dictionary mit 'day', 'month', 'year' Returns: bool: True bei Erfolg, False bei Fehler """ try: page = self.automation.browser.page # Monat auswählen month_selector = 'select#SELECTOR_1' month_select = page.wait_for_selector(month_selector, timeout=5000) if month_select: logger.info(f"Wähle Monat: {birthday['month']}") page.select_option(month_selector, str(birthday['month'])) self.automation.human_behavior.random_delay(0.3, 0.7) # Tag auswählen day_selector = 'select#SELECTOR_2' day_select = page.wait_for_selector(day_selector, timeout=5000) if day_select: logger.info(f"Wähle Tag: {birthday['day']}") page.select_option(day_selector, str(birthday['day'])) self.automation.human_behavior.random_delay(0.3, 0.7) # Jahr auswählen year_selector = 'select#SELECTOR_3' year_select = page.wait_for_selector(year_selector, timeout=5000) if year_select: logger.info(f"Wähle Jahr: {birthday['year']}") page.select_option(year_selector, str(birthday['year'])) self.automation.human_behavior.random_delay(0.5, 1) # Screenshot nach Geburtstagseingabe self.automation._take_screenshot("birthday_page") return True except Exception as e: logger.error(f"Fehler beim Eingeben des Geburtsdatums: {e}") return False def _click_next_after_birthday(self) -> bool: """ Klickt auf den Weiter-Button nach der Geburtstagseingabe. Returns: bool: True bei Erfolg, False bei Fehler """ try: page = self.automation.browser.page # Weiter-Button klicken next_button = 'button[data-testid="ocfSignupNextLink"]' logger.info("Klicke auf Weiter nach Geburtsdatum") page.wait_for_selector(next_button, timeout=5000) page.click(next_button) self.automation.human_behavior.random_delay(1, 2) return True except Exception as e: logger.error(f"Fehler beim Klicken auf Weiter nach Geburtsdatum: {e}") return False def _click_next_settings(self) -> bool: """ Klickt auf den zweiten Weiter-Button (Einstellungen). Returns: bool: True bei Erfolg, False bei Fehler """ try: page = self.automation.browser.page # Zweiter Weiter-Button next_button = 'button[data-testid="ocfSettingsListNextButton"]' logger.info("Klicke auf Weiter in den Einstellungen") page.wait_for_selector(next_button, timeout=5000) page.click(next_button) self.automation.human_behavior.random_delay(2, 3) return True except Exception as e: logger.error(f"Fehler beim Klicken auf Weiter in Einstellungen: {e}") return False def _get_verification_code(self, email: str) -> Optional[str]: """ Holt den Verifizierungscode aus der E-Mail. Args: email: E-Mail-Adresse Returns: Optional[str]: Verifizierungscode oder None """ try: logger.info(f"Warte auf Verifizierungs-E-Mail für {email}") # Debug: Log die E-Mail-Adresse logger.info(f"Rufe Verifizierungscode ab für E-Mail: {email}") logger.info(f"Platform: x, Domain: {email.split('@')[1] if '@' in email else 'unknown'}") # Verwende die gleiche Methode wie Instagram verification_code = self.automation.email_handler.get_verification_code( target_email=email, platform="x", # Platform name für X (nicht "twitter"!) max_attempts=90, # 90 Versuche * 2 Sekunden = 180 Sekunden (3 Minuten) delay_seconds=2 ) if verification_code: logger.info(f"Verifizierungscode erhalten: {verification_code}") return verification_code else: logger.error("Konnte keinen Verifizierungscode erhalten") return None except Exception as e: logger.error(f"Fehler beim Abrufen des Verifizierungscodes: {e}") return None def _enter_verification_code(self, code: str) -> bool: """ Gibt den Verifizierungscode ein. Args: code: Verifizierungscode Returns: bool: True bei Erfolg, False bei Fehler """ try: page = self.automation.browser.page # Warte kurz, damit die Seite sich aktualisiert logger.info("Warte auf das Erscheinen des Verifizierungsfeldes...") self.automation.human_behavior.random_delay(2, 3) # Screenshot um zu sehen was auf der Seite ist self.automation._take_screenshot("verification_page_state") # Log alle sichtbaren Input-Felder try: all_inputs = page.query_selector_all('input:visible') logger.info(f"Gefundene sichtbare Input-Felder: {len(all_inputs)}") for i, input_elem in enumerate(all_inputs): input_type = input_elem.get_attribute('type') or 'text' input_name = input_elem.get_attribute('name') or 'unnamed' input_placeholder = input_elem.get_attribute('placeholder') or 'no placeholder' input_testid = input_elem.get_attribute('data-testid') or 'no testid' logger.info(f"Input {i}: type={input_type}, name={input_name}, placeholder={input_placeholder}, data-testid={input_testid}") except Exception as e: logger.debug(f"Konnte Input-Felder nicht loggen: {e}") # Verifizierungscode-Eingabefeld mit mehreren Selektoren code_selectors = [ # X-spezifische Selektoren 'input[data-testid="ocfEnterTextTextInput"]', 'input[autocomplete="one-time-code"]', 'input[name="verification_code"]', 'input[name="code"]', # Placeholder-basierte Selektoren 'input[placeholder*="Code"]', 'input[placeholder*="code"]', 'input[placeholder*="Gib"]', 'input[placeholder*="Enter"]', # Type-basierte Selektoren 'input[type="text"]:not([name="name"]):not([name="email"]):not([type="password"])', 'input[type="text"][data-testid*="verification"]', 'input[type="number"]', # Allgemeine Selektoren 'input:visible:not([name="name"]):not([name="email"]):not([type="password"])', 'div[role="textbox"] input', # Nth-child falls es das dritte Input-Feld ist 'input[type="text"]:nth-of-type(3)', 'input:nth-of-type(3)' ] # Prüfe ob wir vielleicht noch auf der vorherigen Seite sind if page.is_visible('button[data-testid="ocfSettingsListNextButton"]'): logger.info("Noch auf Einstellungen-Seite, klicke erneut auf Weiter") try: page.click('button[data-testid="ocfSettingsListNextButton"]') self.automation.human_behavior.random_delay(2, 3) except: pass code_entered = False # Versuche zuerst, das neueste Input-Feld zu finden try: # Finde alle Input-Felder und nimm das letzte/neueste all_inputs = page.query_selector_all('input[type="text"]:visible, input[type="tel"]:visible, input:not([type]):visible') if all_inputs and len(all_inputs) > 0: # Nimm das letzte sichtbare Input-Feld last_input = all_inputs[-1] logger.info(f"Versuche letztes Input-Feld ({len(all_inputs)} gefunden)") # Klicke und fülle es last_input.click() self.automation.human_behavior.random_delay(0.3, 0.5) last_input.fill('') # Tippe den Code for char in code: last_input.type(char) self.automation.human_behavior.random_delay(0.05, 0.15) logger.info("Verifizierungscode in letztes Input-Feld eingegeben") code_entered = True self.automation.human_behavior.random_delay(0.5, 1) except Exception as e: logger.debug(f"Konnte nicht über letztes Input-Feld eingeben: {e}") # Falls das nicht funktioniert hat, versuche die spezifischen Selektoren if not code_entered: for selector in code_selectors: try: element = page.wait_for_selector(selector, timeout=2000, state="visible") if element: logger.info(f"Verifizierungscode-Input gefunden mit Selektor: {selector}") # Klicke zuerst auf das Feld element.click() self.automation.human_behavior.random_delay(0.3, 0.5) # Lösche eventuell vorhandenen Inhalt element.fill('') # Tippe den Code langsam ein for char in code: element.type(char) self.automation.human_behavior.random_delay(0.05, 0.15) # Zwischen Zeichen logger.info(f"Verifizierungscode eingegeben: {code}") code_entered = True self.automation.human_behavior.random_delay(0.5, 1) break except Exception as e: logger.debug(f"Selektor {selector} nicht gefunden: {e}") continue if not code_entered: logger.error("Konnte Verifizierungscode nicht eingeben") return False # Weiter klicken - NACH erfolgreicher Code-Eingabe logger.info("Suche nach Weiter-Button...") next_selectors = [ 'button:has-text("Weiter")', 'text="Weiter"', 'button:has-text("Next")', # Englische Version 'text="Next"', 'div[role="button"]:has-text("Weiter")', 'div[role="button"]:has-text("Next")', '[data-testid*="next"]', 'button[type="submit"]', # X-spezifische Selektoren 'button[data-testid="LoginForm_Login_Button"]', 'div[data-testid="LoginForm_Login_Button"]' ] next_clicked = False for selector in next_selectors: try: element = page.wait_for_selector(selector, timeout=2000, state="visible") if element: logger.info(f"Weiter-Button gefunden mit Selektor: {selector}") page.click(selector) self.automation.human_behavior.random_delay(1, 2) next_clicked = True break except Exception as e: logger.debug(f"Selektor {selector} nicht gefunden: {e}") continue if not next_clicked: logger.warning("Weiter-Button nach Verifizierungscode nicht gefunden") # Screenshot für Debugging self.automation._take_screenshot("no_next_button_after_code") return True except Exception as e: logger.error(f"Fehler beim Eingeben des Verifizierungscodes: {e}") return False def _enter_password(self, password: str) -> bool: """ Legt das Passwort fest. Args: password: Passwort Returns: bool: True bei Erfolg, False bei Fehler """ try: page = self.automation.browser.page # Screenshot vor Passwort-Eingabe self.automation._take_screenshot("before_password_input") # Passwort-Eingabefeld mit mehreren Selektoren password_selectors = [ 'input[type="password"]', 'input[name="password"]', 'input[autocomplete="new-password"]', 'input[autocomplete="current-password"]', 'input[placeholder*="Passwort"]', 'input[placeholder*="Password"]' ] password_entered = False for selector in password_selectors: try: element = page.wait_for_selector(selector, timeout=3000, state="visible") if element: logger.info(f"Passwort-Input gefunden mit Selektor: {selector}") # Klicke zuerst auf das Feld element.click() self.automation.human_behavior.random_delay(0.3, 0.5) # Lösche eventuell vorhandenen Inhalt element.fill('') # Tippe das Passwort langsam ein for char in password: element.type(char) self.automation.human_behavior.random_delay(0.05, 0.15) # Zwischen Zeichen logger.info("Passwort eingegeben") password_entered = True self.automation.human_behavior.random_delay(0.5, 1) break except Exception as e: logger.debug(f"Selektor {selector} nicht gefunden: {e}") continue if not password_entered: logger.error("Konnte Passwort nicht eingeben") return False # Registrieren-Button klicken logger.info("Suche nach Registrieren-Button...") register_selectors = [ 'button[data-testid="LoginForm_Login_Button"]', 'button:has-text("Registrieren")', 'button:has-text("Sign up")', 'button:has-text("Create account")', 'button:has-text("Weiter")', 'button:has-text("Next")', 'button[type="submit"]', 'div[role="button"]:has-text("Registrieren")' ] register_clicked = False for selector in register_selectors: try: element = page.wait_for_selector(selector, timeout=2000, state="visible") if element: logger.info(f"Registrieren-Button gefunden mit Selektor: {selector}") page.click(selector) self.automation.human_behavior.random_delay(2, 3) register_clicked = True break except Exception as e: logger.debug(f"Selektor {selector} nicht gefunden: {e}") continue if not register_clicked: logger.warning("Registrieren-Button nicht gefunden") # Screenshot für Debugging self.automation._take_screenshot("no_register_button") return True except Exception as e: logger.error(f"Fehler beim Festlegen des Passworts: {e}") return False def _skip_profile_picture(self) -> bool: """ Überspringt den Profilbild-Schritt. Returns: bool: True bei Erfolg, False bei Fehler """ try: page = self.automation.browser.page # "Vorerst überspringen" Button skip_button = page.wait_for_selector('button[data-testid="ocfSelectAvatarSkipForNowButton"]', timeout=5000) if skip_button: logger.info("Überspringe Profilbild") skip_button.click() self.automation.human_behavior.random_delay(1, 2) return True return False except Exception as e: logger.debug(f"Konnte Profilbild nicht überspringen: {e}") return False def _skip_username(self) -> bool: """ Liest den von X generierten Benutzernamen aus und überspringt dann den Schritt. Returns: bool: True bei Erfolg, False bei Fehler """ try: page = self.automation.browser.page # Zuerst den generierten Benutzernamen auslesen username_input = page.wait_for_selector('input[name="username"]', timeout=5000) if username_input: # Benutzername aus dem value-Attribut auslesen generated_username = username_input.get_attribute("value") if generated_username: logger.info(f"Von X generierter Benutzername ausgelesen: {generated_username}") # Den generierten Benutzernamen in den Account-Daten speichern if hasattr(self, '_current_account_data'): self._current_account_data['username'] = generated_username self._current_account_data['x_generated_username'] = generated_username else: logger.warning("Konnte Account-Daten nicht aktualisieren") else: logger.warning("Konnte Benutzernamen nicht aus Input-Feld auslesen") # Dann den "Nicht jetzt" Button klicken skip_button = page.wait_for_selector('button[data-testid="ocfEnterUsernameSkipButton"]', timeout=5000) if skip_button: logger.info("Überspringe Benutzername-Änderung") skip_button.click() self.automation.human_behavior.random_delay(1, 2) return True return False except Exception as e: logger.debug(f"Fehler beim Benutzername-Schritt: {e}") return False def _skip_notifications(self) -> bool: """ Überspringt die Benachrichtigungseinstellungen. Returns: bool: True bei Erfolg, False bei Fehler """ try: page = self.automation.browser.page # "Vorerst überspringen" Button für Benachrichtigungen skip_selectors = [ 'div[dir="ltr"]:has-text("Vorerst überspringen")', 'div.css-146c3p1:has-text("Vorerst überspringen")', 'button:has-text("Vorerst überspringen")', 'text="Vorerst überspringen"', 'span:has-text("Vorerst überspringen")', '[role="button"]:has-text("Vorerst überspringen")' ] skip_button = None for selector in skip_selectors: try: skip_button = page.wait_for_selector(selector, timeout=1000) if skip_button: logger.info(f"'Vorerst überspringen' Button gefunden mit Selektor: {selector}") break except: continue if skip_button: logger.info("Überspringe Benachrichtigungen") # Warte kurz, damit der Button wirklich klickbar ist self.automation.human_behavior.random_delay(0.5, 1) skip_button.click() self.automation.human_behavior.random_delay(1, 2) return True else: logger.debug("'Vorerst überspringen' Button nicht gefunden") return False except Exception as e: logger.debug(f"Konnte Benachrichtigungen nicht überspringen: {e}") return False def _check_registration_success(self) -> bool: """ Überprüft, ob die Registrierung erfolgreich war. Returns: bool: True bei Erfolg, False bei Fehler """ try: page = self.automation.browser.page # Warte etwas self.automation.human_behavior.random_delay(2, 3) # Prüfe auf Zeichen erfolgreicher Registrierung # Z.B. Home-Timeline, Tweet-Button, etc. success_indicators = [ 'a[href="/home"]', 'a[data-testid="SideNav_NewTweet_Button"]', 'button[data-testid="tweetButtonInline"]', 'nav[aria-label="Primary"]' ] for indicator in success_indicators: try: # Warte kurz und prüfe dann ohne timeout page.wait_for_timeout(1000) if page.is_visible(indicator): logger.info(f"Registrierung erfolgreich - Indikator gefunden: {indicator}") # Finaler Screenshot self.automation._take_screenshot("registration_final") return True except: continue logger.error("Keine Erfolgsindikatoren gefunden") return False except Exception as e: logger.error(f"Fehler beim Überprüfen des Registrierungserfolgs: {e}") return False