# social_networks/x/x_selectors.py """ X (Twitter) Selektoren - Zentrale Sammlung aller CSS-Selektoren für X """ class XSelectors: """ Zentrale Klasse für alle X-spezifischen CSS-Selektoren. Organisiert nach Funktionsbereichen. """ # === ALLGEMEINE SELEKTOREN === COOKIE_ACCEPT_BUTTONS = [ "button:has-text('Accept all')", "button:has-text('Alle akzeptieren')", "button:has-text('Accept')", "button:has-text('Akzeptieren')" ] # === REGISTRIERUNG === REGISTRATION = { # Hauptseite "create_account_button": 'text="Account erstellen"', # Robustester Selektor "create_account_button_en": 'text="Create account"', # Englische Version "create_account_button_alt": 'span:has-text("Account erstellen")', # Alternative "create_account_button_div": 'div[dir="ltr"] >> text="Account erstellen"', # Spezifischer # Formularfelder "name_input": 'input[name="name"]', "email_input": 'input[name="email"]', "phone_input": 'input[name="phone"]', # Geburtsdatum Dropdowns "month_select": 'select#SELECTOR_1', "day_select": 'select#SELECTOR_2', "year_select": 'select#SELECTOR_3', # Buttons "next_button_birthday": 'button[data-testid="ocfSignupNextLink"]', "next_button_settings": 'button[data-testid="ocfSettingsListNextButton"]', "register_button": 'button[data-testid="LoginForm_Login_Button"]', # Verifizierung "verification_code_input": 'input[autocomplete="one-time-code"]', "verification_code_label": 'div:has-text("Verifizierungscode")', # Passwort "password_input": 'input[type="password"]', "password_label": 'div:has-text("Passwort")', # Skip-Buttons "skip_profile_picture": 'button[data-testid="ocfSelectAvatarSkipForNowButton"]', "skip_username": 'button[data-testid="ocfEnterUsernameSkipButton"]', "skip_notifications": 'button:has-text("Vorerst überspringen")', "skip_for_now": 'button:has-text("Nicht jetzt")' } # === LOGIN === LOGIN = { # Login-Buttons "login_button": 'a[href="/login"]', "login_button_alt": 'div:has-text("Anmelden")', # Formularfelder "username_input": 'input[autocomplete="username"]', "email_or_username_input": 'input[name="text"]', "password_input": 'input[type="password"]', "password_input_alt": 'input[name="password"]', # Submit-Buttons "next_button": 'div[role="button"]:has-text("Weiter")', "next_button_en": 'div[role="button"]:has-text("Next")', "login_submit": 'div[role="button"]:has-text("Anmelden")', "login_submit_en": 'div[role="button"]:has-text("Log in")' } # === NAVIGATION === NAVIGATION = { # Hauptnavigation "home_link": 'a[href="/home"]', "explore_link": 'a[href="/explore"]', "notifications_link": 'a[href="/notifications"]', "messages_link": 'a[href="/messages"]', "profile_link": 'a[data-testid="AppTabBar_Profile_Link"]', # Tweet/Post-Buttons "tweet_button": 'a[data-testid="SideNav_NewTweet_Button"]', "tweet_button_inline": 'button[data-testid="tweetButtonInline"]', # Navigation Container "primary_nav": 'nav[aria-label="Primary"]', "sidebar": 'div[data-testid="sidebarColumn"]' } # === PROFIL === PROFILE = { # Profilbearbeitung "edit_profile_button": 'button:has-text("Profil bearbeiten")', "edit_profile_button_en": 'button:has-text("Edit profile")', # Formularfelder "display_name_input": 'input[name="displayName"]', "bio_textarea": 'textarea[name="description"]', "location_input": 'input[name="location"]', "website_input": 'input[name="url"]', # Speichern "save_button": 'button:has-text("Speichern")', "save_button_en": 'button:has-text("Save")' } # === VERIFIZIERUNG === VERIFICATION = { # Challenge/Captcha "challenge_frame": 'iframe[title="arkose-challenge"]', "captcha_frame": 'iframe[src*="recaptcha"]', # Telefonnummer-Verifizierung "phone_verification_input": 'input[name="phone_number"]', "send_code_button": 'button:has-text("Code senden")', "verification_code_input": 'input[name="verification_code"]' } # === FEHLER UND WARNUNGEN === ERRORS = { # Fehlermeldungen "error_message": 'div[data-testid="toast"]', "error_alert": 'div[role="alert"]', "rate_limit_message": 'span:has-text("versuchen Sie es später")', "suspended_message": 'span:has-text("gesperrt")', # Spezifische Fehler "email_taken": 'span:has-text("E-Mail-Adresse wird bereits verwendet")', "invalid_credentials": 'span:has-text("Falscher Benutzername oder falsches Passwort")' } # === MODALE DIALOGE === MODALS = { # Allgemeine Modale "modal_container": 'div[role="dialog"]', "modal_close_button": 'div[aria-label="Schließen"]', "modal_close_button_en": 'div[aria-label="Close"]', # Bestätigungsdialoge "confirm_button": 'button:has-text("Bestätigen")', "cancel_button": 'button:has-text("Abbrechen")' } @classmethod def get_selector(cls, category: str, key: str) -> str: """ Holt einen spezifischen Selektor. Args: category: Kategorie (z.B. "REGISTRATION", "LOGIN") key: Schlüssel innerhalb der Kategorie Returns: str: CSS-Selektor oder None """ category_dict = getattr(cls, category.upper(), {}) if isinstance(category_dict, dict): return category_dict.get(key) return None @classmethod def get_all_selectors(cls, category: str) -> dict: """ Holt alle Selektoren einer Kategorie. Args: category: Kategorie Returns: dict: Alle Selektoren der Kategorie """ return getattr(cls, category.upper(), {})