# social_networks/facebook/facebook_login.py """ Facebook-Login - Klasse für die Anmeldefunktionalität bei Facebook Placeholder für zukünftige Implementierung. """ import logging import re import time from typing import Dict, Any, Optional from playwright.sync_api import TimeoutError as PlaywrightTimeoutError from .facebook_selectors import FacebookSelectors from .facebook_workflow import FacebookWorkflow from utils.logger import setup_logger logger = setup_logger("facebook_login") class FacebookLogin: """ Klasse für die Anmeldung bei Facebook-Konten. TODO: Vollständige Implementierung wenn Login-Details verfügbar. """ def __init__(self, automation): """ Initialisiert die Facebook-Login-Funktionalität. Args: automation: Referenz auf die Hauptautomatisierungsklasse """ self.automation = automation self.selectors = FacebookSelectors() self.workflow = FacebookWorkflow.get_login_workflow() logger.debug("Facebook-Login initialisiert") def login_account(self, email_or_phone: str, password: str, **kwargs) -> Dict[str, Any]: """ Führt den Login-Prozess für ein Facebook-Konto durch. Args: email_or_phone: E-Mail-Adresse oder Telefonnummer password: Passwort **kwargs: Weitere optionale Parameter Returns: Dict[str, Any]: Ergebnis des Logins """ logger.info(f"Starte Facebook-Login für {email_or_phone}") automation = self.automation browser_manager = automation.browser if browser_manager is None or not getattr(browser_manager, "page", None): if not automation._initialize_browser(): return { "success": False, "error": "Browser konnte nicht initialisiert werden", "stage": "browser_init" } browser_manager = automation.browser page = browser_manager.page raw_account_data = kwargs.get("raw_account_data") or {} target_email = raw_account_data.get("email") if not target_email and email_or_phone and "@" in email_or_phone: target_email = email_or_phone login_url = "https://www.facebook.com/?locale=de_DE" automation._send_status_update("Öffne Facebook") automation._send_log_update("Navigiere zur Facebook-Startseite...") if not browser_manager.navigate_to(login_url): return { "success": False, "error": "Konnte Facebook nicht öffnen", "stage": "navigation_failed" } self._reject_optional_cookies(browser_manager) automation._send_status_update("Fülle Login-Formular aus") automation._send_log_update("Gebe Zugangsdaten ein...") if not browser_manager.fill_form_field("#email", email_or_phone): return { "success": False, "error": "E-Mail/Telefon-Feld konnte nicht ausgefüllt werden", "stage": "fill_email" } if not browser_manager.fill_form_field("#pass", password): return { "success": False, "error": "Passwortfeld konnte nicht ausgefüllt werden", "stage": "fill_password" } automation._send_status_update("Sende Login-Daten") if not browser_manager.click_element("button[data-testid='royal-login-button']"): return { "success": False, "error": "Login-Button konnte nicht geklickt werden", "stage": "click_login" } try: page.wait_for_load_state("networkidle", timeout=15000) except PlaywrightTimeoutError: logger.debug("Warten auf Netzwerk-Leerlauf nach Login abgelaufen") # Prüfe auf Zwei-Faktor-Authentifizierung if "auth_platform/codesubmit" in page.url: automation._send_status_update("Zwei-Faktor-Verifizierung erforderlich") automation._send_log_update("Warte auf E-Mail mit Sicherheitscode...") if not target_email: return { "success": False, "error": "Zwei-Faktor-Code erforderlich, aber keine E-Mail für den Account vorhanden", "stage": "two_factor_missing_email" } if not self._handle_two_factor(page, browser_manager, target_email): return { "success": False, "error": "Zwei-Faktor-Verifizierung fehlgeschlagen", "stage": "two_factor_failed" } try: page.wait_for_load_state("networkidle", timeout=15000) except PlaywrightTimeoutError: logger.debug("Warten nach 2FA auf Netzwerk-Leerlauf abgelaufen") # Prüfe auf Login-Erfolg oder Fehler if self._detect_login_error(browser_manager): error_message = self._extract_error_message(browser_manager) return { "success": False, "error": error_message or "Login fehlgeschlagen", "stage": "login_failed" } if not self._await_login_success(page): return { "success": False, "error": "Login konnte nicht bestätigt werden", "stage": "login_unknown" } self._dismiss_post_login_dialog(page) automation._send_status_update("Login erfolgreich") automation._send_log_update("Facebook-Login abgeschlossen") return { "success": True, "stage": "completed", "username": email_or_phone } # ------------------------------------------------------------------ # Hilfsmethoden # ------------------------------------------------------------------ def _reject_optional_cookies(self, browser_manager) -> None: """Klickt den Button "Optionale Cookies ablehnen", falls vorhanden.""" page = browser_manager.page try: button = page.locator("text=Optionale Cookies ablehnen").first button.wait_for(state="visible", timeout=5000) button.click() logger.info("Optionale Cookies abgelehnt") except PlaywrightTimeoutError: logger.debug("Cookie-Banner nicht gefunden oder bereits geschlossen") except Exception as e: logger.warning(f"Konnte Cookie-Banner nicht schließen: {e}") def _handle_two_factor(self, page, browser_manager, target_email: str) -> bool: """Handhabt die Eingabe des Zwei-Faktor-Codes.""" self.automation._send_log_update("Versuche Sicherheitscode aus E-Mail zu lesen...") code = self.automation.email_handler.get_verification_code( target_email=target_email, platform="facebook", max_attempts=60, delay_seconds=5 ) if not code: logger.error("Kein Zwei-Faktor-Code gefunden") return False logger.info("Trage Zwei-Faktor-Code ein") self.automation._send_log_update("Zwei-Faktor-Code gefunden – trage ihn ein...") if not browser_manager.fill_form_field("input[name='email']", code): logger.error("Zwei-Faktor-Eingabefeld konnte nicht gefüllt werden") return False try: page.locator("text=Weiter").first.click() self.automation._send_log_update("Weiter mit Zwei-Faktor-Verifizierung...") except PlaywrightTimeoutError: logger.error("Weiter-Button nach Zwei-Faktor-Eingabe nicht gefunden") return False except Exception as e: logger.error(f"Fehler beim Klicken auf den Weiter-Button: {e}") return False return True def _detect_login_error(self, browser_manager) -> bool: """Überprüft, ob ein Fehler nach dem Login angezeigt wird.""" error_selector = "div[data-testid='error_box'], div._9ay7" element = browser_manager.wait_for_selector(error_selector, timeout=2000) return bool(element) def _extract_error_message(self, browser_manager) -> Optional[str]: element = browser_manager.wait_for_selector("div[data-testid='error_box'], div._9ay7", timeout=2000) if not element: return None try: text = element.inner_text().strip() logger.error(f"Facebook-Login-Fehler: {text}") return text except Exception: return None def _await_login_success(self, page) -> bool: """Wartet auf eine Seite, die einen erfolgreichen Login vermuten lässt.""" target_pattern = re.compile(r"https://www\.facebook\.com/(?!login|checkpoint).*") try: page.wait_for_url(target_pattern, timeout=15000) return True except PlaywrightTimeoutError: logger.debug(f"Aktuelle URL nach Login: {page.url}") return bool(target_pattern.match(page.url)) def _dismiss_post_login_dialog(self, page) -> None: """Schließt nach dem Login auftauchende Dialoge.""" try: close_button = page.locator("button:has-text('Schließen')").first close_button.click(timeout=3000) logger.info("Post-Login-Dialog geschlossen") except PlaywrightTimeoutError: logger.debug("Kein Post-Login-Dialog zum Schließen gefunden") except Exception: pass