Facebook - Workflow geht aber Popup nicht da mit Browser nicht anbtouchen

Dieser Commit ist enthalten in:
Claude Project Manager
2025-09-14 20:59:12 +02:00
Ursprung d0920d4078
Commit 4903dee3bc
10 geänderte Dateien mit 633 neuen und 182 gelöschten Zeilen

Datei anzeigen

@ -13,7 +13,6 @@ from browser.playwright_manager import PlaywrightManager
from utils.proxy_rotator import ProxyRotator
from utils.email_handler import EmailHandler
from utils.text_similarity import TextSimilarity, fuzzy_find_element, click_fuzzy_button
from domain.value_objects.browser_protection_style import BrowserProtectionStyle, ProtectionLevel
# Konfiguriere Logger
logger = logging.getLogger("base_automation")
@ -167,12 +166,6 @@ class BaseAutomation(ABC):
self.browser.start()
logger.info("Browser erfolgreich initialisiert")
# Browser-Schutz anwenden wenn nicht headless
if not self.headless:
self._emit_customer_log("🛡️ Sicherheitseinstellungen werden konfiguriert...")
# TEMPORÄR DEAKTIVIERT zum Testen
# self._apply_browser_protection()
logger.info("Browser-Schutz wurde temporär deaktiviert")
self._emit_customer_log("✅ Verbindung erfolgreich hergestellt")
return True
@ -532,51 +525,6 @@ class BaseAutomation(ABC):
return code
def _apply_browser_protection(self):
"""Wendet Browser-Schutz an, um versehentliche Interaktionen zu verhindern."""
try:
# Lade Schutz-Einstellungen aus stealth_config.json
import json
from pathlib import Path
protection_config = None
try:
config_file = Path(__file__).parent.parent / "config" / "stealth_config.json"
if config_file.exists():
with open(config_file, 'r', encoding='utf-8') as f:
stealth_config = json.load(f)
protection_config = stealth_config.get("browser_protection", {})
except Exception as e:
logger.warning(f"Konnte Browser-Schutz-Konfiguration nicht laden: {e}")
# Nutze Konfiguration oder Standardwerte
if protection_config and protection_config.get("enabled", True):
level_mapping = {
"none": ProtectionLevel.NONE,
"light": ProtectionLevel.LIGHT,
"medium": ProtectionLevel.MEDIUM,
"strong": ProtectionLevel.STRONG
}
protection_style = BrowserProtectionStyle(
level=level_mapping.get(protection_config.get("level", "medium"), ProtectionLevel.MEDIUM),
show_border=protection_config.get("show_border", True),
show_badge=protection_config.get("show_badge", True),
blur_effect=protection_config.get("blur_effect", False),
opacity=protection_config.get("opacity", 0.1),
badge_text=protection_config.get("badge_text", "🔒 Account wird erstellt - Bitte nicht eingreifen"),
badge_position=protection_config.get("badge_position", "top-right"),
border_color=protection_config.get("border_color", "rgba(255, 0, 0, 0.5)")
)
# Wende Schutz an
if hasattr(self.browser, 'apply_protection'):
self.browser.apply_protection(protection_style)
logger.info("Browser-Schutz aktiviert")
except Exception as e:
# Browser-Schutz ist optional, Fehler nicht kritisch
logger.warning(f"Browser-Schutz konnte nicht aktiviert werden: {str(e)}")
def _is_text_similar(self, text1: str, text2: str, threshold: float = None) -> bool:
"""

Datei anzeigen

@ -0,0 +1,103 @@
# Facebook-Modul Verbesserungsvorschläge
## 1. Facebook Login noch nicht implementiert
**Problem:** `facebook_login.py` enthält nur einen Platzhalter
```python
def login_account(self, email_or_phone: str, password: str, **kwargs) -> Dict[str, Any]:
logger.warning("Facebook-Login noch nicht vollständig implementiert")
return {"success": False, "error": "Login-Funktion noch nicht implementiert"}
```
**Lösung:** Vollständige Login-Implementation analog zu Registration
## 2. Fehlende Browser-Verfügbarkeitsprüfung
**Problem:** In `facebook_ui_helper.py` wird `_ensure_browser()` verwendet, aber nicht konsistent in allen Methoden
**Empfehlung:** Decorator-Pattern für Browser-Checks implementieren:
```python
def requires_browser(func):
def wrapper(self, *args, **kwargs):
if not self._ensure_browser():
return False
return func(self, *args, **kwargs)
return wrapper
```
## 3. Hardcodierte Timeouts
**Problem:** Viele hardcodierte Timeout-Werte (1000ms, 2000ms, etc.)
**Empfehlung:** Zentrale Timeout-Konfiguration:
```python
class FacebookTimeouts:
SHORT = 1000
MEDIUM = 3000
LONG = 5000
VERIFICATION = 120000
```
## 4. Unvollständige SMS-Verifikation
**Problem:** `handle_sms_verification()` in `facebook_verification.py` ist nicht implementiert
**Empfehlung:** SMS-Service Integration planen oder als "nicht unterstützt" markieren
## 5. Fehlende Unit-Tests
**Problem:** Keine Test-Dateien für das Facebook-Modul gefunden
**Empfehlung:** Test-Suite erstellen mit pytest:
- test_facebook_selectors.py
- test_facebook_registration.py
- test_facebook_utils.py
## 6. Redundanter Code in Selektoren
**Problem:** Viele alternative Selektoren könnten in Listen organisiert werden
**Empfehlung:**
```python
class FacebookSelectors:
FIRSTNAME_SELECTORS = [
"input[name='firstname']",
"input[aria-label='Vorname']",
"input[placeholder*='Vorname']"
]
```
## 7. Fehlende Retry-Logik
**Problem:** Workflow definiert `retry` Werte, aber keine Implementation dafür
**Empfehlung:** Retry-Decorator implementieren:
```python
@retry(max_attempts=3, delay=1.0)
def _open_registration_form(self):
# ...
```
## 8. Unvollständige Captcha-Behandlung
**Problem:** `handle_captcha()` erkennt nur Captchas, löst sie aber nicht
**Empfehlung:**
- 2Captcha/Anti-Captcha Service Integration
- Oder manuellen Modus mit Benachrichtigung implementieren
## 9. Fehlende Konfigurationsdatei
**Problem:** Keine zentrale Konfiguration für Facebook-spezifische Settings
**Empfehlung:** `facebook_config.py` erstellen:
```python
class FacebookConfig:
BASE_URL = "https://www.facebook.com"
SUPPORTED_LANGUAGES = ["de", "en"]
MIN_PASSWORD_LENGTH = 6
VERIFICATION_CODE_LENGTH = 5
```
## 10. Unvollständige Internationalisierung
**Problem:** Texte sind teilweise hardcodiert auf Deutsch
**Empfehlung:** i18n-Support verbessern mit Language-Dictionary
## Priorität der Verbesserungen:
1. **Hoch:** Facebook Login implementieren
2. **Hoch:** Retry-Logik implementieren
3. **Mittel:** Timeout-Konfiguration zentralisieren
4. **Mittel:** Unit-Tests hinzufügen
5. **Niedrig:** Code-Redundanz reduzieren

Datei anzeigen

@ -13,7 +13,6 @@ from typing import Dict, List, Any, Optional, Tuple
from browser.playwright_manager import PlaywrightManager
from browser.playwright_extensions import PlaywrightExtensions
from browser.fingerprint_protection import FingerprintProtection
from social_networks.base_automation import BaseAutomation
from infrastructure.services.advanced_fingerprint_service import AdvancedFingerprintService
from infrastructure.repositories.fingerprint_repository import FingerprintRepository
@ -85,6 +84,9 @@ class FacebookAutomation(BaseAutomation):
window_position=window_position
)
# Zusätzliche Initialisierungen für Facebook
self.window_position = window_position
# Facebook-spezifische Einstellungen
self.language = language
self.base_url = f"https://www.facebook.com/?locale={language}_DE" if language == "de" else "https://www.facebook.com"
@ -118,33 +120,37 @@ class FacebookAutomation(BaseAutomation):
def _initialize_browser(self) -> bool:
"""
Initialisiert den Browser mit Anti-Bot Features.
Identisch zu Instagram für konsistente Fingerprint-Protection.
Initialisiert den Browser mit Facebook-spezifischen Einstellungen.
Folgt dem Instagram-Pattern für saubere Implementierung.
Returns:
bool: True bei Erfolg, False bei Fehler
"""
try:
self._emit_customer_log("🔄 Sichere Verbindung wird aufgebaut...")
# Proxy-Konfiguration, falls aktiviert
proxy_config = None
if self.use_proxy:
self._emit_customer_log("🌐 Optimale Verbindung wird ausgewählt...")
proxy_config = self.proxy_rotator.get_proxy(self.proxy_type)
if not proxy_config:
logger.warning(f"Kein Proxy vom Typ '{self.proxy_type}' verfügbar, verwende direkten Zugriff")
# Browser initialisieren
# Browser initialisieren (wie Instagram - direkt, ohne super())
self.browser = PlaywrightManager(
headless=self.headless,
proxy=proxy_config,
browser_type="chromium",
screenshots_dir=self.screenshots_dir,
slowmo=self.slowmo
slowmo=self.slowmo,
window_position=self.window_position
)
# Browser starten
self.browser.start()
# Erweiterten Fingerprint-Schutz aktivieren (wie bei Instagram)
# Erweiterten Fingerprint-Schutz aktivieren, wenn gewünscht
if self.enhanced_stealth:
# Erstelle Extensions-Objekt
extensions = PlaywrightExtensions(self.browser)
@ -152,39 +158,55 @@ class FacebookAutomation(BaseAutomation):
# Methoden anhängen
extensions.hook_into_playwright_manager()
# Fingerprint-Schutz aktivieren
# Fingerprint-Schutz aktivieren mit angepasster Konfiguration
if self.provided_fingerprint:
# Nutze den bereitgestellten Fingerprint
logger.info("Verwende bereitgestellten Fingerprint für Account-Erstellung")
# Konvertiere Dict zu BrowserFingerprint wenn nötig
if isinstance(self.provided_fingerprint, dict):
from infrastructure.models.browser_fingerprint import BrowserFingerprint
from domain.entities.browser_fingerprint import BrowserFingerprint
fingerprint_obj = BrowserFingerprint.from_dict(self.provided_fingerprint)
else:
fingerprint_obj = self.provided_fingerprint
# Wende Fingerprint über FingerprintProtection an
from browser.fingerprint_protection import FingerprintProtection
protection = FingerprintProtection(
context=self.browser.context,
fingerprint_config=fingerprint_obj
)
protection.apply_to_context(self.browser.context)
logger.info(f"Fingerprint {fingerprint_obj.fingerprint_id} angewendet")
self.account_fingerprint = fingerprint_obj
fingerprint_config = fingerprint_obj.to_config()
else:
# Generiere neuen Fingerprint
self.account_fingerprint = self.fingerprint_service.generate_fingerprint("facebook")
fingerprint_config = self.account_fingerprint.to_config()
# Fingerprint-Protection mit Noise-Level
protection = FingerprintProtection(
noise_level=self.fingerprint_noise,
fingerprint_config=fingerprint_config
)
protection.apply(self.browser.page)
logger.info(f"Fingerprint-Schutz aktiviert (Noise-Level: {self.fingerprint_noise})")
# Fallback: Zufällige Fingerprint-Konfiguration
fingerprint_config = {
"noise_level": self.fingerprint_noise,
"canvas_noise": True,
"audio_noise": True,
"webgl_noise": True,
"hardware_concurrency": random.choice([4, 6, 8]),
"device_memory": random.choice([4, 8]),
"language": self.language,
"timezone_id": "Europe/Berlin"
}
success = self.browser.enable_enhanced_fingerprint_protection(fingerprint_config)
if success:
logger.info("Erweiterter Fingerprint-Schutz erfolgreich aktiviert")
else:
logger.warning("Erweiterter Fingerprint-Schutz konnte nicht aktiviert werden")
# Facebook-spezifische Browser-Einstellungen
self._apply_facebook_specific_settings()
self._emit_customer_log("✅ Verbindung erfolgreich hergestellt")
logger.info("Browser erfolgreich initialisiert")
return True
except Exception as e:
logger.error(f"Fehler bei der Browser-Initialisierung: {e}")
self.status["error"] = f"Browser-Initialisierungsfehler: {str(e)}"
return False
def _apply_facebook_specific_settings(self):
@ -257,9 +279,10 @@ class FacebookAutomation(BaseAutomation):
# Passwort generieren wenn nicht vorhanden
if not password:
# Facebook-spezifische Passwort-Policy
password = self.password_generator.generate_password(
length=random.randint(12, 16),
include_special=True
platform="facebook", # Plattform-spezifische Regeln
length=random.randint(12, 16) # Überschreibt default-Länge
)
logger.info("Passwort generiert")
@ -388,6 +411,82 @@ class FacebookAutomation(BaseAutomation):
# Browser offen lassen für User-Kontrolle
logger.info("Login abgeschlossen - Browser bleibt offen")
def verify_account(self, verification_code: str, **kwargs) -> Dict[str, Any]:
"""
Verifiziert einen Facebook-Account mit einem Bestätigungscode.
Implementiert die abstrakte Methode aus BaseAutomation.
Args:
verification_code: Der Bestätigungscode (5-stellig für Facebook)
**kwargs: Weitere optionale Parameter
Returns:
Dict[str, Any]: Ergebnis der Verifizierung mit Status
"""
logger.info(f"Starte Facebook-Account-Verifizierung mit Code: {verification_code}")
try:
# Browser initialisieren falls noch nicht geschehen
if not self.browser or not hasattr(self.browser, 'page'):
if not self._initialize_browser():
return {"success": False, "error": "Browser konnte nicht initialisiert werden"}
# Delegiere an Verification-Klasse
# Die eigentliche Verifizierung wird bereits in registration.py gehandhabt
# Diese Methode ist für standalone Verifizierung
# Prüfe ob wir auf der Verifizierungsseite sind
current_url = self.browser.page.url if self.browser else ""
if "confirmemail" not in current_url:
logger.warning("Nicht auf der Verifizierungsseite - navigiere dorthin")
# Könnte hier zur Verifizierungsseite navigieren wenn nötig
# Nutze die _enter_verification_code Methode aus registration
from .facebook_registration import FacebookRegistration
temp_registration = FacebookRegistration(self)
success = temp_registration._enter_verification_code(verification_code)
if success:
logger.info("Verifizierung erfolgreich abgeschlossen")
result = {
"success": True,
"stage": "verified",
"message": "Account erfolgreich verifiziert"
}
else:
logger.error("Verifizierung fehlgeschlagen")
result = {
"success": False,
"error": "Verifizierungscode konnte nicht bestätigt werden",
"stage": "verification_failed"
}
# Screenshot
self._take_screenshot(f"verification_result_{int(time.time())}")
# Status aktualisieren
self.status.update(result)
return result
except Exception as e:
error_msg = f"Unerwarteter Fehler bei der Verifizierung: {str(e)}"
logger.error(error_msg, exc_info=True)
# Fehler-Screenshot
self._take_screenshot(f"verification_error_{int(time.time())}")
self.status.update({
"success": False,
"error": error_msg,
"stage": "error"
})
return self.status
finally:
# Browser offen lassen für weitere Aktionen
logger.info("Verifizierung abgeschlossen - Browser bleibt offen")
def _initialize_browser_with_fingerprint(self, account_id: str) -> bool:
"""
Initialisiert den Browser mit einem Account-spezifischen Fingerprint.

