""" VK UI Helper - Hilfsfunktionen für UI-Interaktionen """ import logging import time import random import os from typing import Optional from playwright.sync_api import Page, ElementHandle logger = logging.getLogger("vk_ui_helper") class VKUIHelper: """ Hilfsklasse für VK UI-Interaktionen """ def __init__(self, page: Page, screenshots_dir: str = None, save_screenshots: bool = True): """ Initialisiert den UI Helper """ self.page = page self.screenshots_dir = screenshots_dir or "logs/screenshots" self.save_screenshots = save_screenshots # Screenshot-Verzeichnis erstellen falls nötig if self.save_screenshots and not os.path.exists(self.screenshots_dir): os.makedirs(self.screenshots_dir) def take_screenshot(self, name: str) -> Optional[str]: """ Erstellt einen Screenshot """ if not self.save_screenshots: return None try: timestamp = int(time.time()) filename = f"{name}_{timestamp}.png" filepath = os.path.join(self.screenshots_dir, filename) self.page.screenshot(path=filepath) logger.debug(f"Screenshot gespeichert: {filepath}") return filepath except Exception as e: logger.warning(f"Fehler beim Erstellen des Screenshots: {e}") return None def wait_for_element(self, selector: str, timeout: int = 30000) -> bool: """ Wartet auf ein Element """ try: self.page.wait_for_selector(selector, timeout=timeout) return True except Exception as e: logger.error(f"Element {selector} nicht gefunden nach {timeout}ms") return False def type_with_delay(self, selector: str, text: str, delay_min: float = 0.05, delay_max: float = 0.15): """ Tippt Text mit menschenähnlicher Verzögerung """ try: element = self.page.locator(selector) element.click() for char in text: element.type(char) time.sleep(random.uniform(delay_min, delay_max)) except Exception as e: logger.error(f"Fehler beim Tippen in {selector}: {e}") raise def click_with_retry(self, selector: str, max_attempts: int = 3) -> bool: """ Klickt auf ein Element mit Wiederholungsversuchen """ for attempt in range(max_attempts): try: self.page.click(selector) return True except Exception as e: logger.warning(f"Klick-Versuch {attempt + 1} fehlgeschlagen: {e}") if attempt < max_attempts - 1: time.sleep(random.uniform(1, 2)) return False def scroll_to_element(self, selector: str): """ Scrollt zu einem Element """ try: self.page.locator(selector).scroll_into_view_if_needed() time.sleep(random.uniform(0.5, 1)) except Exception as e: logger.warning(f"Fehler beim Scrollen zu {selector}: {e}") def is_element_visible(self, selector: str) -> bool: """ Prüft ob ein Element sichtbar ist """ try: return self.page.locator(selector).is_visible() except: return False def get_element_text(self, selector: str) -> Optional[str]: """ Holt den Text eines Elements """ try: return self.page.locator(selector).text_content() except Exception as e: logger.warning(f"Fehler beim Lesen des Texts von {selector}: {e}") return None def select_dropdown_option(self, selector: str, value: str): """ Wählt eine Option aus einem Dropdown """ try: self.page.select_option(selector, value) time.sleep(random.uniform(0.3, 0.6)) except Exception as e: logger.error(f"Fehler beim Auswählen von {value} in {selector}: {e}") raise def check_radio_button(self, selector: str): """ Wählt einen Radio Button aus """ try: self.page.check(selector) time.sleep(random.uniform(0.2, 0.4)) except Exception as e: logger.error(f"Fehler beim Auswählen des Radio Buttons {selector}: {e}") raise def wait_for_navigation(self, timeout: int = 30000): """ Wartet auf Navigation """ try: self.page.wait_for_load_state("networkidle", timeout=timeout) except Exception as e: logger.warning(f"Navigation-Timeout nach {timeout}ms: {e}")