Rollbackpunkt, alles außer TikTok geht, die wollen wieder so eine extra locke bei Login

Dieser Commit ist enthalten in:
Claude Project Manager
2025-10-18 02:26:44 +02:00
Ursprung 9c1d7d8a8f
Commit 7261f70073
12 geänderte Dateien mit 754 neuen und 254 gelöschten Zeilen

Datei anzeigen

@ -124,22 +124,69 @@ class FacebookRegistration:
}
# 7. Erfolgreiche Registrierung überprüfen
if not self._check_registration_success():
return {
"success": False,
"error": "Registrierung fehlgeschlagen",
"stage": "final_check"
}
success_check = self._check_registration_success()
# 8. Wenn nicht erfolgreich: Prüfe auf Cookie-Consent oder andere Zwischen-Schritte
if not success_check:
current_url = self.automation.browser.page.url
logger.info(f"Success-Check fehlgeschlagen, prüfe Zwischen-Schritte: {current_url}")
# Behandle Cookie-Consent falls vorhanden
if "privacy/consent" in current_url or "user_cookie_choice" in current_url:
logger.info("Cookie-Consent Dialog erkannt (nach Verifikation)")
self.automation._send_log_update("Behandle Cookie-Einstellungen...")
if self._handle_cookie_consent():
logger.info("Cookie-Consent erfolgreich behandelt")
# Warte nach Cookie-Ablehnung
self.automation.human_behavior.wait_for_page_load(multiplier=1.5)
# Prüfe auf finalen Dialog/Layer mit "Schließen"-Button
if self._handle_final_dialogs():
logger.info("Finale Dialogs behandelt")
# Erneuter Success-Check
success_check = self._check_registration_success()
if not success_check:
return {
"success": False,
"error": "Registrierung fehlgeschlagen (nach Zwischen-Schritten)",
"stage": "final_check"
}
# Registrierung erfolgreich
logger.info(f"Facebook-Account erfolgreich erstellt")
self.automation._send_status_update("Registrierung erfolgreich!")
self.automation._send_log_update("Account wurde erfolgreich erstellt")
# Account-Daten für Rückgabe vorbereiten
account_data["platform"] = "facebook"
account_data["created_at"] = time.time()
# Username generieren falls nicht vorhanden (Facebook gibt keinen zurück)
if not account_data.get("username"):
username = self._generate_username_from_email(
account_data.get("email", ""),
account_data.get("first_name", ""),
account_data.get("last_name", "")
)
# Username ist GARANTIERT vorhanden (Fallback-Strategien)
account_data["username"] = username
logger.info(f"Username generiert: {username}")
# KRITISCHE VALIDIERUNG: Stelle sicher dass Username vorhanden ist
if not account_data.get("username") or account_data["username"] == "":
error_msg = "KRITISCHER FEHLER: Username konnte nicht generiert werden"
logger.error(error_msg)
logger.error(f"Account-Daten: {account_data}")
return {
"success": False,
"error": error_msg,
"stage": "username_validation_failed",
"account_data": account_data
}
return {
"success": True,
"stage": "completed",
@ -672,11 +719,15 @@ class FacebookRegistration:
logger.info("E-Mail-Verifikation erforderlich (Input-Field gefunden)")
return True
# Prüfe auf Erfolgs-Indikatoren (dann keine Verifikation nötig)
for indicator in self.selectors.SUCCESS_INDICATORS:
if self.automation.browser.is_element_visible(indicator, timeout=500):
logger.info(f"Keine Verifikation nötig (Erfolgs-Indikator gefunden: {indicator})")
return False
# Prüfe auf Erfolgs-Indikatoren NUR wenn URL eindeutig KEINE Verifikations-URL ist
# WICHTIG: Verifikationsseiten haben auch div[role='navigation'], deshalb URL-Check zuerst!
if "privacy/consent" not in current_url and "user_cookie_choice" not in current_url:
for indicator in self.selectors.SUCCESS_INDICATORS:
if self.automation.browser.is_element_visible(indicator, timeout=500):
# Finale Prüfung: Ist es wirklich eine Erfolgsseite?
if "facebook.com/?" in current_url or "facebook.com/home" in current_url or "feed" in current_url:
logger.info(f"Keine Verifikation nötig (Erfolgs-Indikator gefunden: {indicator})")
return False
# Kurze Pause vor nächstem Versuch
time.sleep(check_interval)
@ -797,48 +848,182 @@ class FacebookRegistration:
# Warte auf Navigation/Verarbeitung
self.automation.human_behavior.wait_for_page_load(multiplier=1.5)
# Prüfe auf OK-Button (Popup nach erfolgreicher Verifikation)
# Warte länger, da das Popup verzögert erscheinen kann
self.automation.human_behavior.random_delay(1.0, 2.0)
ok_selectors = [
self.selectors.VERIFICATION_OK_BUTTON,
self.selectors.VERIFICATION_OK_BUTTON_ALT,
"a:has-text('OK')",
"button:has-text('OK')"
self.selectors.VERIFICATION_OK_BUTTON, # a.layerCancel:has-text('OK')
self.selectors.VERIFICATION_OK_BUTTON_ALT, # a[role='button']:has-text('OK')
"a.layerCancel", # Nur Klasse (falls Text-Match fehlschlägt)
"a[role='button']._42ft._42fu.layerCancel", # Spezifische Klassen
"a:has-text('OK')", # Allgemeiner Link
"button:has-text('OK')" # Button-Fallback
]
ok_button_clicked = False
for selector in ok_selectors:
try:
if self.automation.browser.is_element_visible(selector, timeout=2000):
self.automation.browser.click_element(selector)
logger.info(f"OK-Button nach Verifikation geklickt: {selector}")
break
except:
if self.automation.browser.is_element_visible(selector, timeout=5000):
logger.info(f"OK-Button gefunden mit: {selector}")
if self.automation.browser.click_element(selector, timeout=2000):
logger.info(f"OK-Button nach Verifikation erfolgreich geklickt: {selector}")
ok_button_clicked = True
break
else:
logger.warning(f"OK-Button Click fehlgeschlagen für: {selector}")
except Exception as e:
logger.debug(f"Fehler beim OK-Button Click mit {selector}: {e}")
continue
if ok_button_clicked:
# Warte nach OK-Click auf finale Navigation
self.automation.human_behavior.wait_for_page_load(multiplier=1.5)
else:
logger.warning("OK-Button nach Verifikation nicht gefunden oder Click fehlgeschlagen")
return True
except Exception as e:
logger.error(f"Fehler beim Eingeben des Verifikationscodes: {e}")
return False
def _handle_final_dialogs(self) -> bool:
"""
Behandelt finale Dialogs/Layer nach Cookie-Consent.
Z.B. "Schließen"-Button.
Returns:
bool: True wenn Dialog behandelt wurde
"""
try:
self.automation.human_behavior.random_delay(0.5, 1.0)
close_button_selectors = [
"button:has-text('Schließen')",
"button:has-text('Close')",
self.selectors.DIALOG_CLOSE_BUTTON, # div[aria-label='Schließen']
self.selectors.DIALOG_CLOSE_BUTTON_EN, # div[aria-label='Close']
"div[role='button']:has-text('Schließen')",
"div[role='button']:has-text('Close')",
"a[role='button']:has-text('Schließen')",
"a[role='button']:has-text('Close')"
]
for selector in close_button_selectors:
try:
if self.automation.browser.is_element_visible(selector, timeout=2000):
if self.automation.browser.click_element(selector, timeout=1000):
logger.info(f"Finaler Dialog geschlossen mit: {selector}")
self.automation._send_log_update("Schließe Dialog...")
# Kurze Pause nach Schließen
self.automation.human_behavior.random_delay(0.5, 1.0)
return True
except Exception as e:
logger.debug(f"Fehler beim Schließen-Button mit {selector}: {e}")
continue
logger.debug("Kein finaler Dialog gefunden")
return False
except Exception as e:
logger.error(f"Fehler beim Behandeln finaler Dialogs: {e}")
return False
def _generate_username_from_email(self, email: str, first_name: str = "", last_name: str = "") -> str:
"""
Generiert einen Username aus der E-Mail-Adresse.
Facebook gibt keinen Username während der Registrierung zurück.
Mit Fallback-Strategien falls E-Mail ungültig ist.
Args:
email: E-Mail-Adresse
first_name: Vorname als Fallback
last_name: Nachname als Fallback
Returns:
str: Generierter Username (GARANTIERT nicht leer!)
"""
try:
# Strategie 1: Aus E-Mail generieren
if email and "@" in email:
# Extrahiere Teil vor @
username_part = email.split("@")[0]
# Ersetze Punkte durch Underscores
username = username_part.replace(".", "_")
# Stelle sicher, dass es gültige Zeichen sind
import re
username = re.sub(r'[^a-zA-Z0-9_]', '_', username)
if username and len(username) >= 3: # Mindestens 3 Zeichen
logger.debug(f"Username aus E-Mail generiert: {email} -> {username}")
return username
# Strategie 2: Aus Vor- und Nachnamen generieren
if first_name and last_name:
import re
clean_first = re.sub(r'[^a-zA-Z0-9]', '', first_name.lower())
clean_last = re.sub(r'[^a-zA-Z0-9]', '', last_name.lower())
if clean_first and clean_last:
import random
username = f"{clean_first}_{clean_last}_{random.randint(100, 999)}"
logger.info(f"Username aus Namen generiert (Fallback): {username}")
return username
# Strategie 3: Timestamp-basierter Name (letzter Fallback)
import time
import random
timestamp = int(time.time() * 1000) % 1000000 # Letzte 6 Stellen
random_suffix = random.randint(100, 999)
username = f"fb_user_{timestamp}_{random_suffix}"
logger.warning(f"Username mit Timestamp generiert (Notfall-Fallback): {username}")
return username
except Exception as e:
# ABSOLUTER NOTFALL: Garantiere IMMER einen Username
import time
import random
timestamp = int(time.time() * 1000) % 1000000
random_suffix = random.randint(100, 999)
emergency_username = f"fb_emergency_{timestamp}_{random_suffix}"
logger.error(f"Fehler beim Generieren des Usernames: {e}")
logger.error(f"Notfall-Username generiert: {emergency_username}")
return emergency_username
def _check_registration_success(self) -> bool:
"""
Überprüft ob die Registrierung erfolgreich war.
Returns:
bool: True bei Erfolg
"""
try:
# Warte auf finale Navigation
self.automation.human_behavior.wait_for_page_load(multiplier=2.0)
# Screenshot
self.automation._take_screenshot("registration_final")
# Prüfe URL
current_url = self.automation.browser.page.url
logger.info(f"Finale URL: {current_url}")
# WICHTIG: Prüfe ZUERST auf Zwischen-Schritte die KEINE Erfolgs-Indikatoren sind
intermediate_patterns = [
"privacy/consent",
"user_cookie_choice",
"confirmemail"
]
for pattern in intermediate_patterns:
if pattern in current_url:
logger.info(f"Zwischen-Schritt erkannt (noch nicht fertig): {pattern}")
return False # Noch nicht erfolgreich, weitere Schritte nötig
# Erfolgs-URLs
success_patterns = [
"facebook.com/?",
@ -847,12 +1032,12 @@ class FacebookRegistration:
"welcome",
"onboarding"
]
for pattern in success_patterns:
if pattern in current_url:
logger.info(f"Registrierung erfolgreich (URL-Pattern: {pattern})")
return True
# Prüfe auf Erfolgs-Indikatoren
for indicator in self.selectors.SUCCESS_INDICATORS:
if self.automation.browser.is_element_visible(indicator, timeout=2000):