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

458 Zeilen
19 KiB
Python

# social_networks/tiktok/tiktok_verification.py
"""
TikTok-Verifizierung - Klasse für die Verifizierungsfunktionalitä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_verification")
class TikTokVerification:
"""
Klasse für die Verifizierung von TikTok-Konten.
Enthält alle Methoden für den Verifizierungsprozess.
"""
def __init__(self, automation):
"""
Initialisiert die TikTok-Verifizierung.
Args:
automation: Referenz auf die Hauptautomatisierungsklasse
"""
self.automation = automation
# Browser wird direkt von automation verwendet
self.selectors = TikTokSelectors()
self.workflow = TikTokWorkflow.get_verification_workflow()
logger.debug("TikTok-Verifizierung initialisiert")
def verify_account(self, verification_code: str, **kwargs) -> Dict[str, Any]:
"""
Führt den Verifizierungsprozess für ein TikTok-Konto durch.
Args:
verification_code: Der Bestätigungscode
**kwargs: Weitere optionale Parameter
Returns:
Dict[str, Any]: Ergebnis der Verifizierung mit Status
"""
# Browser wird direkt von automation verwendet
# Validiere den Verifizierungscode
if not self._validate_verification_code(verification_code):
return {
"success": False,
"error": "Ungültiger Verifizierungscode",
"stage": "code_validation"
}
try:
# 1. Überprüfen, ob wir auf der Verifizierungsseite sind
if not self._is_on_verification_page():
# Versuche, zur Verifizierungsseite zu navigieren, falls möglich
# Direktnavigation ist jedoch normalerweise nicht möglich
return {
"success": False,
"error": "Nicht auf der Verifizierungsseite",
"stage": "page_check"
}
# 2. Verifizierungscode eingeben und absenden
if not self.enter_and_submit_verification_code(verification_code):
return {
"success": False,
"error": "Fehler beim Eingeben oder Absenden des Verifizierungscodes",
"stage": "code_entry"
}
# 3. Überprüfen, ob die Verifizierung erfolgreich war
success, error_message = self._check_verification_success()
if not success:
return {
"success": False,
"error": f"Verifizierung fehlgeschlagen: {error_message or 'Unbekannter Fehler'}",
"stage": "verification_check"
}
# 4. Zusätzliche Dialoge behandeln
self._handle_post_verification_dialogs()
# Verifizierung erfolgreich
logger.info("TikTok-Verifizierung erfolgreich abgeschlossen")
return {
"success": True,
"stage": "completed"
}
except Exception as e:
error_msg = f"Unerwarteter Fehler bei der TikTok-Verifizierung: {str(e)}"
logger.error(error_msg, exc_info=True)
return {
"success": False,
"error": error_msg,
"stage": "exception"
}
def _validate_verification_code(self, verification_code: str) -> bool:
"""
Validiert den Verifizierungscode.
Args:
verification_code: Der zu validierende Code
Returns:
bool: True wenn der Code gültig ist, False sonst
"""
# Leerer Code
if not verification_code:
logger.error("Verifizierungscode ist leer")
return False
# Code-Format prüfen (normalerweise 6-stellige Zahl)
if not re.match(r"^\d{6}$", verification_code):
logger.warning(f"Verifizierungscode hat unerwartetes Format: {verification_code}")
# Wir geben trotzdem True zurück, da einige Codes andere Formate haben könnten
return True
return True
def _is_on_verification_page(self) -> bool:
"""
Überprüft, ob wir auf der Verifizierungsseite sind.
Returns:
bool: True wenn auf der Verifizierungsseite, False sonst
"""
try:
# Screenshot erstellen
self.automation._take_screenshot("verification_page_check")
# Nach Verifizierungsfeld suchen
verification_selectors = [
TikTokSelectors.VERIFICATION_CODE_FIELD,
"input[placeholder*='Code']",
"input[placeholder*='code']",
"input[placeholder*='sechsstelligen']",
"input[data-e2e='verification-code-input']"
]
for selector in verification_selectors:
if self.automation.browser.is_element_visible(selector, timeout=3000):
logger.info("Auf Verifizierungsseite")
return True
# Textbasierte Erkennung
verification_texts = [
"Bestätigungscode",
"Verification code",
"sechsstelligen Code",
"6-digit code",
"Code senden",
"Send code"
]
page_content = self.automation.browser.page.content().lower()
for text in verification_texts:
if text.lower() in page_content:
logger.info(f"Auf Verifizierungsseite (erkannt durch Text: {text})")
return True
logger.warning("Nicht auf der Verifizierungsseite")
return False
except Exception as e:
logger.error(f"Fehler beim Überprüfen der Verifizierungsseite: {e}")
return False
def enter_and_submit_verification_code(self, verification_code: str) -> bool:
"""
Gibt den Verifizierungscode ein und sendet ihn ab.
Args:
verification_code: Der einzugebende Verifizierungscode
Returns:
bool: True bei Erfolg, False bei Fehler
"""
try:
logger.info(f"Versuche Verifizierungscode einzugeben: {verification_code}")
# Mögliche Selektoren für das Verifizierungscode-Feld
code_field_selectors = [
TikTokSelectors.VERIFICATION_CODE_FIELD,
TikTokSelectors.VERIFICATION_CODE_FIELD_ALT,
"input[placeholder*='Code']",
"input[placeholder*='sechsstelligen Code']",
"input[data-e2e='verification-code-input']"
]
# Versuche, das Feld zu finden und auszufüllen
code_field_found = False
for selector in code_field_selectors:
logger.debug(f"Versuche Selektor: {selector}")
if self.automation.browser.is_element_visible(selector, timeout=2000):
logger.info(f"Codefeld gefunden mit Selektor: {selector}")
if self.automation.browser.fill_form_field(selector, verification_code):
code_field_found = True
logger.info(f"Verifizierungscode eingegeben: {verification_code}")
break
# Versuche es mit der Fuzzy-Matching-Methode, wenn direkte Selektoren fehlschlagen
if not code_field_found:
logger.info("Versuche Fuzzy-Matching für Codefeld")
code_field_found = self.automation.ui_helper.fill_field_fuzzy(
["Bestätigungscode", "Code eingeben", "Verification code", "6-digit code"],
verification_code
)
if not code_field_found:
logger.error("Konnte Verifizierungscode-Feld nicht finden oder ausfüllen")
# Erstelle einen Screenshot zum Debuggen
self.automation._take_screenshot("code_field_not_found")
return False
# Menschliche Verzögerung vor dem Absenden
self.automation.human_behavior.random_delay(1.0, 2.0)
# Screenshot erstellen
self.automation._take_screenshot("verification_code_entered")
# "Weiter"-Button finden und klicken
weiter_button_selectors = [
TikTokSelectors.CONTINUE_BUTTON,
TikTokSelectors.CONTINUE_BUTTON_ALT,
"button[type='submit']",
"button.e1w6iovg0",
"button[data-e2e='next-button']",
"//button[contains(text(), 'Weiter')]"
]
weiter_button_found = False
logger.info("Suche nach Weiter-Button")
for selector in weiter_button_selectors:
logger.debug(f"Versuche Weiter-Button-Selektor: {selector}")
if self.automation.browser.is_element_visible(selector, timeout=2000):
logger.info(f"Weiter-Button gefunden mit Selektor: {selector}")
if self.automation.browser.click_element(selector):
weiter_button_found = True
logger.info("Verifizierungscode-Formular abgesendet")
break
# Versuche es mit der Fuzzy-Matching-Methode, wenn direkte Selektoren fehlschlagen
if not weiter_button_found:
logger.info("Versuche Fuzzy-Matching für Weiter-Button")
weiter_buttons = ["Weiter", "Next", "Continue", "Fertig", "Submit", "Verify", "Senden"]
weiter_button_found = self.automation.ui_helper.click_button_fuzzy(
weiter_buttons
)
if not weiter_button_found:
# Erstelle einen Screenshot zum Debuggen
self.automation._take_screenshot("weiter_button_not_found")
# Versuche es mit Enter-Taste als letzten Ausweg
logger.info("Konnte Weiter-Button nicht finden, versuche Enter-Taste")
self.automation.browser.page.keyboard.press("Enter")
logger.info("Enter-Taste zur Bestätigung des Verifizierungscodes gedrückt")
weiter_button_found = True
# Warten nach dem Absenden
self.automation.human_behavior.wait_for_page_load(multiplier=1.5)
return weiter_button_found
except Exception as e:
logger.error(f"Fehler beim Eingeben und Absenden des Verifizierungscodes: {e}")
return False
def _check_verification_success(self) -> Tuple[bool, Optional[str]]:
"""
Überprüft, ob die Verifizierung erfolgreich war.
Returns:
Tuple[bool, Optional[str]]: (Erfolg, Fehlermeldung falls vorhanden)
"""
try:
# Warten nach der Verifizierung
self.automation.human_behavior.wait_for_page_load(multiplier=1.5)
# Screenshot erstellen
self.automation._take_screenshot("verification_result")
# Immer noch auf der Verifizierungsseite?
still_on_verification = self._is_on_verification_page()
if still_on_verification:
# Fehlermeldung suchen
error_message = self.automation.ui_helper.check_for_error()
if error_message:
logger.error(f"Verifizierungsfehler: {error_message}")
return False, error_message
else:
logger.error("Verifizierung fehlgeschlagen, immer noch auf der Verifizierungsseite")
return False, "Immer noch auf der Verifizierungsseite"
# Prüfe, ob wir zur Benutzernamen-Erstellung weitergeleitet wurden
username_selectors = [
"input[placeholder='Benutzername']",
"input[name='new-username']",
"//input[@placeholder='Benutzername']"
]
for selector in username_selectors:
if self.automation.browser.is_element_visible(selector, timeout=2000):
logger.info("Verifizierung erfolgreich, zur Benutzernamenauswahl weitergeleitet")
return True, None
# Prüfe auf TikTok-Startseite
current_url = self.automation.browser.page.url
if "tiktok.com" in current_url and "/login" not in current_url and "/signup" not in current_url:
logger.info("Verifizierung erfolgreich, jetzt auf der Startseite")
return True, None
# Wenn keine eindeutigen Indikatoren gefunden wurden, aber auch keine Fehler
logger.warning("Keine eindeutigen Erfolgsindikatoren für die Verifizierung gefunden")
return True, None # Wir gehen davon aus, dass es erfolgreich war
except Exception as e:
logger.error(f"Fehler beim Überprüfen des Verifizierungserfolgs: {e}")
return False, f"Fehler bei der Erfolgsprüfung: {str(e)}"
def _handle_post_verification_dialogs(self) -> None:
"""
Behandelt Dialoge, die nach erfolgreicher Verifizierung erscheinen können.
"""
try:
# Liste der möglichen Dialoge und wie man sie überspringt
dialogs_to_handle = [
{
"name": "username_setup",
"skip_texts": ["Überspringen", "Skip"],
"skip_selectors": ["//button[contains(text(), 'Überspringen')]", "//button[contains(text(), 'Skip')]"]
},
{
"name": "interests",
"skip_texts": ["Überspringen", "Skip"],
"skip_selectors": ["//button[contains(text(), 'Überspringen')]", "//button[contains(text(), 'Skip')]"]
},
{
"name": "follow_accounts",
"skip_texts": ["Überspringen", "Skip"],
"skip_selectors": ["//button[contains(text(), 'Überspringen')]", "//button[contains(text(), 'Skip')]"]
},
{
"name": "notifications",
"skip_texts": ["Später", "Nein", "Nicht jetzt", "Later", "No", "Not now"],
"skip_selectors": ["//button[contains(text(), 'Später')]", "//button[contains(text(), 'Not now')]"]
}
]
# Versuche, jeden möglichen Dialog zu behandeln
for dialog in dialogs_to_handle:
self._try_skip_dialog(dialog)
logger.info("Nachverifizierungs-Dialoge behandelt")
except Exception as e:
logger.warning(f"Fehler beim Behandeln der Nachverifizierungs-Dialoge: {e}")
# Nicht kritisch, daher keine Fehlerbehandlung
def _try_skip_dialog(self, dialog: Dict[str, Any]) -> bool:
"""
Versucht, einen bestimmten Dialog zu überspringen.
Args:
dialog: Informationen zum Dialog
Returns:
bool: True wenn Dialog gefunden und übersprungen, False sonst
"""
try:
# Zuerst mit Fuzzy-Matching versuchen
skip_clicked = self.automation.ui_helper.click_button_fuzzy(
dialog["skip_texts"],
threshold=0.7,
timeout=3000
)
if skip_clicked:
logger.info(f"Dialog '{dialog['name']}' mit Fuzzy-Matching übersprungen")
self.automation.human_behavior.random_delay(0.5, 1.0)
return True
# Wenn Fuzzy-Matching fehlschlägt, direkte Selektoren versuchen
for selector in dialog["skip_selectors"]:
if self.automation.browser.is_element_visible(selector, timeout=1000):
if self.automation.browser.click_element(selector):
logger.info(f"Dialog '{dialog['name']}' mit direktem Selektor übersprungen")
self.automation.human_behavior.random_delay(0.5, 1.0)
return True
return False
except Exception as e:
logger.warning(f"Fehler beim Versuch, Dialog '{dialog['name']}' zu überspringen: {e}")
return False
def resend_verification_code(self) -> bool:
"""
Versucht, den Verifizierungscode erneut senden zu lassen.
Returns:
bool: True bei Erfolg, False bei Fehler
"""
try:
# Resend-Button suchen und klicken
resend_selectors = [
"button[data-e2e='send-code-button']",
"//button[contains(text(), 'Code senden')]",
"//button[contains(text(), 'Code erneut senden')]",
"//button[contains(text(), 'Erneut senden')]",
"a[data-e2e='resend-code-link']"
]
for selector in resend_selectors:
if self.automation.browser.is_element_visible(selector, timeout=2000):
if self.automation.browser.click_element(selector):
logger.info("Code erneut angefordert")
self.automation.human_behavior.random_delay(1.0, 2.0)
return True
# Fuzzy-Matching versuchen
resend_texts = ["Code senden", "Code erneut senden", "Erneut senden", "Resend code", "Send again"]
resend_clicked = self.automation.ui_helper.click_button_fuzzy(
resend_texts,
threshold=0.7,
timeout=3000
)
if resend_clicked:
logger.info("Code erneut angefordert (über Fuzzy-Matching)")
self.automation.human_behavior.random_delay(1.0, 2.0)
return True
logger.warning("Konnte keinen 'Code erneut senden'-Button finden")
return False
except Exception as e:
logger.error(f"Fehler beim erneuten Anfordern des Codes: {e}")
return False