""" TikTok-Workflow - Definiert die Schritte für die TikTok-Anmeldung und -Registrierung """ from typing import Dict, List, Any, Optional, Tuple import re from utils.text_similarity import TextSimilarity from utils.logger import setup_logger # Konfiguriere Logger logger = setup_logger("tiktok_workflow") class TikTokWorkflow: """ Definiert die Workflow-Schritte für verschiedene TikTok-Aktionen wie Registrierung, Anmeldung und Verifizierung. """ # Text-Ähnlichkeits-Threshold für Fuzzy-Matching SIMILARITY_THRESHOLD = 0.7 # Initialisiere TextSimilarity für Matching text_similarity = TextSimilarity(default_threshold=SIMILARITY_THRESHOLD) # Mögliche alternative Texte für verschiedene UI-Elemente TEXT_ALTERNATIVES = { "email": ["E-Mail", "Email", "E-mail", "Mail", "email"], "phone": ["Telefon", "Telefonnummer", "Phone", "Mobile", "mobile"], "password": ["Passwort", "Password", "pass"], "code": ["Code", "Bestätigungscode", "Verification code", "Sicherheitscode"], "username": ["Benutzername", "Username", "user name"], "submit": ["Registrieren", "Sign up", "Anmelden", "Login", "Log in", "Submit"], "next": ["Weiter", "Next", "Continue", "Fortfahren"], "skip": ["Überspringen", "Skip", "Later", "Später", "Not now", "Nicht jetzt"] } @staticmethod def get_registration_workflow(registration_method: str = "email") -> List[Dict[str, Any]]: """ Gibt den Workflow für die TikTok-Registrierung zurück. Args: registration_method: "email" oder "phone" Returns: List[Dict[str, Any]]: Liste von Workflow-Schritten """ # Basisschritte für beide Methoden common_steps = [ { "name": "navigate_to_signup", "description": "Zur TikTok-Startseite navigieren", "url": "https://www.tiktok.com", "wait_for": ["button#header-login-button", "button#top-right-action-bar-login-button"], "fuzzy_match": None }, { "name": "click_login_button", "description": "Anmelden-Button klicken", "action": "click", "target": "button#top-right-action-bar-login-button", "wait_for": ["a[href*='/signup']", "div[role='dialog']"], "fuzzy_match": ["Anmelden", "Sign in", "Log in"] }, { "name": "click_register_link", "description": "Registrieren-Link klicken", "action": "click", "target": "a[href*='/signup']", "wait_for": ["div[data-e2e='channel-item']"], "fuzzy_match": ["Registrieren", "Sign up", "Register"] }, { "name": "click_phone_email_button", "description": "Telefon/E-Mail-Option auswählen", "action": "click", "target": "div[data-e2e='channel-item']", "wait_for": ["a[href*='/signup/phone-or-email/email']", "a[href*='/signup/phone-or-email/phone']"], "fuzzy_match": ["Telefonnummer oder E-Mail-Adresse", "Phone or Email"] } ] # Spezifische Schritte je nach Registrierungsmethode method_steps = [] if registration_method == "email": method_steps.append({ "name": "click_email_registration", "description": "Mit E-Mail registrieren auswählen", "action": "click", "target": "a[href*='/signup/phone-or-email/email']", "wait_for": ["input[placeholder='E-Mail-Adresse']"], "fuzzy_match": ["Mit E-Mail-Adresse registrieren", "Email", "E-Mail"] }) else: # phone method_steps.append({ "name": "click_phone_registration", "description": "Mit Telefonnummer registrieren auswählen", "action": "click", "target": "a[href*='/signup/phone-or-email/phone']", "wait_for": ["input[placeholder='Telefonnummer']"], "fuzzy_match": ["Mit Telefonnummer registrieren", "Phone", "Telefon"] }) # Geburtsdatum-Schritte birthday_steps = [ { "name": "select_birth_month", "description": "Geburtsmonat auswählen", "action": "click", "target": "div.css-1fi2hzv-DivSelectLabel:contains('Monat')", "wait_for": ["div[role='option']"], "fuzzy_match": ["Monat", "Month"] }, { "name": "select_month_option", "description": "Monats-Option auswählen", "action": "select_option", "target": "div[role='option']", "value": "{MONTH_NAME}", "wait_for": [], "fuzzy_match": None }, { "name": "select_birth_day", "description": "Geburtstag auswählen", "action": "click", "target": "div.css-1fi2hzv-DivSelectLabel:contains('Tag')", "wait_for": ["div[role='option']"], "fuzzy_match": ["Tag", "Day"] }, { "name": "select_day_option", "description": "Tags-Option auswählen", "action": "select_option", "target": "div[role='option']", "value": "{DAY}", "wait_for": [], "fuzzy_match": None }, { "name": "select_birth_year", "description": "Geburtsjahr auswählen", "action": "click", "target": "div.css-1fi2hzv-DivSelectLabel:contains('Jahr')", "wait_for": ["div[role='option']"], "fuzzy_match": ["Jahr", "Year"] }, { "name": "select_year_option", "description": "Jahres-Option auswählen", "action": "select_option", "target": "div[role='option']", "value": "{YEAR}", "wait_for": [], "fuzzy_match": None } ] # Formularschritte für E-Mail email_form_steps = [ { "name": "fill_email", "description": "E-Mail-Adresse eingeben", "action": "fill", "target": "input[placeholder='E-Mail-Adresse']", "value": "{EMAIL}", "fuzzy_match": TikTokWorkflow.TEXT_ALTERNATIVES["email"] }, { "name": "fill_password", "description": "Passwort eingeben", "action": "fill", "target": "input[placeholder='Passwort']", "value": "{PASSWORD}", "fuzzy_match": TikTokWorkflow.TEXT_ALTERNATIVES["password"] }, { "name": "click_send_code", "description": "Code senden klicken", "action": "click", "target": "button[data-e2e='send-code-button']", "wait_for": ["input[placeholder*='sechsstelligen Code']"], "fuzzy_match": ["Code senden", "Send code", "Senden"] }, { "name": "fill_verification_code", "description": "Bestätigungscode eingeben", "action": "fill", "target": "input[placeholder*='sechsstelligen Code']", "value": "{VERIFICATION_CODE}", "fuzzy_match": TikTokWorkflow.TEXT_ALTERNATIVES["code"] }, { "name": "click_continue", "description": "Weiter klicken", "action": "click", "target": "button[type='submit']", "wait_for": ["input[placeholder='Benutzername']"], "fuzzy_match": TikTokWorkflow.TEXT_ALTERNATIVES["next"] } ] # Formularschritte für Telefon phone_form_steps = [ { "name": "select_country_code", "description": "Ländervorwahl auswählen", "action": "click", "target": "div[role='combobox']", "wait_for": ["div[role='option']"], "fuzzy_match": None }, { "name": "select_country_option", "description": "Land auswählen", "action": "select_option", "target": "div[role='option']", "value": "{COUNTRY_NAME}", "wait_for": [], "fuzzy_match": None }, { "name": "fill_phone", "description": "Telefonnummer eingeben", "action": "fill", "target": "input[placeholder='Telefonnummer']", "value": "{PHONE}", "fuzzy_match": TikTokWorkflow.TEXT_ALTERNATIVES["phone"] }, { "name": "click_send_code", "description": "Code senden klicken", "action": "click", "target": "button[data-e2e='send-code-button']", "wait_for": ["input[placeholder*='sechsstelligen Code']"], "fuzzy_match": ["Code senden", "Send code", "Senden"] }, { "name": "fill_verification_code", "description": "Bestätigungscode eingeben", "action": "fill", "target": "input[placeholder*='sechsstelligen Code']", "value": "{VERIFICATION_CODE}", "fuzzy_match": TikTokWorkflow.TEXT_ALTERNATIVES["code"] }, { "name": "click_continue", "description": "Weiter klicken", "action": "click", "target": "button[type='submit']", "wait_for": ["input[placeholder='Benutzername']"], "fuzzy_match": TikTokWorkflow.TEXT_ALTERNATIVES["next"] } ] # Benutzername-Schritte username_steps = [ { "name": "fill_username", "description": "Benutzernamen eingeben", "action": "fill", "target": "input[placeholder='Benutzername']", "value": "{USERNAME}", "fuzzy_match": TikTokWorkflow.TEXT_ALTERNATIVES["username"] }, { "name": "click_register", "description": "Registrieren klicken", "action": "click", "target": "button:contains('Registrieren')", "wait_for": ["a[href='/foryou']", "button:contains('Überspringen')"], "fuzzy_match": TikTokWorkflow.TEXT_ALTERNATIVES["submit"] }, { "name": "handle_skip_option", "description": "Optional: Überspringen klicken", "action": "click", "target": "button:contains('Überspringen')", "optional": True, "wait_for": ["a[href='/foryou']"], "fuzzy_match": TikTokWorkflow.TEXT_ALTERNATIVES["skip"] } ] # Vollständigen Workflow zusammenstellen if registration_method == "email": workflow = common_steps + method_steps + birthday_steps + email_form_steps + username_steps else: # phone workflow = common_steps + method_steps + birthday_steps + phone_form_steps + username_steps return workflow @staticmethod def get_login_workflow() -> List[Dict[str, Any]]: """ Gibt den Workflow für die TikTok-Anmeldung zurück. Returns: List[Dict[str, Any]]: Liste von Workflow-Schritten """ login_steps = [ { "name": "navigate_to_login", "description": "Zur TikTok-Startseite navigieren", "url": "https://www.tiktok.com", "wait_for": ["button#header-login-button", "button#top-right-action-bar-login-button"], "fuzzy_match": None }, { "name": "click_login_button", "description": "Anmelden-Button klicken", "action": "click", "target": "button#top-right-action-bar-login-button", "wait_for": ["div[role='dialog']"], "fuzzy_match": ["Anmelden", "Sign in", "Log in"] }, { "name": "click_phone_email_button", "description": "Telefon/E-Mail-Option auswählen", "action": "click", "target": "div[data-e2e='channel-item']", "wait_for": ["input[type='text']"], "fuzzy_match": ["Telefon-Nr./E-Mail/Anmeldename", "Phone or Email"] }, { "name": "fill_login_field", "description": "Benutzername/E-Mail/Telefon eingeben", "action": "fill", "target": "input[type='text']", "value": "{USERNAME_OR_EMAIL}", "fuzzy_match": ["Email", "Benutzername", "Telefon"] }, { "name": "fill_password", "description": "Passwort eingeben", "action": "fill", "target": "input[type='password']", "value": "{PASSWORD}", "fuzzy_match": TikTokWorkflow.TEXT_ALTERNATIVES["password"] }, { "name": "click_login", "description": "Anmelden klicken", "action": "click", "target": "button[type='submit']", "wait_for": ["a[href='/foryou']"], "fuzzy_match": ["Anmelden", "Log in", "Login"] } ] return login_steps @staticmethod def get_verification_workflow() -> List[Dict[str, Any]]: """ Gibt den Workflow für die TikTok-Verifizierung zurück. Returns: List[Dict[str, Any]]: Liste von Workflow-Schritten """ verification_steps = [ { "name": "fill_verification_code", "description": "Bestätigungscode eingeben", "action": "fill", "target": "input[placeholder*='sechsstelligen Code']", "value": "{VERIFICATION_CODE}", "fuzzy_match": TikTokWorkflow.TEXT_ALTERNATIVES["code"] }, { "name": "click_continue", "description": "Weiter klicken", "action": "click", "target": "button[type='submit']", "wait_for": ["input[placeholder='Benutzername']", "a[href='/foryou']"], "fuzzy_match": TikTokWorkflow.TEXT_ALTERNATIVES["next"] } ] return verification_steps @staticmethod def identify_current_step(page_title: str, page_url: str, visible_elements: List[str]) -> str: """ Identifiziert den aktuellen Schritt basierend auf dem Seitentitel, der URL und sichtbaren Elementen. Args: page_title: Titel der Seite page_url: URL der Seite visible_elements: Liste sichtbarer Elemente (Selektoren) Returns: str: Name des identifizierten Schritts """ # Auf der Startseite if "tiktok.com" in page_url and not "/signup" in page_url and not "/login" in page_url: return "navigate_to_signup" # Anmelde-/Registrierungsauswahl if "signup" in page_url or "login" in page_url: if any("channel-item" in element for element in visible_elements): return "click_phone_email_button" # Geburtsdatum if "Monat" in page_title or "Month" in page_title or any("Geburtsdatum" in element for element in visible_elements): return "select_birth_month" # E-Mail-/Telefon-Eingabe if any("E-Mail-Adresse" in element for element in visible_elements): return "fill_email" if any("Telefonnummer" in element for element in visible_elements): return "fill_phone" # Bestätigungscode if any("sechsstelligen Code" in element for element in visible_elements): return "fill_verification_code" # Benutzernamen-Erstellung if any("Benutzername" in element for element in visible_elements): return "fill_username" # Erfolgreiche Anmeldung if "foryou" in page_url or any("Für dich" in element for element in visible_elements): return "logged_in" return "unknown"