""" TikTok-Selektoren - CSS-Selektoren und XPath-Ausdrücke für die TikTok-Automatisierung Mit Text-Matching-Funktionen für robuste Element-Erkennung """ from typing import List, Dict, Optional, Any class TikTokSelectors: """ Zentrale Sammlung aller Selektoren für die TikTok-Automatisierung. Bei Änderungen der TikTok-Webseite müssen nur hier Anpassungen vorgenommen werden. Enthält auch Fuzzy-Text-Matching-Daten für robustere Element-Erkennung. """ # URL-Konstanten BASE_URL = "https://www.tiktok.com" SIGNUP_URL = "https://www.tiktok.com/signup" LOGIN_URL = "https://www.tiktok.com/login" EXPLORE_URL = "https://www.tiktok.com/explore" # Anmelden/Registrieren-Buttons Hauptseite LOGIN_BUTTON = "button#header-login-button" LOGIN_BUTTON_HEADER = "button#header-login-button" LOGIN_BUTTON_CLASS = "button.TUXButton:has-text('Anmelden')" LOGIN_BUTTON_LEFT = "button#header-login-button" LOGIN_BUTTON_RIGHT = "button#top-right-action-bar-login-button" LOGIN_BUTTON_TOP = "button#header-login-button" LOGIN_BUTTON_TOP_RIGHT = "button#top-right-action-bar-login-button" LOGIN_BUTTON_SIDEBAR = "button[data-e2e='login-button-sidebar']" LOGIN_BUTTON_FALLBACK = "//button[contains(text(), 'Anmelden')]" SIGNUP_LINK = "span[data-e2e='bottom-sign-up']" SIGNUP_LINK_FALLBACK = "a[href*='/signup']" # Login-Dialog Optionen LOGIN_DIALOG = "div[role='dialog']" LOGIN_EMAIL_PHONE_OPTION = "div[data-e2e='channel-item']" LOGIN_EMAIL_USERNAME_LINK = "a[href='/login/phone-or-email/email']" # Cookie-Dialog COOKIE_DIALOG = "div[role='dialog'][data-testid='cookie-banner']" COOKIE_ACCEPT_BUTTON = "button[data-testid='accept-all-cookies']" # Registrierungsdialog - Methoden REGISTER_DIALOG_TITLE = "h1:contains('Registrieren')" REGISTER_LINK = "a:contains('Registrieren')" REGISTER_LINK_FALLBACK = "//a[contains(text(), 'Registrieren')]" REGISTRATION_DIALOG = "div[role='dialog']" PHONE_EMAIL_BUTTON = "div[data-e2e='channel-item']" PHONE_EMAIL_OPTION = "div[data-e2e='channel-item']" PHONE_EMAIL_OPTION_FALLBACK = "//div[contains(text(), 'Telefonnummer oder E-Mail')]" EMAIL_OPTION = "a[href*='/signup/phone-or-email/email']" EMAIL_OPTION_FALLBACK = "//a[contains(text(), 'E-Mail')]" PHONE_OPTION = "a[href*='/signup/phone-or-email/phone']" PHONE_OPTION_FALLBACK = "//a[contains(text(), 'Telefon')]" REGISTER_WITH_EMAIL = "a[href*='/signup/phone-or-email/email']" REGISTER_WITH_PHONE = "a[href*='/signup/phone-or-email/phone']" # Geburtsdatum-Selektoren BIRTHDAY_MONTH_DROPDOWN = "select[name='month']" BIRTHDAY_DAY_DROPDOWN = "select[name='day']" BIRTHDAY_YEAR_DROPDOWN = "select[name='year']" BIRTHDAY_MONTH_SELECT = "div.css-1leicpq-DivSelectLabel:contains('Monat')" BIRTHDAY_DAY_SELECT = "div.css-1leicpq-DivSelectLabel:contains('Tag')" BIRTHDAY_YEAR_SELECT = "div.css-1leicpq-DivSelectLabel:contains('Jahr')" BIRTHDAY_DROPDOWN_OPTION = "div[role='option']" BIRTHDAY_DROPDOWN_CONTAINER = "div.css-1leicpq-DivSelectLabel" BIRTHDAY_ARROW = "svg.css-gz151e-StyledArrowTriangleDownLargeFill" # Formularfelder - E-Mail-Registrierung EMAIL_FIELD = "input[placeholder='E-Mail-Adresse']" EMAIL_FIELD_ALT = "input[name='email']" PASSWORD_FIELD = "input[placeholder='Passwort']" PASSWORD_FIELD_ALT = "input[type='password']" VERIFICATION_CODE_FIELD = "input[placeholder*='sechsstelligen Code']" VERIFICATION_CODE_FIELD_ALT = "input[placeholder='Gib den sechsstelligen Code ein']" USERNAME_FIELD = "input[placeholder='Benutzername']" USERNAME_FIELD_ALT = "input[name='new-username']" # Formularfelder - Telefon-Registrierung COUNTRY_CODE_SELECT = "div[role='combobox']" PHONE_FIELD = "input[placeholder='Telefonnummer']" # Buttons SEND_CODE_BUTTON = "button[data-e2e='send-code-button']" SEND_CODE_BUTTON_ALT = "button.css-1jjb4td-ButtonSendCode" SEND_CODE_BUTTON_ALT2 = "button[class*='ButtonSendCode']" SEND_CODE_BUTTON_TEXT = "button:has-text('Code senden')" RESEND_CODE_BUTTON = "button:contains('Code erneut senden')" CONTINUE_BUTTON = "button[type='submit']" CONTINUE_BUTTON_ALT = "button.e1w6iovg0" REGISTER_BUTTON = "button:contains('Registrieren')" REGISTER_BUTTON_ALT = "button[type='submit']:contains('Registrieren')" SKIP_BUTTON = "div:contains('Überspringen')" SKIP_BUTTON_ALT = "div.css-4y1w75-DivTextContainer" SKIP_USERNAME_BUTTON = "button:contains('Überspringen')" # Checkbox NEWSLETTER_CHECKBOX = "input[type='checkbox']" # Login-Formularfelder LOGIN_EMAIL_FIELD = "input[name='username'][placeholder='E-Mail-Adresse oder Benutzername']" LOGIN_EMAIL_FIELD_ALT = "input.tiktok-11to27l-InputContainer[name='username']" LOGIN_PASSWORD_FIELD = "input[type='password'][placeholder='Passwort']" LOGIN_PASSWORD_FIELD_ALT = "input.tiktok-wv3bkt-InputContainer[type='password']" LOGIN_SUBMIT_BUTTON = "button[type='submit'][data-e2e='login-button']" LOGIN_SUBMIT_BUTTON_ALT = "button.tiktok-11sviba-Button-StyledButton[data-e2e='login-button']" # Erfolgs-Indikatoren für Registrierung SUCCESS_INDICATORS = [ "a[href='/foryou']", "a[href='/explore']", "button[data-e2e='profile-icon']", "svg[data-e2e='profile-icon']" ] # Links für Nutzungsbedingungen und Datenschutz TERMS_LINK = "a:contains('Nutzungsbedingungen')" PRIVACY_LINK = "a:contains('Datenschutzerklärung')" # Login-Fehler ERROR_MESSAGE = "span.error-message" LOGIN_ERROR_CONTAINER = "div[class*='error']" # Text-Matching-Parameter für Fuzzy-Matching TEXT_MATCH = { # Formularfelder "form_fields": { "email": ["E-Mail-Adresse", "E-Mail", "Email", "Mail"], "phone": ["Telefonnummer", "Telefon", "Phone", "Mobile"], "password": ["Passwort", "Password"], "verification_code": ["Bestätigungscode", "Code", "Verifizierungscode", "Sicherheitscode"], "username": ["Benutzername", "Username", "Name"] }, # Buttons "buttons": { "send_code": ["Code senden", "Senden", "Send code", "Verification code", "Send"], "continue": ["Weiter", "Continue", "Next", "Fortfahren"], "register": ["Registrieren", "Register", "Sign up", "Konto erstellen"], "skip": ["Überspringen", "Skip", "Later", "Später", "Nicht jetzt"], }, # Fehler-Indikatoren "error_indicators": [ "Fehler", "Error", "Leider", "Ungültig", "Invalid", "Nicht verfügbar", "Fehlgeschlagen", "Problem", "Failed", "Nicht möglich", "Bereits verwendet", "Too many attempts", "Zu viele Versuche", "Rate limit", "Bitte warte" ], # Bestätigungscode-Texte in E-Mails "email_verification_patterns": [ "ist dein Bestätigungscode", "ist dein TikTok-Code", "is your TikTok code", "is your verification code", "Dein Bestätigungscode lautet", "Your verification code is" ], # E-Mail-Betreff-Muster für TikTok "email_subject_patterns": [ "ist dein Bestätigungscode", "is your confirmation code", "TikTok verification code", "TikTok Bestätigungscode" ] } @classmethod def get_field_labels(cls, field_type: str) -> List[str]: """ Gibt die möglichen Bezeichnungen für ein Formularfeld zurück. Args: field_type: Typ des Formularfelds (z.B. "email", "phone") Returns: List[str]: Liste mit möglichen Bezeichnungen """ return cls.TEXT_MATCH["form_fields"].get(field_type, []) @classmethod def get_button_texts(cls, button_type: str) -> List[str]: """ Gibt die möglichen Texte für einen Button zurück. Args: button_type: Typ des Buttons (z.B. "send_code", "continue") Returns: List[str]: Liste mit möglichen Button-Texten """ return cls.TEXT_MATCH["buttons"].get(button_type, []) @classmethod def get_error_indicators(cls) -> List[str]: """ Gibt die möglichen Texte für Fehlerindikatoren zurück. Returns: List[str]: Liste mit möglichen Fehlerindikator-Texten """ return cls.TEXT_MATCH["error_indicators"] @classmethod def get_email_verification_patterns(cls) -> List[str]: """ Gibt die möglichen Texte für Bestätigungscodes in E-Mails zurück. Returns: List[str]: Liste mit möglichen E-Mail-Bestätigungscode-Texten """ return cls.TEXT_MATCH["email_verification_patterns"] @classmethod def get_month_option_selector(cls, month: int) -> str: """Returns selector for month option.""" return f"option[value='{month}']" @classmethod def get_day_option_selector(cls, day: int) -> str: """Returns selector for day option.""" return f"option[value='{day}']" @classmethod def get_year_option_selector(cls, year: int) -> str: """Returns selector for year option.""" return f"option[value='{year}']"