Files
AccountForger-neuerUpload/social_networks/tiktok/tiktok_login.py
Claude Project Manager 04585e95b6 Initial commit
2025-08-01 23:50:28 +02:00

825 Zeilen
34 KiB
Python

"""
TikTok-Login - Klasse für die Anmeldefunktionalität bei TikTok
"""
import time
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_login")
class TikTokLogin:
"""
Klasse für die Anmeldung bei TikTok-Konten.
Enthält alle Methoden für den Login-Prozess.
"""
def __init__(self, automation):
"""
Initialisiert die TikTok-Login-Funktionalität.
Args:
automation: Referenz auf die Hauptautomatisierungsklasse
"""
self.automation = automation
# Browser wird direkt von automation verwendet
self.selectors = TikTokSelectors()
self.workflow = TikTokWorkflow.get_login_workflow()
logger.debug("TikTok-Login initialisiert")
def login_account(self, username_or_email: str, password: str, **kwargs) -> Dict[str, Any]:
"""
Führt den Login-Prozess für ein TikTok-Konto durch.
Args:
username_or_email: Benutzername oder E-Mail-Adresse
password: Passwort
**kwargs: Weitere optionale Parameter
Returns:
Dict[str, Any]: Ergebnis des Logins mit Status
"""
# Browser wird direkt von automation verwendet
# Validiere die Eingaben
if not self._validate_login_inputs(username_or_email, password):
return {
"success": False,
"error": "Ungültige Login-Eingaben",
"stage": "input_validation"
}
# Account-Daten für die Anmeldung
account_data = {
"username": username_or_email,
"password": password,
"handle_2fa": kwargs.get("handle_2fa", False),
"two_factor_code": kwargs.get("two_factor_code"),
"skip_save_login": kwargs.get("skip_save_login", True)
}
logger.info(f"Starte TikTok-Login für {username_or_email}")
try:
# 1. Zur Login-Seite navigieren
if not self._navigate_to_login_page():
return {
"success": False,
"error": "Konnte nicht zur Login-Seite navigieren",
"stage": "navigation"
}
# 2. Cookie-Banner behandeln
self._handle_cookie_banner()
# 3. Login-Formular ausfüllen
if not self._fill_login_form(account_data):
return {
"success": False,
"error": "Fehler beim Ausfüllen des Login-Formulars",
"stage": "login_form"
}
# 4. Auf 2FA prüfen und behandeln, falls nötig
needs_2fa, two_fa_error = self._check_needs_two_factor_auth()
if needs_2fa:
if not account_data["handle_2fa"]:
return {
"success": False,
"error": "Zwei-Faktor-Authentifizierung erforderlich, aber nicht aktiviert",
"stage": "two_factor_required"
}
# 2FA behandeln
if not self._handle_two_factor_auth(account_data["two_factor_code"]):
return {
"success": False,
"error": "Fehler bei der Zwei-Faktor-Authentifizierung",
"stage": "two_factor_auth"
}
# 5. Benachrichtigungserlaubnis-Dialog behandeln
self._handle_notifications_prompt()
# 6. Erfolgreichen Login überprüfen
if not self._check_login_success():
error_message = self._get_login_error()
return {
"success": False,
"error": f"Login fehlgeschlagen: {error_message or 'Unbekannter Fehler'}",
"stage": "login_check"
}
# Login erfolgreich
logger.info(f"TikTok-Login für {username_or_email} erfolgreich")
return {
"success": True,
"stage": "completed",
"username": username_or_email
}
except Exception as e:
error_msg = f"Unerwarteter Fehler beim TikTok-Login: {str(e)}"
logger.error(error_msg, exc_info=True)
return {
"success": False,
"error": error_msg,
"stage": "exception"
}
def _validate_login_inputs(self, username_or_email: str, password: str) -> bool:
"""
Validiert die Eingaben für den Login.
Args:
username_or_email: Benutzername oder E-Mail-Adresse
password: Passwort
Returns:
bool: True wenn alle Eingaben gültig sind, False sonst
"""
if not username_or_email or len(username_or_email) < 3:
logger.error("Ungültiger Benutzername oder E-Mail")
return False
if not password or len(password) < 6:
logger.error("Ungültiges Passwort")
return False
return True
def _navigate_to_login_page(self) -> bool:
"""
Navigiert zur TikTok-Login-Seite über die Explore-Seite.
Returns:
bool: True bei Erfolg, False bei Fehler
"""
try:
# Zur Explore-Seite navigieren
logger.info("Navigiere zur TikTok Explore-Seite")
self.automation.browser.navigate_to(TikTokSelectors.EXPLORE_URL)
# Warten, bis die Seite geladen ist
self.automation.human_behavior.wait_for_page_load()
# Screenshot erstellen
self.automation._take_screenshot("tiktok_explore_page")
# Login-Button auf der Explore-Seite suchen und klicken
logger.info("Suche Anmelden-Button auf Explore-Seite")
login_button_selectors = [
"button#header-login-button",
"button.TUXButton--primary",
"button:has-text('Anmelden')",
TikTokSelectors.LOGIN_BUTTON_HEADER,
"button[class*='StyledLeftSidePrimaryButton']"
]
button_clicked = False
for selector in login_button_selectors:
logger.debug(f"Versuche Login-Button: {selector}")
if self.automation.browser.is_element_visible(selector, timeout=2000):
# Kurz warten vor dem Klick
self.automation.human_behavior.random_delay(0.5, 1.0)
if self.automation.browser.click_element(selector):
button_clicked = True
logger.info(f"Anmelden-Button erfolgreich geklickt: {selector}")
break
if not button_clicked:
logger.error("Konnte keinen Anmelden-Button auf der Explore-Seite finden")
self.automation._take_screenshot("no_login_button_found")
return False
# Warten, bis der Login-Dialog erscheint
logger.info("Warte auf Login-Dialog")
self.automation.human_behavior.random_delay(2.0, 3.0)
# Prüfen, ob der Login-Dialog sichtbar ist
dialog_visible = False
dialog_selectors = [
"div[role='dialog']",
TikTokSelectors.LOGIN_DIALOG,
"div[class*='login-modal']",
"div[class*='DivLoginContainer']"
]
for dialog_selector in dialog_selectors:
if self.automation.browser.is_element_visible(dialog_selector, timeout=5000):
dialog_visible = True
logger.info(f"Login-Dialog erschienen: {dialog_selector}")
break
if not dialog_visible:
logger.error("Login-Dialog ist nach 5 Sekunden nicht erschienen")
self.automation._take_screenshot("no_login_dialog")
return False
# Screenshot vom geöffneten Dialog
self.automation._take_screenshot("login_dialog_opened")
logger.info("Erfolgreich zum Login-Dialog navigiert")
return True
except Exception as e:
logger.error(f"Fehler beim Navigieren zur Login-Seite: {e}")
return False
def _handle_cookie_banner(self) -> bool:
"""
Behandelt den Cookie-Banner, falls angezeigt.
Akzeptiert IMMER Cookies für vollständiges Session-Management beim Login.
Returns:
bool: True wenn Banner behandelt wurde oder nicht existiert, False bei Fehler
"""
# Cookie-Dialog-Erkennung
if self.automation.browser.is_element_visible(TikTokSelectors.COOKIE_DIALOG, timeout=2000):
logger.info("Cookie-Banner erkannt - akzeptiere alle Cookies für Session-Management")
# Akzeptieren-Button suchen und klicken (PRIMÄR für Login)
accept_success = self.automation.ui_helper.click_button_fuzzy(
TikTokSelectors.get_button_texts("accept_cookies"),
TikTokSelectors.COOKIE_ACCEPT_BUTTON
)
if accept_success:
logger.info("Cookie-Banner erfolgreich akzeptiert - Session-Cookies werden gespeichert")
self.automation.human_behavior.random_delay(0.5, 1.5)
return True
else:
logger.warning("Konnte Cookie-Banner nicht akzeptieren, versuche alternativen Akzeptieren-Button")
# Alternative Akzeptieren-Selektoren versuchen
alternative_accept_selectors = [
"//button[contains(text(), 'Alle akzeptieren')]",
"//button[contains(text(), 'Accept All')]",
"//button[contains(text(), 'Zulassen')]",
"//button[contains(text(), 'Allow All')]",
"//button[contains(@aria-label, 'Accept')]",
"[data-testid='accept-all-button']"
]
for selector in alternative_accept_selectors:
if self.automation.browser.is_element_visible(selector, timeout=1000):
if self.automation.browser.click_element(selector):
logger.info("Cookie-Banner mit alternativem Selector akzeptiert")
self.automation.human_behavior.random_delay(0.5, 1.5)
return True
logger.error("Konnte Cookie-Banner nicht akzeptieren - Session-Management könnte beeinträchtigt sein")
return False
else:
logger.debug("Kein Cookie-Banner erkannt")
return True
def _fill_login_form(self, account_data: Dict[str, Any]) -> bool:
"""
Füllt das Login-Formular aus und sendet es ab.
Args:
account_data: Account-Daten für den Login
Returns:
bool: True bei Erfolg, False bei Fehler
"""
try:
# 1. E-Mail/Telefon-Login-Option auswählen
logger.info("Klicke auf 'Telefon-Nr./E-Mail/Anmeldename nutzen'")
# Warte kurz, damit Dialog vollständig geladen ist
self.automation.human_behavior.random_delay(1.0, 1.5)
# Selektoren für die Option - spezifischer für E-Mail/Telefon
phone_email_selectors = [
"div[data-e2e='channel-item']:has(p:has-text('Telefon-Nr./E-Mail/Anmeldename nutzen'))",
"div[role='link']:has-text('Telefon-Nr./E-Mail/Anmeldename nutzen')",
"//div[@data-e2e='channel-item'][.//p[contains(text(), 'Telefon-Nr./E-Mail/Anmeldename nutzen')]]",
"div.css-17hparj-DivBoxContainer:has-text('Telefon-Nr./E-Mail/Anmeldename nutzen')",
"//div[contains(@class, 'DivBoxContainer') and contains(., 'Telefon-Nr./E-Mail/Anmeldename nutzen')]"
]
email_phone_clicked = False
for selector in phone_email_selectors:
logger.debug(f"Versuche E-Mail/Telefon-Selektor: {selector}")
if self.automation.browser.is_element_visible(selector, timeout=2000):
# Kurz warten vor dem Klick
self.automation.human_behavior.random_delay(0.3, 0.5)
if self.automation.browser.click_element(selector):
email_phone_clicked = True
logger.info(f"E-Mail/Telefon-Option erfolgreich geklickt: {selector}")
break
else:
logger.warning(f"Klick fehlgeschlagen für Selektor: {selector}")
if not email_phone_clicked:
logger.error("Konnte 'Telefon-Nr./E-Mail/Anmeldename nutzen' nicht klicken")
self.automation._take_screenshot("phone_email_option_not_found")
return False
self.automation.human_behavior.random_delay(1.0, 2.0)
# 2. "Mit E-Mail-Adresse oder Benutzernamen anmelden" Link klicken
logger.info("Klicke auf 'Mit E-Mail-Adresse oder Benutzernamen anmelden'")
email_link_selectors = [
"a[href='/login/phone-or-email/email']",
"a.css-1mgli76-ALink-StyledLink",
"a:has-text('Mit E-Mail-Adresse oder Benutzernamen anmelden')",
"//a[contains(text(), 'Mit E-Mail-Adresse oder Benutzernamen anmelden')]"
]
email_login_clicked = False
for selector in email_link_selectors:
if self.automation.browser.is_element_visible(selector, timeout=2000):
if self.automation.browser.click_element(selector):
email_login_clicked = True
logger.info(f"E-Mail-Login-Link geklickt: {selector}")
break
if not email_login_clicked:
logger.error("Konnte E-Mail-Login-Link nicht klicken")
self.automation._take_screenshot("email_login_link_not_found")
return False
self.automation.human_behavior.random_delay(1.5, 2.5)
# 3. E-Mail/Benutzername eingeben (Character-by-Character)
logger.info(f"Gebe E-Mail/Benutzername ein: {account_data['username']}")
# Warte bis Formular geladen ist
self.automation.human_behavior.random_delay(0.5, 1.0)
username_selectors = [
"input[name='username']",
"input[placeholder='E-Mail-Adresse oder Benutzername']",
"input.css-11to27l-InputContainer[name='username']",
"input[type='text'][autocomplete='webauthn']"
]
username_success = False
for selector in username_selectors:
if self.automation.browser.is_element_visible(selector, timeout=2000):
username_success = self._fill_username_field_character_by_character(selector, account_data["username"])
if username_success:
logger.info(f"Benutzername erfolgreich eingegeben mit Selektor: {selector}")
break
if not username_success:
logger.error("Konnte Benutzername-Feld nicht ausfüllen")
self.automation._take_screenshot("username_field_not_found")
return False
self.automation.human_behavior.random_delay(0.5, 1.0)
# 4. Passwort eingeben (mit Character-by-Character für bessere Kompatibilität)
logger.info("Gebe Passwort ein")
password_selectors = [
"input[type='password']",
"input[placeholder='Passwort']",
"input.css-wv3bkt-InputContainer[type='password']",
"input[autocomplete='new-password']"
]
password_success = False
for selector in password_selectors:
if self.automation.browser.is_element_visible(selector, timeout=2000):
# Verwende character-by-character Eingabe
password_success = self._fill_password_field_character_by_character(selector, account_data["password"])
if password_success:
logger.info(f"Passwort erfolgreich eingegeben mit Selektor: {selector}")
break
if not password_success:
logger.error("Konnte Passwort-Feld nicht ausfüllen")
self.automation._take_screenshot("password_field_not_found")
return False
self.automation.human_behavior.random_delay(1.0, 2.0)
# Screenshot vorm Absenden
self.automation._take_screenshot("login_form_filled")
# 5. Prüfe ob Login-Button aktiviert ist
logger.info("Prüfe Login-Button Status")
login_button_selectors = [
"button[data-e2e='login-button']",
"button[type='submit'][data-e2e='login-button']",
"button.css-11sviba-Button-StyledButton",
"button:has-text('Anmelden')"
]
button_ready = False
active_selector = None
for selector in login_button_selectors:
if self.automation.browser.is_element_visible(selector, timeout=2000):
element = self.automation.browser.page.locator(selector).first
is_disabled = element.get_attribute("disabled")
if not is_disabled:
button_ready = True
active_selector = selector
logger.info(f"Login-Button ist aktiviert: {selector}")
break
else:
logger.warning(f"Login-Button ist disabled: {selector}")
if not button_ready:
logger.warning("Login-Button ist nicht bereit, warte zusätzlich")
self.automation.human_behavior.random_delay(2.0, 3.0)
# Nochmal prüfen
for selector in login_button_selectors:
if self.automation.browser.is_element_visible(selector, timeout=1000):
element = self.automation.browser.page.locator(selector).first
is_disabled = element.get_attribute("disabled")
if not is_disabled:
button_ready = True
active_selector = selector
break
# 6. Login-Button klicken
logger.info("Klicke auf Anmelden-Button")
if button_ready and active_selector:
if self.automation.browser.click_element(active_selector):
logger.info(f"Login-Button erfolgreich geklickt: {active_selector}")
else:
logger.error("Klick auf Login-Button fehlgeschlagen")
return False
else:
logger.error("Konnte keinen aktivierten Login-Button finden")
self.automation._take_screenshot("no_active_login_button")
return False
# Nach dem Absenden warten
self.automation.human_behavior.wait_for_page_load(multiplier=2.0)
# Überprüfen, ob es eine Fehlermeldung gab
error_message = self._get_login_error()
if error_message:
logger.error(f"Login-Fehler erkannt: {error_message}")
return False
logger.info("Login-Formular erfolgreich ausgefüllt und abgesendet")
return True
except Exception as e:
logger.error(f"Fehler beim Ausfüllen des Login-Formulars: {e}")
return False
def _fill_username_field_character_by_character(self, selector: str, username: str) -> bool:
"""
Füllt das Benutzername-Feld Zeichen für Zeichen aus.
Args:
selector: CSS-Selektor für das Username-Feld
username: Der einzugebende Benutzername
Returns:
bool: True bei Erfolg, False bei Fehler
"""
try:
element = self.automation.browser.page.locator(selector).first
if not element.is_visible():
return False
logger.info("Verwende Character-by-Character Eingabe für Benutzername-Feld")
# Fokussiere und lösche das Feld
element.click()
self.automation.human_behavior.random_delay(0.1, 0.2)
# Lösche existierenden Inhalt
element.select_text()
element.press("Delete")
self.automation.human_behavior.random_delay(0.1, 0.2)
# Tippe jeden Buchstaben einzeln
import random
for i, char in enumerate(username):
element.type(char, delay=random.randint(50, 150)) # Zufällige Tippgeschwindigkeit
# Nach jedem 4. Zeichen eine kleine Pause (simuliert echtes Tippen)
if (i + 1) % 4 == 0:
self.automation.human_behavior.random_delay(0.1, 0.3)
# Fokus verlassen
self.automation.human_behavior.random_delay(0.2, 0.4)
element.press("Tab")
logger.info(f"Benutzername character-by-character eingegeben: {len(username)} Zeichen")
return True
except Exception as e:
logger.error(f"Fehler bei Character-by-Character Benutzername-Eingabe: {e}")
return False
def _fill_password_field_character_by_character(self, selector: str, password: str) -> bool:
"""
Füllt das Passwort-Feld Zeichen für Zeichen aus, um React's State korrekt zu aktualisieren.
Args:
selector: CSS-Selektor für das Passwort-Feld
password: Das einzugebende Passwort
Returns:
bool: True bei Erfolg, False bei Fehler
"""
try:
element = self.automation.browser.page.locator(selector).first
if not element.is_visible():
return False
logger.info("Verwende Character-by-Character Eingabe für Passwort-Feld")
# Fokussiere und lösche das Feld
element.click()
self.automation.human_behavior.random_delay(0.1, 0.2)
# Lösche existierenden Inhalt
element.select_text()
element.press("Delete")
self.automation.human_behavior.random_delay(0.1, 0.2)
# Tippe jeden Buchstaben einzeln
import random
for i, char in enumerate(password):
element.type(char, delay=random.randint(50, 150)) # Zufällige Tippgeschwindigkeit
# Nach jedem 3. Zeichen eine kleine Pause (simuliert echtes Tippen)
if (i + 1) % 3 == 0:
self.automation.human_behavior.random_delay(0.1, 0.3)
# Fokus verlassen, um Validierung zu triggern
self.automation.human_behavior.random_delay(0.2, 0.4)
element.press("Tab")
logger.info(f"Passwort character-by-character eingegeben: {len(password)} Zeichen")
return True
except Exception as e:
logger.error(f"Fehler bei Character-by-Character Passwort-Eingabe: {e}")
return False
def _get_login_error(self) -> Optional[str]:
"""
Überprüft, ob eine Login-Fehlermeldung angezeigt wird.
Returns:
Optional[str]: Fehlermeldung oder None, wenn keine gefunden wurde
"""
try:
# Auf Fehlermeldungen prüfen
error_selectors = [
TikTokSelectors.ERROR_MESSAGE,
"p[class*='error']",
"div[role='alert']",
"div[class*='error']",
"div[class*='Error']"
]
for selector in error_selectors:
error_element = self.automation.browser.wait_for_selector(selector, timeout=2000)
if error_element:
error_text = error_element.text_content()
if error_text and len(error_text.strip()) > 0:
return error_text.strip()
# Wenn keine spezifische Fehlermeldung gefunden wurde, nach bekannten Fehlermustern suchen
error_texts = [
"Falsches Passwort",
"Benutzername nicht gefunden",
"incorrect password",
"username you entered doesn't belong",
"please wait a few minutes",
"try again later",
"Bitte warte einige Minuten",
"versuche es später noch einmal"
]
page_content = self.automation.browser.page.content()
for error_text in error_texts:
if error_text.lower() in page_content.lower():
return f"Erkannter Fehler: {error_text}"
return None
except Exception as e:
logger.error(f"Fehler beim Prüfen auf Login-Fehler: {e}")
return None
def _check_needs_two_factor_auth(self) -> Tuple[bool, Optional[str]]:
"""
Überprüft, ob eine Zwei-Faktor-Authentifizierung erforderlich ist.
Returns:
Tuple[bool, Optional[str]]: (2FA erforderlich, Fehlermeldung falls vorhanden)
"""
try:
# Nach 2FA-Indikatoren suchen
two_fa_selectors = [
"input[name='verificationCode']",
"input[placeholder*='code']",
"input[placeholder*='Code']",
"div[class*='verification-code']",
"div[class*='two-factor']"
]
for selector in two_fa_selectors:
if self.automation.browser.is_element_visible(selector, timeout=2000):
logger.info("Zwei-Faktor-Authentifizierung erforderlich")
return True, None
# Texte, die auf 2FA hinweisen
two_fa_indicators = [
"Verifizierungscode",
"Verification code",
"Sicherheitscode",
"Security code",
"zwei-faktor",
"two-factor",
"2FA"
]
# Seiteninhalt durchsuchen
page_content = self.automation.browser.page.content().lower()
for indicator in two_fa_indicators:
if indicator.lower() in page_content:
logger.info(f"Zwei-Faktor-Authentifizierung erkannt durch Text: {indicator}")
return True, None
return False, None
except Exception as e:
logger.error(f"Fehler beim Prüfen auf 2FA: {e}")
return False, f"Fehler bei der 2FA-Erkennung: {str(e)}"
def _handle_two_factor_auth(self, two_factor_code: Optional[str] = None) -> bool:
"""
Behandelt die Zwei-Faktor-Authentifizierung.
Args:
two_factor_code: Optional vorhandener 2FA-Code
Returns:
bool: True bei Erfolg, False bei Fehler
"""
try:
# Screenshot erstellen
self.automation._take_screenshot("two_factor_auth")
# 2FA-Eingabefeld finden
two_fa_selectors = [
"input[name='verificationCode']",
"input[placeholder*='code']",
"input[placeholder*='Code']"
]
two_fa_field = None
for selector in two_fa_selectors:
element = self.automation.browser.wait_for_selector(selector, timeout=2000)
if element:
two_fa_field = selector
break
if not two_fa_field:
logger.error("Konnte 2FA-Eingabefeld nicht finden")
return False
# Wenn kein Code bereitgestellt wurde, Benutzer auffordern
if not two_factor_code:
logger.warning("Kein 2FA-Code bereitgestellt, kann nicht fortfahren")
return False
# 2FA-Code eingeben
code_success = self.automation.browser.fill_form_field(two_fa_field, two_factor_code)
if not code_success:
logger.error("Konnte 2FA-Code nicht eingeben")
return False
self.automation.human_behavior.random_delay(1.0, 2.0)
# Bestätigen-Button finden und klicken
confirm_button_selectors = [
"button[type='submit']",
"//button[contains(text(), 'Bestätigen')]",
"//button[contains(text(), 'Confirm')]",
"//button[contains(text(), 'Verify')]"
]
confirm_clicked = False
for selector in confirm_button_selectors:
if self.automation.browser.is_element_visible(selector, timeout=1000):
if self.automation.browser.click_element(selector):
confirm_clicked = True
break
if not confirm_clicked:
# Alternative: Mit Tastendruck bestätigen
self.automation.browser.page.keyboard.press("Enter")
logger.info("Enter-Taste gedrückt, um 2FA zu bestätigen")
# Warten nach der Bestätigung
self.automation.human_behavior.wait_for_page_load(multiplier=1.5)
# Überprüfen, ob 2FA erfolgreich war
still_on_2fa = self._check_needs_two_factor_auth()[0]
if still_on_2fa:
# Prüfen, ob Fehlermeldung angezeigt wird
error_message = self._get_login_error()
if error_message:
logger.error(f"2FA-Fehler: {error_message}")
else:
logger.error("2FA fehlgeschlagen, immer noch auf 2FA-Seite")
return False
logger.info("Zwei-Faktor-Authentifizierung erfolgreich")
return True
except Exception as e:
logger.error(f"Fehler bei der Zwei-Faktor-Authentifizierung: {e}")
return False
def _handle_notifications_prompt(self) -> bool:
"""
Behandelt den Benachrichtigungen-Dialog.
Returns:
bool: True bei Erfolg, False bei Fehler
"""
try:
# Nach "Nicht jetzt"-Button suchen
not_now_selectors = [
"//button[contains(text(), 'Nicht jetzt')]",
"//button[contains(text(), 'Not now')]",
"//button[contains(text(), 'Skip')]",
"//button[contains(text(), 'Später')]",
"//button[contains(text(), 'Later')]"
]
for selector in not_now_selectors:
if self.automation.browser.is_element_visible(selector, timeout=3000):
if self.automation.browser.click_element(selector):
logger.info("Benachrichtigungen-Dialog übersprungen")
self.automation.human_behavior.random_delay(0.5, 1.0)
return True
# Wenn kein Button gefunden wurde, ist der Dialog wahrscheinlich nicht vorhanden
logger.debug("Kein Benachrichtigungen-Dialog erkannt")
return True
except Exception as e:
logger.warning(f"Fehler beim Behandeln des Benachrichtigungen-Dialogs: {e}")
# Dies ist nicht kritisch, daher geben wir trotzdem True zurück
return True
def _check_login_success(self) -> bool:
"""
Überprüft, ob der Login erfolgreich war.
Returns:
bool: True wenn erfolgreich, False sonst
"""
try:
# Warten nach dem Login
self.automation.human_behavior.wait_for_page_load(multiplier=1.5)
# Screenshot erstellen
self.automation._take_screenshot("login_final")
# Erfolg anhand verschiedener Indikatoren prüfen
success_indicators = TikTokSelectors.SUCCESS_INDICATORS
for indicator in success_indicators:
if self.automation.browser.is_element_visible(indicator, timeout=2000):
logger.info(f"Login-Erfolgsindikator gefunden: {indicator}")
return True
# Alternativ prüfen, ob wir auf der TikTok-Startseite sind
current_url = self.automation.browser.page.url
if "tiktok.com" in current_url and "/login" not in current_url:
logger.info(f"Login-Erfolg basierend auf URL: {current_url}")
return True
# Prüfen, ob immer noch auf der Login-Seite
if "/login" in current_url or self.automation.browser.is_element_visible(TikTokSelectors.LOGIN_EMAIL_FIELD, timeout=1000):
logger.warning("Immer noch auf der Login-Seite, Login fehlgeschlagen")
return False
logger.warning("Keine Login-Erfolgsindikatoren gefunden")
return False
except Exception as e:
logger.error(f"Fehler beim Überprüfen des Login-Erfolgs: {e}")
return False