Datei anzeigen

@ -168,7 +168,11 @@ class FacebookRegistration:
logger.info(f"Navigiere zu {self.automation.base_url}")
# Navigiere zur Facebook-Seite
self.automation.browser.navigate_to(self.automation.base_url)
navigation_success = self.automation.browser.navigate_to(self.automation.base_url)
if not navigation_success:
logger.error(f"Navigation zu {self.automation.base_url} fehlgeschlagen")
return False
# Warte auf Seitenladung
self.automation.human_behavior.wait_for_page_load(multiplier=1.5)
@ -178,11 +182,20 @@ class FacebookRegistration:
# Prüfe ob wir auf Facebook sind
current_url = self.automation.browser.page.url
logger.info(f"Aktuelle URL nach Navigation: {current_url}")
# Debug: Prüfe sichtbare Elemente
logger.debug(f"Sichtbare Buttons: {self.automation.browser.page.locator('button').count()}")
logger.debug(f"Sichtbare Links: {self.automation.browser.page.locator('a').count()}")
if "facebook.com" in current_url:
logger.info("Erfolgreich zu Facebook navigiert")
return True
else:
logger.error(f"Nicht auf Facebook gelandet: {current_url}")
# Zusätzliche Debug-Info
page_title = self.automation.browser.page.title()
logger.debug(f"Seiten-Titel: {page_title}")
return False
except Exception as e:
@ -287,15 +300,31 @@ class FacebookRegistration:
button_clicked = True
if button_clicked:
# Warte auf Formular-Ladung
self.automation.human_behavior.wait_for_page_load()
self.automation._take_screenshot("registration_form")
# Warte auf Formular-Ladung mit längerer Wartezeit
self.automation.human_behavior.wait_for_page_load(multiplier=2.0)
# Extra Wartezeit für Facebook's React-Rendering
self.automation.human_behavior.random_delay(2.0, 3.0)
# Prüfe ob Browser noch aktiv ist
if not self.automation.browser or not self.automation.browser.page:
logger.error("Browser wurde unerwartet geschlossen")
return False
try:
self.automation._take_screenshot("registration_form")
except Exception as e:
logger.warning(f"Screenshot fehlgeschlagen: {e}")
# Prüfe ob wir auf der Registrierungsseite sind
current_url = self.automation.browser.page.url
if "/r.php" in current_url or "registration" in current_url:
logger.info("Registrierungsformular erfolgreich geöffnet")
return True
try:
current_url = self.automation.browser.page.url
if "/r.php" in current_url or "registration" in current_url:
logger.info("Registrierungsformular erfolgreich geöffnet")
return True
except Exception as e:
logger.error(f"Fehler beim Abrufen der URL: {e}")
return False
logger.error("Konnte Registrierungsformular nicht öffnen")
return False
@ -307,6 +336,7 @@ class FacebookRegistration:
def _fill_registration_form(self, account_data: Dict[str, Any]) -> bool:
"""
Füllt das Registrierungsformular aus.
Verbesserte Version mit Fallback-Selektoren und robusterem Handling.
Args:
account_data: Account-Daten
@ -317,90 +347,234 @@ class FacebookRegistration:
try:
logger.info("Fülle Registrierungsformular aus")
# Vorname
if not self.automation.ui_helper.type_text_human_like(
self.selectors.REG_FIRSTNAME_FIELD,
account_data["first_name"]
):
logger.error("Fehler beim Eingeben des Vornamens")
# Prüfe ob Browser noch aktiv ist
if not self.automation.browser or not self.automation.browser.page:
logger.error("Browser ist nicht mehr aktiv vor Formular-Ausfüllung")
return False
# Nachname
if not self.automation.ui_helper.type_text_human_like(
# Debug: Prüfe welche Input-Felder sichtbar sind
try:
visible_inputs = self.automation.browser.page.locator("input[type='text']").count()
logger.debug(f"Anzahl sichtbarer Text-Input-Felder: {visible_inputs}")
# Liste alle sichtbaren Inputs mit Namen auf
all_inputs = self.automation.browser.page.locator("input").all()
for idx, inp in enumerate(all_inputs[:10]): # Nur erste 10 zur Sicherheit
try:
name = inp.get_attribute("name")
placeholder = inp.get_attribute("placeholder")
aria_label = inp.get_attribute("aria-label")
logger.debug(f"Input {idx}: name='{name}', placeholder='{placeholder}', aria-label='{aria_label}'")
except:
pass
except Exception as e:
logger.warning(f"Debug-Ausgabe fehlgeschlagen: {e}")
# Vorname mit Fallback
firstname_selectors = [
self.selectors.REG_FIRSTNAME_FIELD,
self.selectors.REG_FIRSTNAME_FIELD_ALT,
"input[placeholder*='Vorname']",
"input[name='firstname']", # Direkter Name-Selektor
"input[aria-label*='Vorname' i]" # Case-insensitive aria-label
]
firstname_filled = False
for selector in firstname_selectors:
logger.debug(f"Versuche Vorname-Selektor: {selector}")
try:
if self.automation.browser.is_element_visible(selector, timeout=1000):
logger.debug(f"Selektor {selector} ist sichtbar")
if self.automation.ui_helper.type_text_human_like(selector, account_data["first_name"]):
logger.info(f"Vorname eingegeben mit: {selector}")
firstname_filled = True
break
else:
logger.debug(f"Selektor {selector} nicht sichtbar")
except Exception as e:
logger.debug(f"Fehler bei Selektor {selector}: {e}")
if not firstname_filled:
logger.error(f"Fehler beim Eingeben des Vornamens. Getestete Selektoren: {firstname_selectors}")
# Zusätzliche Debug-Info
try:
current_url = self.automation.browser.page.url
logger.error(f"Aktuelle URL beim Fehler: {current_url}")
except:
pass
return False
# Nachname mit Fallback
lastname_selectors = [
self.selectors.REG_LASTNAME_FIELD,
account_data["last_name"]
):
self.selectors.REG_LASTNAME_FIELD_ALT,
"input[placeholder*='Nachname']"
]
lastname_filled = False
for selector in lastname_selectors:
if self.automation.browser.is_element_visible(selector, timeout=1000):
if self.automation.ui_helper.type_text_human_like(selector, account_data["last_name"]):
logger.info(f"Nachname eingegeben mit: {selector}")
lastname_filled = True
break
if not lastname_filled:
logger.error("Fehler beim Eingeben des Nachnamens")
return False
# Geburtsdatum
# Geburtsdatum - Verbesserte Dropdown-Behandlung
birth_date = account_data["birth_date"]
# Tag auswählen
if not self.automation.browser.select_option(
# Tag auswählen mit Fallback
day_selectors = [
self.selectors.REG_BIRTHDAY_DAY,
str(birth_date["day"])
):
self.selectors.REG_BIRTHDAY_DAY_ALT,
"select[aria-label='Tag']",
"select[title='Tag']"
]
day_selected = False
for selector in day_selectors:
try:
if self.automation.browser.select_option(selector, str(birth_date["day"])):
logger.info(f"Tag {birth_date['day']} ausgewählt mit: {selector}")
day_selected = True
break
except:
continue
if not day_selected:
logger.error("Fehler beim Auswählen des Geburtstags")
return False
# Monat auswählen
if not self.automation.browser.select_option(
self.automation.human_behavior.random_delay(0.3, 0.5)
# Monat auswählen mit Fallback
month_selectors = [
self.selectors.REG_BIRTHDAY_MONTH,
str(birth_date["month"])
):
self.selectors.REG_BIRTHDAY_MONTH_ALT,
"select[aria-label='Monat']",
"select[title='Monat']"
]
month_selected = False
for selector in month_selectors:
try:
if self.automation.browser.select_option(selector, str(birth_date["month"])):
logger.info(f"Monat {birth_date['month']} ausgewählt mit: {selector}")
month_selected = True
break
except:
continue
if not month_selected:
logger.error("Fehler beim Auswählen des Geburtsmonats")
return False
# Jahr auswählen
if not self.automation.browser.select_option(
self.automation.human_behavior.random_delay(0.3, 0.5)
# Jahr auswählen mit Fallback
year_selectors = [
self.selectors.REG_BIRTHDAY_YEAR,
str(birth_date["year"])
):
self.selectors.REG_BIRTHDAY_YEAR_ALT,
"select[aria-label='Jahr']",
"select[title='Jahr']"
]
year_selected = False
for selector in year_selectors:
try:
if self.automation.browser.select_option(selector, str(birth_date["year"])):
logger.info(f"Jahr {birth_date['year']} ausgewählt mit: {selector}")
year_selected = True
break
except:
continue
if not year_selected:
logger.error("Fehler beim Auswählen des Geburtsjahrs")
return False
self.automation.human_behavior.random_delay(0.5, 1.0)
# Geschlecht auswählen
# Geschlecht auswählen - Verbesserte Radio-Button Behandlung
gender_selector = self.selectors.get_gender_selector(account_data["gender"])
if not self.automation.browser.click_element(gender_selector):
gender_selected = False
# Versuche erst direkten Click auf das Input-Element
if self.automation.browser.click_element(gender_selector):
logger.info(f"Geschlecht direkt ausgewählt: {account_data['gender']}")
gender_selected = True
else:
# Fallback: Klicke auf das Label
label_selectors = [
f"label:has-text('{'Weiblich' if account_data['gender'] == 'female' else 'Männlich' if account_data['gender'] == 'male' else 'Divers'}')",
f"label._58mt:has(input[value='{'1' if account_data['gender'] == 'female' else '2' if account_data['gender'] == 'male' else '-1'}'])"
]
for selector in label_selectors:
try:
if self.automation.browser.click_element(selector):
logger.info(f"Geschlecht über Label ausgewählt: {account_data['gender']}")
gender_selected = True
break
except:
continue
if not gender_selected:
logger.error(f"Fehler beim Auswählen des Geschlechts: {account_data['gender']}")
return False
self.automation.human_behavior.random_delay(0.5, 1.0)
# E-Mail oder Telefonnummer
contact_field = account_data.get("email") or account_data.get("phone_number")
if not contact_field:
logger.error("Keine E-Mail oder Telefonnummer angegeben")
# E-Mail eingeben mit Fallback
email_field = account_data.get("email")
if not email_field:
logger.error("Keine E-Mail-Adresse angegeben")
return False
if not self.automation.ui_helper.type_text_human_like(
email_selectors = [
self.selectors.REG_EMAIL_OR_PHONE,
contact_field
):
logger.error("Fehler beim Eingeben der Kontaktdaten")
self.selectors.REG_EMAIL_OR_PHONE_ALT,
"input[placeholder*='E-Mail']",
"input[placeholder*='Handynummer oder E-Mail']"
]
email_filled = False
for selector in email_selectors:
if self.automation.browser.is_element_visible(selector, timeout=1000):
if self.automation.ui_helper.type_text_human_like(selector, email_field):
logger.info(f"E-Mail eingegeben mit: {selector}")
email_filled = True
break
if not email_filled:
logger.error("Fehler beim Eingeben der E-Mail")
return False
# Warte auf mögliches E-Mail-Bestätigungsfeld
self.automation.human_behavior.random_delay(1.0, 2.0)
# Wenn E-Mail eingegeben wurde, könnte ein Bestätigungsfeld erscheinen
if account_data.get("email"):
if self.automation.browser.is_element_visible(self.selectors.REG_EMAIL_CONFIRM, timeout=2000):
logger.info("E-Mail-Bestätigungsfeld erkannt")
if not self.automation.ui_helper.type_text_human_like(
self.selectors.REG_EMAIL_CONFIRM,
account_data["email"]
):
logger.warning("Fehler beim Bestätigen der E-Mail")
# E-Mail-Bestätigung falls erforderlich
if self.automation.browser.is_element_visible(self.selectors.REG_EMAIL_CONFIRM, timeout=2000):
logger.info("E-Mail-Bestätigungsfeld erkannt")
if not self.automation.ui_helper.type_text_human_like(
self.selectors.REG_EMAIL_CONFIRM,
email_field
):
logger.warning("Fehler beim Bestätigen der E-Mail")
# Passwort
if not self.automation.ui_helper.type_text_human_like(
# Passwort mit Fallback
password_selectors = [
self.selectors.REG_PASSWORD,
account_data["password"]
):
self.selectors.REG_PASSWORD_ALT,
self.selectors.REG_PASSWORD_ALT2,
"input[type='password']",
"input[autocomplete='new-password']"
]
password_filled = False
for selector in password_selectors:
if self.automation.browser.is_element_visible(selector, timeout=1000):
if self.automation.ui_helper.type_text_human_like(selector, account_data["password"]):
logger.info(f"Passwort eingegeben mit: {selector}")
password_filled = True
break
if not password_filled:
logger.error("Fehler beim Eingeben des Passworts")
return False
@ -522,30 +696,68 @@ class FacebookRegistration:
def _enter_verification_code(self, code: str) -> bool:
"""
Gibt den Verifikationscode ein.
Verbesserte Version für 5-stelligen Code mit Fallback-Selektoren.
Args:
code: Verifikationscode
code: Verifikationscode (5-stellig, nur Zahlen)
Returns:
bool: True bei Erfolg
"""
try:
# Extrahiere nur Zahlen aus dem Code (falls FB- prefix vorhanden)
import re
code_digits = re.sub(r'\D', '', code)
if len(code_digits) == 5:
code = code_digits
logger.info(f"Gebe Verifikationscode ein: {code}")
# Code eingeben
if not self.automation.ui_helper.type_text_human_like(
self.selectors.VERIFICATION_CODE_INPUT,
code
):
logger.error("Fehler beim Eingeben des Verifikationscodes")
# Versuche verschiedene Selektoren für das Code-Eingabefeld
code_selectors = [
self.selectors.VERIFICATION_CODE_INPUT, # input#code_in_cliff
self.selectors.VERIFICATION_CODE_INPUT_ALT, # input[name='code']
self.selectors.VERIFICATION_CODE_INPUT_ALT2, # input[maxlength='5']
"input[size='5']", # 5-stelliges Feld
"input[type='text'][maxlength='5']", # Text-Input mit 5 Zeichen
"input[placeholder*='Code']", # Placeholder mit 'Code'
]
code_entered = False
for selector in code_selectors:
try:
if self.automation.browser.is_element_visible(selector, timeout=1000):
# Stelle sicher, dass das Feld leer ist
self.automation.browser.page.locator(selector).first.clear()
self.automation.human_behavior.random_delay(0.2, 0.4)
# Gebe Code ein
if self.automation.ui_helper.type_text_human_like(selector, code):
logger.info(f"Verifikationscode eingegeben mit: {selector}")
code_entered = True
break
except:
continue
if not code_entered:
logger.error("Fehler beim Eingeben des Verifikationscodes - kein Eingabefeld gefunden")
return False
self.automation.human_behavior.random_delay(0.5, 1.0)
# Weiter-Button klicken
continue_clicked = False
# Versuche verschiedene Selektoren
for text in self.selectors.get_button_texts("continue"):
selector = f"button:has-text('{text}')"
# Versuche verschiedene Button-Selektoren
continue_selectors = [
self.selectors.VERIFICATION_CONTINUE_BUTTON, # button:has-text('Weiter')
self.selectors.VERIFICATION_CONTINUE_BUTTON_EN, # button:has-text('Continue')
"button[type='submit']", # Submit-Button
"button:has-text('Bestätigen')", # Bestätigen
"button:has-text('Confirm')", # Englisch
"button:has-text('OK')", # OK
]
for selector in continue_selectors:
try:
if self.automation.browser.click_element(selector, timeout=1000):
logger.info(f"Verifikation fortgesetzt mit: {selector}")
@ -554,18 +766,35 @@ class FacebookRegistration:
except:
continue
# Oder Enter drücken
# Fallback: Enter drücken
if not continue_clicked:
self.automation.browser.page.keyboard.press("Enter")
logger.info("Verifikation mit Enter fortgesetzt")
continue_clicked = True
# Warte auf Navigation
self.automation.human_behavior.wait_for_page_load()
if not continue_clicked:
logger.error("Konnte Verifikation nicht fortsetzen")
return False
# Warte auf Navigation/Verarbeitung
self.automation.human_behavior.wait_for_page_load(multiplier=1.5)
# Prüfe auf OK-Button (Popup nach erfolgreicher Verifikation)
if self.automation.browser.is_element_visible(self.selectors.VERIFICATION_OK_BUTTON, timeout=3000):
self.automation.browser.click_element(self.selectors.VERIFICATION_OK_BUTTON)
logger.info("OK-Button nach Verifikation geklickt")
ok_selectors = [
self.selectors.VERIFICATION_OK_BUTTON,
self.selectors.VERIFICATION_OK_BUTTON_ALT,
"a:has-text('OK')",
"button:has-text('OK')"
]
for selector in ok_selectors:
try:
if self.automation.browser.is_element_visible(selector, timeout=2000):
self.automation.browser.click_element(selector)
logger.info(f"OK-Button nach Verifikation geklickt: {selector}")
break
except:
continue
return True

Datei anzeigen

@ -29,27 +29,34 @@ class FacebookSelectors:
LOGIN_BUTTON_ALT = "button[data-testid='royal_login_button']"
# ===== REGISTRATION FORM =====
# Name fields
# Name fields - Updated based on actual HTML
REG_FIRSTNAME_FIELD = "input[name='firstname']"
REG_FIRSTNAME_FIELD_ALT = "input[aria-label='Vorname']"
REG_LASTNAME_FIELD = "input[name='lastname']"
REG_LASTNAME_FIELD_ALT = "input[aria-label='Nachname']"
# Birthday selects
# Birthday selects - Updated with correct selectors
REG_BIRTHDAY_DAY = "select[name='birthday_day']"
REG_BIRTHDAY_DAY_ALT = "select#day"
REG_BIRTHDAY_MONTH = "select[name='birthday_month']"
REG_BIRTHDAY_MONTH_ALT = "select#month"
REG_BIRTHDAY_YEAR = "select[name='birthday_year']"
REG_BIRTHDAY_YEAR_ALT = "select#year"
# Gender radio buttons
REG_GENDER_FEMALE = "input[name='sex'][value='1']"
REG_GENDER_MALE = "input[name='sex'][value='2']"
REG_GENDER_CUSTOM = "input[name='sex'][value='-1']"
# Gender radio buttons - Updated with correct values
REG_GENDER_FEMALE = "input[name='sex'][value='1']" # Weiblich
REG_GENDER_MALE = "input[name='sex'][value='2']" # Männlich
REG_GENDER_CUSTOM = "input[name='sex'][value='-1']" # Divers
# Contact info
# Contact info - Updated based on actual HTML
REG_EMAIL_OR_PHONE = "input[name='reg_email__']"
REG_EMAIL_OR_PHONE_ALT = "input[aria-label='Handynummer oder E-Mail-Adresse']"
REG_EMAIL_CONFIRM = "input[name='reg_email_confirmation__']" # Erscheint wenn Email eingegeben
# Password
# Password - Updated with correct selectors
REG_PASSWORD = "input[name='reg_passwd__']"
REG_PASSWORD_ALT = "input#password_step_input"
REG_PASSWORD_ALT2 = "input[aria-label='Neues Passwort']"
# Submit button
REG_SUBMIT_BUTTON = "button[name='websubmit']"
@ -57,8 +64,10 @@ class FacebookSelectors:
REG_SUBMIT_BUTTON_EN = "button:has-text('Sign Up')"
# ===== EMAIL VERIFICATION =====
# Updated for 5-digit code based on actual HTML
VERIFICATION_CODE_INPUT = "input#code_in_cliff"
VERIFICATION_CODE_INPUT_ALT = "input[name='code']"
VERIFICATION_CODE_INPUT_ALT2 = "input[maxlength='5']" # 5-stelliger Code
VERIFICATION_CONTINUE_BUTTON = "button:has-text('Weiter')"
VERIFICATION_CONTINUE_BUTTON_EN = "button:has-text('Continue')"