Problem bei X gelöst

Dieser Commit ist enthalten in:
Claude Project Manager
2025-08-12 00:38:23 +02:00
Ursprung 5d169ba517
Commit 3101e41451
16 geänderte Dateien mit 3142 neuen und 12 gelöschten Zeilen

Datei anzeigen

@ -8,7 +8,12 @@
"WebFetch(domain:support.google.com)",
"Bash(python3 -m pip list:*)",
"Bash(python3:*)",
"Bash(grep:*)"
"Bash(grep:*)",
"Bash(cat:*)",
"Bash(claude config)",
"Bash(claude config list:*)",
"Bash(claude mcp)",
"Bash(claude mcp:*)"
],
"deny": [],
"additionalDirectories": [

Datei anzeigen

@ -5,9 +5,9 @@
## Project Overview
- **Path**: `A:\GiTea\AccountForger`
- **Files**: 987 files
- **Size**: 364.7 MB
- **Last Modified**: 2025-08-10 00:03
- **Files**: 1011 files
- **Size**: 369.9 MB
- **Last Modified**: 2025-08-10 20:51
## Technology Stack
@ -70,17 +70,16 @@ controllers/
│ └── platform_controllers/
│ ├── base_controller.py
│ ├── base_worker_thread.py
│ ├── facebook_controller.py
│ ├── gmail_controller.py
│ ├── instagram_controller.py
│ ├── method_rotation_mixin.py
│ ├── method_rotation_worker_mixin.py
│ ├── ok_ru_controller.py
│ ├── rotation_error_handler.py
── safe_imports.py
│ └── tiktok_controller.py
── safe_imports.py
database/
│ ├── accounts.db
│ ├── accounts.db-journal
│ ├── account_repository.py
│ ├── db_manager.py
│ ├── schema_v2.sql
@ -204,7 +203,7 @@ resources/
│ │ ├── fr.svg
│ │ ├── gmail.svg
│ │ ├── instagram.svg
│ │ └── intelsight-logo.svg
│ │ └── intelsight-dark.svg
│ └── themes/
│ ├── dark.qss
│ └── light.qss
@ -297,6 +296,10 @@ styles/
│ └── __init__.py
tests/
│ └── test_method_rotation.py
themes/
│ ├── qss_generator.py
│ ├── theme_config.py
│ └── __init__.py
updates/
│ ├── downloader.py
│ ├── update_checker.py
@ -318,6 +321,9 @@ views/
├── about_dialog.py
├── main_window.py
├── platform_selector.py
├── base/
│ ├── theme_aware_widget.py
│ └── __init__.py
├── components/
│ ├── accounts_overview_view.py
│ ├── platform_grid_view.py
@ -329,6 +335,7 @@ views/
│ └── __init__.py
├── tabs/
│ ├── accounts_tab.py
│ ├── facebook_generator_tab.py
│ ├── generator_tab.py
│ ├── generator_tab_modern.py
│ └── settings_tab.py
@ -336,13 +343,13 @@ views/
├── account_card.py
├── account_creation_modal.py
├── account_creation_modal_v2.py
├── dark_mode_toggle.py
├── forge_animation_widget.py
├── forge_animation_widget_v2.py
├── icon_factory.py
├── language_dropdown.py
├── login_process_modal.py
── modern_message_box.py
└── platform_button.py
── modern_message_box.py
```
## Key Files
@ -378,3 +385,4 @@ This project is managed with Claude Project Manager. To work with this project:
- README updated on 2025-08-09 01:31:28
- README updated on 2025-08-10 00:03:51
- README updated on 2025-08-10 12:55:25
- README updated on 2025-08-11 19:49:09

Datei anzeigen

@ -121,8 +121,15 @@ class MainController:
gmail_controller.session_controller = self.session_controller
self.platform_controllers["gmail"] = gmail_controller
# Hier können in Zukunft weitere Controller hinzugefügt werden:
# self.platform_controllers["facebook"] = FacebookController(...)
# Facebook Controller hinzufügen
from controllers.platform_controllers.facebook_controller import FacebookController
facebook_controller = FacebookController(
self.db_manager,
self.proxy_rotator,
self.email_handler,
self.language_manager
)
self.platform_controllers["facebook"] = facebook_controller
# Signals verbinden
self.connect_signals()

Datei anzeigen

@ -0,0 +1,233 @@
"""
Controller für Facebook-spezifische Funktionalität.
Mit Fingerprint-Protection und Anti-Bot Features.
"""
import logging
import time
import random
from PyQt5.QtCore import QThread, pyqtSignal
from typing import Dict, Any
from controllers.platform_controllers.base_controller import BasePlatformController
from controllers.platform_controllers.base_worker_thread import BaseAccountCreationWorkerThread
from views.tabs.facebook_generator_tab import FacebookGeneratorTab
from social_networks.facebook.facebook_automation import FacebookAutomation
from utils.birthday_generator import BirthdayGenerator
from utils.logger import setup_logger
logger = setup_logger("facebook_controller")
class FacebookWorkerThread(BaseAccountCreationWorkerThread):
"""Worker-Thread für die Facebook-Account-Erstellung."""
def __init__(self, params):
super().__init__(params, "Facebook")
self.birthday_generator = BirthdayGenerator()
def get_automation_class(self):
"""Gibt die Facebook Automation Klasse zurück"""
return FacebookAutomation
def get_error_interpretations(self) -> Dict[str, str]:
"""Facebook-spezifische Fehlerinterpretationen"""
return {
"email already in use": "Diese E-Mail-Adresse wird bereits verwendet",
"phone number required": "Telefonnummer erforderlich",
"invalid birth date": "Ungültiges Geburtsdatum",
"account suspended": "Account wurde gesperrt",
"verification required": "Verifizierung erforderlich"
}
def run(self):
"""Führt die Account-Erstellung aus."""
try:
self.log_signal.emit("Facebook-Account-Erstellung gestartet...")
self.progress_signal.emit(10)
# Facebook-Automation initialisieren (mit Anti-Bot Features wie Instagram)
automation = FacebookAutomation(
headless=self.params.get("headless", False),
use_proxy=self.params.get("use_proxy", False),
proxy_type=self.params.get("proxy_type"),
save_screenshots=True,
debug=self.params.get("debug", False),
email_domain=self.params.get("email_domain", "z5m7q9dk3ah2v1plx6ju.com"),
enhanced_stealth=True, # Anti-Bot Features aktivieren
fingerprint_noise=0.5, # Fingerprint-Verschleierung
language="de" # Deutsche Version
)
self.update_signal.emit("Browser wird vorbereitet...")
self.progress_signal.emit(20)
# Namen aufteilen (falls zusammen übergeben)
full_name = self.params.get("full_name", "")
name_parts = full_name.split(" ", 1)
first_name = name_parts[0] if name_parts else "Test"
last_name = name_parts[1] if len(name_parts) > 1 else "User"
# Geburtsdatum aus Alter generieren
age = self.params.get("age", random.randint(18, 65))
birth_date_components = self.birthday_generator.generate_birthday_components("facebook", age)
# Geschlecht aus den Parametern oder default
gender = self.params.get("gender", random.choice(["male", "female"]))
logger.info(f"Geschlecht: {gender}")
self.log_signal.emit(f"Registriere Account für: {first_name} {last_name} (Alter: {age})")
# Account registrieren
result = automation.register_account(
first_name=first_name,
last_name=last_name,
birth_date=birth_date_components,
gender=gender,
email=self.params.get("email"), # Wird generiert wenn nicht vorhanden
phone_number=self.params.get("phone_number"),
password=self.params.get("password"), # Wird generiert wenn nicht vorhanden
**self.params.get("additional_params", {})
)
self.progress_signal.emit(100)
if result["success"]:
self.log_signal.emit("Account erfolgreich erstellt!")
self.finished_signal.emit(result)
else:
error_msg = result.get("error", "Unbekannter Fehler")
self.log_signal.emit(f"Fehler bei der Account-Erstellung: {error_msg}")
self.error_signal.emit(error_msg)
except Exception as e:
logger.error(f"Fehler im Worker-Thread: {e}")
self.log_signal.emit(f"Schwerwiegender Fehler: {str(e)}")
self.error_signal.emit(str(e))
finally:
self.running = False
class FacebookController(BasePlatformController):
"""Controller für die Facebook-Plattform."""
def __init__(self, db_manager=None, proxy_rotator=None, email_handler=None, language_manager=None):
super().__init__("Facebook", db_manager, proxy_rotator, email_handler, language_manager)
self.worker_thread = None
logger.info("Facebook Controller initialisiert")
def get_generator_tab(self):
"""
Erstellt und konfiguriert den Generator-Tab für Facebook.
Returns:
FacebookGeneratorTab: Konfigurierter Tab für Facebook mit Geschlechtsauswahl
"""
# Erstelle Facebook-spezifischen Generator-Tab mit Geschlechtsfeld
generator_tab = FacebookGeneratorTab(
"Facebook",
self.language_manager
)
# Facebook-spezifische Konfiguration
self._configure_facebook_fields(generator_tab)
# Verbinde Signale
generator_tab.start_requested.connect(self.handle_generation_request)
generator_tab.stop_requested.connect(self.stop_generation)
return generator_tab
def _configure_facebook_fields(self, generator_tab):
"""
Konfiguriert Facebook-spezifische Felder im Generator-Tab.
Args:
generator_tab: Der zu konfigurierende Tab
"""
# Facebook-spezifische Konfiguration
# Der FacebookGeneratorTab hat bereits das Geschlechtsfeld integriert
# Vor- und Nachnamen werden im Worker-Thread aus full_name extrahiert
logger.debug("Facebook-spezifische Felder konfiguriert (inkl. Geschlechtsauswahl)")
def handle_generation_request(self, params: Dict[str, Any]):
"""
Behandelt eine Anfrage zur Account-Generierung.
Args:
params: Parameter für die Generierung
"""
logger.info(f"Facebook-Account-Generierung angefordert: {params}")
# Prüfe ob bereits ein Thread läuft
if self.worker_thread and self.worker_thread.isRunning():
logger.warning("Ein Account wird bereits erstellt")
return
# Facebook-spezifische Parameter hinzufügen
params["platform"] = "facebook"
# Starte Worker-Thread
self.worker_thread = FacebookWorkerThread(params)
# Verbinde Signale
self.worker_thread.update_signal.connect(
lambda msg: self.status_update.emit(msg)
)
self.worker_thread.log_signal.connect(
lambda msg: self.log_message.emit(msg)
)
self.worker_thread.progress_signal.connect(
lambda val: self.progress_update.emit(val)
)
self.worker_thread.finished_signal.connect(
self._handle_generation_success
)
self.worker_thread.error_signal.connect(
self._handle_generation_error
)
# Starte Thread
self.worker_thread.start()
self.generation_started.emit()
def _handle_generation_success(self, result: Dict[str, Any]):
"""
Behandelt erfolgreiche Account-Erstellung.
Args:
result: Ergebnis der Erstellung
"""
logger.info("Facebook-Account erfolgreich erstellt")
# Speichere Account in Datenbank
if self.db_manager and result.get("account_data"):
account_data = result["account_data"]
account_data["platform"] = "facebook"
# Speichere in DB
# TODO: DB-Integration
self.generation_completed.emit(result)
def _handle_generation_error(self, error_msg: str):
"""
Behandelt Fehler bei der Account-Erstellung.
Args:
error_msg: Fehlermeldung
"""
logger.error(f"Fehler bei Facebook-Account-Erstellung: {error_msg}")
self.generation_failed.emit(error_msg)
def stop_generation(self):
"""Stoppt die laufende Account-Generierung."""
if self.worker_thread and self.worker_thread.isRunning():
logger.info("Stoppe Facebook-Account-Generierung")
self.worker_thread.stop()
self.worker_thread.wait()
def cleanup(self):
"""Räumt Ressourcen auf."""
self.stop_generation()
logger.info("Facebook Controller aufgeräumt")

Binäre Datei nicht angezeigt.

Datei anzeigen

@ -0,0 +1,26 @@
"""
Facebook-Automatisierungsmodul fuer AccountForger.
Implementiert Account-Registrierung und -Login mit Anti-Bot Features.
"""
from .facebook_automation import FacebookAutomation
from .facebook_registration import FacebookRegistration
from .facebook_login import FacebookLogin
from .facebook_verification import FacebookVerification
from .facebook_ui_helper import FacebookUIHelper
from .facebook_utils import FacebookUtils
from .facebook_selectors import FacebookSelectors
from .facebook_workflow import FacebookWorkflow
__all__ = [
'FacebookAutomation',
'FacebookRegistration',
'FacebookLogin',
'FacebookVerification',
'FacebookUIHelper',
'FacebookUtils',
'FacebookSelectors',
'FacebookWorkflow'
]
__version__ = '1.0.0'

Datei anzeigen

@ -0,0 +1,451 @@
# social_networks/facebook/facebook_automation.py
"""
Facebook-Automatisierung - Hauptklasse für Facebook-Automatisierungsfunktionalität
Mit Anti-Bot Features wie bei Instagram.
"""
import logging
import time
import random
from datetime import datetime
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
from utils.password_generator import PasswordGenerator
from utils.username_generator import UsernameGenerator
from utils.birthday_generator import BirthdayGenerator
from utils.human_behavior import HumanBehavior
from utils.email_handler import EmailHandler
# Importiere Helferklassen
from .facebook_registration import FacebookRegistration
from .facebook_login import FacebookLogin
from .facebook_verification import FacebookVerification
from .facebook_ui_helper import FacebookUIHelper
from .facebook_utils import FacebookUtils
from utils.logger import setup_logger
# Konfiguriere Logger
logger = setup_logger("facebook_automation")
class FacebookAutomation(BaseAutomation):
"""
Hauptklasse für die Facebook-Automatisierung.
Implementiert die Registrierung und Anmeldung bei Facebook mit Anti-Bot Features.
"""
def __init__(self,
headless: bool = False,
use_proxy: bool = False,
proxy_type: str = None,
save_screenshots: bool = True,
screenshots_dir: str = None,
slowmo: int = 0,
debug: bool = False,
email_domain: str = "z5m7q9dk3ah2v1plx6ju.com",
enhanced_stealth: bool = True,
fingerprint_noise: float = 0.5,
window_position = None,
fingerprint = None,
language: str = "de"):
"""
Initialisiert die Facebook-Automatisierung.
Args:
headless: Ob der Browser im Headless-Modus ausgeführt werden soll
use_proxy: Ob ein Proxy verwendet werden soll
proxy_type: Proxy-Typ ("ipv4", "ipv6", "mobile") oder None für zufälligen Typ
save_screenshots: Ob Screenshots gespeichert werden sollen
screenshots_dir: Verzeichnis für Screenshots
slowmo: Verzögerung zwischen Aktionen in Millisekunden
debug: Ob Debug-Informationen angezeigt werden sollen
email_domain: Domain für generierte E-Mail-Adressen
enhanced_stealth: Ob erweiterter Stealth-Modus aktiviert werden soll
fingerprint_noise: Menge an Rauschen für Fingerprint-Verschleierung (0.0-1.0)
window_position: Position des Browser-Fensters
fingerprint: Vordefinierter Fingerprint
language: Sprache für Facebook ("de" oder "en")
"""
# Initialisiere die Basisklasse
super().__init__(
headless=headless,
use_proxy=use_proxy,
proxy_type=proxy_type,
save_screenshots=save_screenshots,
screenshots_dir=screenshots_dir,
slowmo=slowmo,
debug=debug,
email_domain=email_domain,
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"
# Stealth-Modus-Einstellungen (wie bei Instagram)
self.enhanced_stealth = enhanced_stealth
self.fingerprint_noise = max(0.0, min(1.0, fingerprint_noise))
# Initialisiere Helferklassen
self.registration = FacebookRegistration(self)
self.login = FacebookLogin(self)
self.verification = FacebookVerification(self)
self.ui_helper = FacebookUIHelper(self)
self.utils = FacebookUtils(self)
# Zusätzliche Hilfsklassen
self.password_generator = PasswordGenerator()
self.username_generator = UsernameGenerator()
self.birthday_generator = BirthdayGenerator()
self.human_behavior = HumanBehavior(speed_factor=0.8, randomness=0.6)
self.email_handler = EmailHandler() # Fuer E-Mail-Verifikation wie bei Instagram
# Fingerprint Service für Account-gebundene Fingerprints (wie bei Instagram)
self.fingerprint_service = AdvancedFingerprintService(FingerprintRepository())
self.account_fingerprint = None
# Nutze übergebenen Fingerprint wenn vorhanden
self.provided_fingerprint = fingerprint
logger.info(f"Facebook-Automatisierung initialisiert (Sprache: {language})")
def _initialize_browser(self) -> bool:
"""
Initialisiert den Browser mit Anti-Bot Features.
Identisch zu Instagram für konsistente Fingerprint-Protection.
Returns:
bool: True bei Erfolg, False bei Fehler
"""
try:
# Proxy-Konfiguration, falls aktiviert
proxy_config = None
if self.use_proxy:
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
self.browser = PlaywrightManager(
headless=self.headless,
proxy=proxy_config,
browser_type="chromium",
screenshots_dir=self.screenshots_dir,
slowmo=self.slowmo
)
# Browser starten
self.browser.start()
# Erweiterten Fingerprint-Schutz aktivieren (wie bei Instagram)
if self.enhanced_stealth:
# Erstelle Extensions-Objekt
extensions = PlaywrightExtensions(self.browser)
# Methoden anhängen
extensions.hook_into_playwright_manager()
# Fingerprint-Schutz aktivieren
if self.provided_fingerprint:
logger.info("Verwende bereitgestellten Fingerprint für Account-Erstellung")
if isinstance(self.provided_fingerprint, dict):
from infrastructure.models.browser_fingerprint import BrowserFingerprint
fingerprint_obj = BrowserFingerprint.from_dict(self.provided_fingerprint)
else:
fingerprint_obj = self.provided_fingerprint
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})")
# Facebook-spezifische Browser-Einstellungen
self._apply_facebook_specific_settings()
logger.info("Browser erfolgreich initialisiert")
return True
except Exception as e:
logger.error(f"Fehler bei der Browser-Initialisierung: {e}")
return False
def _apply_facebook_specific_settings(self):
"""
Wendet Facebook-spezifische Browser-Einstellungen an.
"""
try:
# Setze Facebook-spezifische Headers
extra_headers = {
'Accept-Language': 'de-DE,de;q=0.9,en;q=0.8' if self.language == 'de' else 'en-US,en;q=0.9',
'sec-ch-ua': '"Not_A Brand";v="8", "Chromium";v="120", "Google Chrome";v="120"',
'sec-ch-ua-mobile': '?0',
'sec-ch-ua-platform': '"Windows"',
}
self.browser.page.set_extra_http_headers(extra_headers)
# Viewport für Desktop
self.browser.page.set_viewport_size({
'width': random.randint(1366, 1920),
'height': random.randint(768, 1080)
})
logger.debug("Facebook-spezifische Browser-Einstellungen angewendet")
except Exception as e:
logger.warning(f"Fehler beim Anwenden Facebook-spezifischer Einstellungen: {e}")
def register_account(self,
first_name: str,
last_name: str,
birth_date: Dict[str, int],
gender: str,
email: str = None,
phone_number: str = None,
password: str = None,
**kwargs) -> Dict[str, Any]:
"""
Registriert einen neuen Facebook-Account.
Args:
first_name: Vorname
last_name: Nachname
birth_date: Geburtsdatum als Dict mit 'day', 'month', 'year'
gender: Geschlecht ('male', 'female', 'custom')
email: E-Mail-Adresse (optional, wird generiert wenn nicht angegeben)
phone_number: Telefonnummer (optional, alternativ zu E-Mail)
password: Passwort (optional, wird generiert wenn nicht angegeben)
**kwargs: Weitere optionale Parameter
Returns:
Dict[str, Any]: Ergebnis der Registrierung
"""
logger.info(f"Starte Facebook-Registrierung für {first_name} {last_name}")
try:
# Browser initialisieren
if not self._initialize_browser():
return {"success": False, "error": "Browser konnte nicht initialisiert werden"}
# Fingerprint rotieren für neue Registrierung
if self.enhanced_stealth and hasattr(self.browser, 'rotate_fingerprint'):
self.browser.rotate_fingerprint()
logger.info("Browser-Fingerprint für Registrierung rotiert")
# E-Mail generieren wenn nicht vorhanden
if not email and not phone_number:
email = self._generate_email(first_name, last_name)
logger.info(f"Generierte E-Mail: {email}")
# Passwort generieren wenn nicht vorhanden
if not password:
password = self.password_generator.generate_password(
length=random.randint(12, 16),
include_special=True
)
logger.info("Passwort generiert")
# Account-Daten vorbereiten
account_data = {
"first_name": first_name,
"last_name": last_name,
"birth_date": birth_date,
"gender": gender,
"email": email,
"phone_number": phone_number,
"password": password,
"language": self.language,
**kwargs
}
# Delegiere an Registration-Klasse
result = self.registration.register_account(account_data)
# Screenshot am Ende
self._take_screenshot(f"registration_finished_{int(time.time())}")
# Fingerprint-Statistiken aktualisieren bei Erfolg
if result.get("success") and self.account_fingerprint:
try:
account_id = result.get("account_data", {}).get("account_id", f"fb_{int(time.time())}")
self.fingerprint_service.update_fingerprint_stats(
self.account_fingerprint.fingerprint_id,
account_id,
success=True
)
logger.info("Fingerprint-Statistiken für erfolgreiche Registrierung aktualisiert")
except Exception as e:
logger.warning(f"Fehler beim Aktualisieren der Fingerprint-Statistiken: {e}")
# Status aktualisieren
self.status.update(result)
return result
except Exception as e:
error_msg = f"Unerwarteter Fehler bei der Registrierung: {str(e)}"
logger.error(error_msg, exc_info=True)
# Fehler-Screenshot
self._take_screenshot(f"registration_error_{int(time.time())}")
self.status.update({
"success": False,
"error": error_msg,
"stage": "error"
})
return self.status
finally:
# Browser offen lassen für Debugging
logger.info("Registrierung abgeschlossen - Browser bleibt offen")
def login_account(self, email_or_phone: str, password: str, account_id: Optional[str] = None, **kwargs) -> Dict[str, Any]:
"""
Meldet sich bei einem bestehenden Facebook-Account an.
Args:
email_or_phone: E-Mail-Adresse oder Telefonnummer
password: Passwort
account_id: Optional account ID für gespeicherten Fingerprint
**kwargs: Weitere optionale Parameter
Returns:
Dict[str, Any]: Ergebnis der Anmeldung
"""
logger.info(f"Starte Facebook-Login für '{email_or_phone}'")
try:
# Browser initialisieren mit Account-Fingerprint wenn vorhanden
if not self.browser or not hasattr(self.browser, 'page') or not self.browser.page:
if account_id:
# Verwende Account-spezifischen Fingerprint
if not self._initialize_browser_with_fingerprint(account_id):
return {"success": False, "error": "Browser konnte nicht mit Account-Fingerprint initialisiert werden"}
else:
# Verwende zufälligen Fingerprint
if not self._initialize_browser():
return {"success": False, "error": "Browser konnte nicht initialisiert werden"}
else:
logger.info("Verwende bereits geöffneten Browser für Login")
# Delegiere an Login-Klasse
result = self.login.login_account(email_or_phone, password, **kwargs)
# Screenshot am Ende
self._take_screenshot(f"login_finished_{int(time.time())}")
# Fingerprint-Statistiken aktualisieren
if account_id and self.account_fingerprint and result.get("success"):
try:
self.fingerprint_service.update_fingerprint_stats(
self.account_fingerprint.fingerprint_id,
account_id,
success=True
)
logger.info("Fingerprint-Statistiken für erfolgreichen Login aktualisiert")
except Exception as e:
logger.warning(f"Fehler beim Aktualisieren der Fingerprint-Statistiken: {e}")
# Status aktualisieren
self.status.update(result)
return result
except Exception as e:
error_msg = f"Unerwarteter Fehler beim Login: {str(e)}"
logger.error(error_msg, exc_info=True)
# Fehler-Screenshot
self._take_screenshot(f"login_error_{int(time.time())}")
self.status.update({
"success": False,
"error": error_msg,
"stage": "error"
})
return self.status
finally:
# Browser offen lassen für User-Kontrolle
logger.info("Login abgeschlossen - Browser bleibt offen")
def _initialize_browser_with_fingerprint(self, account_id: str) -> bool:
"""
Initialisiert den Browser mit einem Account-spezifischen Fingerprint.
Args:
account_id: Account-ID für den Fingerprint
Returns:
bool: True bei Erfolg, False bei Fehler
"""
try:
# Lade gespeicherten Fingerprint für Account
saved_fingerprint = self.fingerprint_service.get_fingerprint_for_account(account_id, "facebook")
if saved_fingerprint:
logger.info(f"Verwende gespeicherten Fingerprint für Account {account_id}")
self.provided_fingerprint = saved_fingerprint
else:
logger.info(f"Kein gespeicherter Fingerprint für Account {account_id}, generiere neuen")
self.provided_fingerprint = self.fingerprint_service.generate_fingerprint("facebook")
# Browser mit Fingerprint initialisieren
return self._initialize_browser()
except Exception as e:
logger.error(f"Fehler bei Browser-Initialisierung mit Fingerprint: {e}")
return False
def _generate_email(self, first_name: str, last_name: str) -> str:
"""
Generiert eine E-Mail-Adresse basierend auf dem Namen.
Args:
first_name: Vorname
last_name: Nachname
Returns:
str: Generierte E-Mail-Adresse
"""
# Entferne Umlaute und Sonderzeichen
first_clean = first_name.lower().replace('ä', 'ae').replace('ö', 'oe').replace('ü', 'ue').replace('ß', 'ss')
last_clean = last_name.lower().replace('ä', 'ae').replace('ö', 'oe').replace('ü', 'ue').replace('ß', 'ss')
# Verschiedene E-Mail-Formate
formats = [
f"{first_clean}.{last_clean}",
f"{first_clean}{last_clean}",
f"{first_clean[0]}{last_clean}",
f"{first_clean}_{last_clean}",
f"{last_clean}.{first_clean}",
]
# Wähle zufälliges Format
base_email = random.choice(formats)
# Füge optional Zahlen hinzu
if random.random() > 0.5:
base_email += str(random.randint(1, 999))
# Füge Domain hinzu
return f"{base_email}@{self.email_domain}"

Datei anzeigen

@ -0,0 +1,58 @@
# 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 time
from typing import Dict, Any
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}")
# TODO: Implementierung sobald Login-Details verfügbar
logger.warning("Facebook-Login noch nicht vollständig implementiert")
return {
"success": False,
"error": "Login-Funktion noch nicht implementiert",
"stage": "not_implemented"
}

Datei anzeigen

@ -0,0 +1,630 @@
# social_networks/facebook/facebook_registration.py
"""
Facebook-Registrierung - Klasse für die Registrierungsfunktionalität bei Facebook
"""
import logging
import time
import re
from typing import Dict, List, Any, Optional, Tuple
from .facebook_selectors import FacebookSelectors
from .facebook_workflow import FacebookWorkflow
from utils.logger import setup_logger
# Konfiguriere Logger
logger = setup_logger("facebook_registration")
class FacebookRegistration:
"""
Klasse für die Registrierung neuer Facebook-Konten.
Enthält alle Methoden für den Registrierungsprozess.
"""
def __init__(self, automation):
"""
Initialisiert die Facebook-Registrierungs-Funktionalität.
Args:
automation: Referenz auf die Hauptautomatisierungsklasse
"""
self.automation = automation
self.selectors = FacebookSelectors()
self.workflow = FacebookWorkflow.get_registration_workflow()
logger.debug("Facebook-Registrierung initialisiert")
def register_account(self, account_data: Dict[str, Any]) -> Dict[str, Any]:
"""
Führt den Registrierungsprozess für einen neuen Facebook-Account durch.
Args:
account_data: Dictionary mit Account-Daten
Returns:
Dict[str, Any]: Ergebnis der Registrierung
"""
logger.info(f"Starte Facebook-Registrierung für {account_data['first_name']} {account_data['last_name']}")
try:
# 1. Zur Facebook-Hauptseite navigieren
self.automation._send_status_update("Öffne Facebook-Webseite")
self.automation._send_log_update("Navigiere zu Facebook...")
if not self._navigate_to_facebook():
return {
"success": False,
"error": "Konnte nicht zu Facebook navigieren",
"stage": "navigation"
}
# 2. Cookie-Consent behandeln
self.automation._send_status_update("Behandle Cookie-Einstellungen")
self.automation._send_log_update("Lehne optionale Cookies ab...")
if not self._handle_cookie_consent():
logger.warning("Cookie-Consent konnte nicht behandelt werden, fahre trotzdem fort")
# 3. Registrierungsformular öffnen
self.automation._send_status_update("Öffne Registrierungsformular")
self.automation._send_log_update("Klicke auf 'Neues Konto erstellen'...")
if not self._open_registration_form():
return {
"success": False,
"error": "Konnte Registrierungsformular nicht öffnen",
"stage": "open_form"
}
# 4. Registrierungsformular ausfüllen
self.automation._send_status_update("Fülle Registrierungsformular aus")
self.automation._send_log_update("Gebe persönliche Daten ein...")
if not self._fill_registration_form(account_data):
return {
"success": False,
"error": "Fehler beim Ausfüllen des Registrierungsformulars",
"stage": "fill_form"
}
# 5. Formular absenden
self.automation._send_status_update("Sende Registrierung ab")
self.automation._send_log_update("Klicke auf 'Registrieren'...")
if not self._submit_registration():
return {
"success": False,
"error": "Fehler beim Absenden der Registrierung",
"stage": "submit"
}
# 6. E-Mail-Verifikation behandeln
needs_verification = self._check_needs_verification()
if needs_verification:
self.automation._send_status_update("E-Mail-Verifikation erforderlich")
self.automation._send_log_update("Warte auf Verifikationscode...")
# Warte auf Verifikationscode
verification_code = self._wait_for_verification_code(account_data.get("email"))
if verification_code:
if not self._enter_verification_code(verification_code):
return {
"success": False,
"error": "Fehler bei der E-Mail-Verifikation",
"stage": "verification"
}
else:
return {
"success": False,
"error": "Verifikationscode nicht erhalten",
"stage": "verification_timeout"
}
# 7. Erfolgreiche Registrierung überprüfen
if not self._check_registration_success():
return {
"success": False,
"error": "Registrierung fehlgeschlagen",
"stage": "final_check"
}
# Registrierung erfolgreich
logger.info(f"Facebook-Account erfolgreich erstellt")
self.automation._send_status_update("Registrierung erfolgreich!")
self.automation._send_log_update("Account wurde erfolgreich erstellt")
# Account-Daten für Rückgabe vorbereiten
account_data["platform"] = "facebook"
account_data["created_at"] = time.time()
return {
"success": True,
"stage": "completed",
"account_data": account_data
}
except Exception as e:
error_msg = f"Unerwarteter Fehler bei der Facebook-Registrierung: {str(e)}"
logger.error(error_msg, exc_info=True)
return {
"success": False,
"error": error_msg,
"stage": "exception",
"account_data": account_data
}
def _navigate_to_facebook(self) -> bool:
"""
Navigiert zur Facebook-Hauptseite.
Returns:
bool: True bei Erfolg
"""
try:
logger.info(f"Navigiere zu {self.automation.base_url}")
# Navigiere zur Facebook-Seite
self.automation.browser.navigate_to(self.automation.base_url)
# Warte auf Seitenladung
self.automation.human_behavior.wait_for_page_load(multiplier=1.5)
# Screenshot
self.automation._take_screenshot("facebook_homepage")
# Prüfe ob wir auf Facebook sind
current_url = self.automation.browser.page.url
if "facebook.com" in current_url:
logger.info("Erfolgreich zu Facebook navigiert")
return True
else:
logger.error(f"Nicht auf Facebook gelandet: {current_url}")
return False
except Exception as e:
logger.error(f"Fehler bei Navigation zu Facebook: {e}")
return False
def _handle_cookie_consent(self) -> bool:
"""
Behandelt den Cookie-Consent-Dialog.
Returns:
bool: True wenn behandelt
"""
try:
logger.info("Prüfe auf Cookie-Consent-Dialog")
# Warte kurz auf möglichen Cookie-Dialog
self.automation.human_behavior.random_delay(1.0, 2.0)
# Versuche "Optionale Cookies ablehnen" zu klicken
decline_clicked = False
# Methode 1: Direkter Selektor
if self.automation.browser.is_element_visible(self.selectors.COOKIE_DECLINE_BUTTON, timeout=2000):
if self.automation.browser.click_element(self.selectors.COOKIE_DECLINE_BUTTON):
logger.info("Cookie-Consent abgelehnt (Methode 1)")
decline_clicked = True
# Methode 2: Alternative Selektoren
if not decline_clicked:
for selector in [self.selectors.COOKIE_DECLINE_BUTTON_ALT,
"button:has-text('Optionale Cookies ablehnen')",
"//button[contains(., 'Optionale Cookies ablehnen')]"]:
try:
if self.automation.browser.click_element(selector, timeout=1000):
logger.info(f"Cookie-Consent abgelehnt mit Selektor: {selector}")
decline_clicked = True
break
except:
continue
# Methode 3: Fuzzy Button Click
if not decline_clicked:
if self.automation.ui_helper.click_button_fuzzy(
self.selectors.get_button_texts("decline_cookies"),
fallback_selector="button"
):
logger.info("Cookie-Consent abgelehnt (Fuzzy Match)")
decline_clicked = True
if decline_clicked:
# Warte auf Dialog-Schließung
self.automation.human_behavior.random_delay(1.0, 2.0)
self.automation._take_screenshot("after_cookie_consent")
return True
else:
logger.debug("Kein Cookie-Consent-Dialog gefunden oder bereits behandelt")
return False
except Exception as e:
logger.error(f"Fehler bei Cookie-Consent-Behandlung: {e}")
return False
def _open_registration_form(self) -> bool:
"""
Öffnet das Registrierungsformular.
Returns:
bool: True bei Erfolg
"""
try:
logger.info("Öffne Registrierungsformular")
# Versuche "Neues Konto erstellen" zu klicken
button_clicked = False
# Methode 1: data-testid Selektor
if self.automation.browser.is_element_visible(self.selectors.CREATE_ACCOUNT_BUTTON, timeout=3000):
if self.automation.browser.click_element(self.selectors.CREATE_ACCOUNT_BUTTON):
logger.info("Registrierungsformular geöffnet (data-testid)")
button_clicked = True
# Methode 2: Alternative Selektoren
if not button_clicked:
for selector in [self.selectors.CREATE_ACCOUNT_BUTTON_ALT,
"a:has-text('Neues Konto erstellen')",
"a[href*='/r.php']"]:
try:
if self.automation.browser.click_element(selector, timeout=2000):
logger.info(f"Registrierungsformular geöffnet mit: {selector}")
button_clicked = True
break
except:
continue
# Methode 3: Fuzzy Button Click
if not button_clicked:
if self.automation.ui_helper.click_button_fuzzy(
self.selectors.get_button_texts("create_account")
):
logger.info("Registrierungsformular geöffnet (Fuzzy Match)")
button_clicked = True
if button_clicked:
# Warte auf Formular-Ladung
self.automation.human_behavior.wait_for_page_load()
self.automation._take_screenshot("registration_form")
# 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
logger.error("Konnte Registrierungsformular nicht öffnen")
return False
except Exception as e:
logger.error(f"Fehler beim Öffnen des Registrierungsformulars: {e}")
return False
def _fill_registration_form(self, account_data: Dict[str, Any]) -> bool:
"""
Füllt das Registrierungsformular aus.
Args:
account_data: Account-Daten
Returns:
bool: True bei Erfolg
"""
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")
return False
# Nachname
if not self.automation.ui_helper.type_text_human_like(
self.selectors.REG_LASTNAME_FIELD,
account_data["last_name"]
):
logger.error("Fehler beim Eingeben des Nachnamens")
return False
# Geburtsdatum
birth_date = account_data["birth_date"]
# Tag auswählen
if not self.automation.browser.select_option(
self.selectors.REG_BIRTHDAY_DAY,
str(birth_date["day"])
):
logger.error("Fehler beim Auswählen des Geburtstags")
return False
# Monat auswählen
if not self.automation.browser.select_option(
self.selectors.REG_BIRTHDAY_MONTH,
str(birth_date["month"])
):
logger.error("Fehler beim Auswählen des Geburtsmonats")
return False
# Jahr auswählen
if not self.automation.browser.select_option(
self.selectors.REG_BIRTHDAY_YEAR,
str(birth_date["year"])
):
logger.error("Fehler beim Auswählen des Geburtsjahrs")
return False
self.automation.human_behavior.random_delay(0.5, 1.0)
# Geschlecht auswählen
gender_selector = self.selectors.get_gender_selector(account_data["gender"])
if not self.automation.browser.click_element(gender_selector):
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")
return False
if not self.automation.ui_helper.type_text_human_like(
self.selectors.REG_EMAIL_OR_PHONE,
contact_field
):
logger.error("Fehler beim Eingeben der Kontaktdaten")
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")
# Passwort
if not self.automation.ui_helper.type_text_human_like(
self.selectors.REG_PASSWORD,
account_data["password"]
):
logger.error("Fehler beim Eingeben des Passworts")
return False
# Screenshot des ausgefüllten Formulars
self.automation._take_screenshot("filled_registration_form")
logger.info("Registrierungsformular erfolgreich ausgefüllt")
return True
except Exception as e:
logger.error(f"Fehler beim Ausfüllen des Registrierungsformulars: {e}")
return False
def _submit_registration(self) -> bool:
"""
Sendet das Registrierungsformular ab.
Returns:
bool: True bei Erfolg
"""
try:
logger.info("Sende Registrierungsformular ab")
# Versuche Submit-Button zu klicken
submit_clicked = False
# Methode 1: Name-Attribut
if self.automation.browser.is_element_visible(self.selectors.REG_SUBMIT_BUTTON, timeout=2000):
if self.automation.browser.click_element(self.selectors.REG_SUBMIT_BUTTON):
logger.info("Registrierung abgesendet (name-Attribut)")
submit_clicked = True
# Methode 2: Text-basiert
if not submit_clicked:
for text in self.selectors.get_button_texts("register"):
selector = f"button:has-text('{text}')"
try:
if self.automation.browser.click_element(selector, timeout=1000):
logger.info(f"Registrierung abgesendet mit: {selector}")
submit_clicked = True
break
except:
continue
# Methode 3: Fuzzy Match
if not submit_clicked:
if self.automation.ui_helper.click_button_fuzzy(
self.selectors.get_button_texts("register")
):
logger.info("Registrierung abgesendet (Fuzzy Match)")
submit_clicked = True
if submit_clicked:
# Warte auf Navigation
self.automation.human_behavior.wait_for_page_load(multiplier=2.0)
self.automation._take_screenshot("after_submit")
return True
else:
logger.error("Konnte Registrierung nicht absenden")
return False
except Exception as e:
logger.error(f"Fehler beim Absenden der Registrierung: {e}")
return False
def _check_needs_verification(self) -> bool:
"""
Prüft ob eine E-Mail-Verifikation erforderlich ist.
Returns:
bool: True wenn Verifikation erforderlich
"""
try:
# Warte kurz
self.automation.human_behavior.random_delay(2.0, 3.0)
# Prüfe URL
current_url = self.automation.browser.page.url
if "confirmemail" in current_url or "confirm" in current_url:
logger.info("E-Mail-Verifikation erforderlich (URL-Check)")
return True
# Prüfe auf Verifikations-Input
if self.automation.browser.is_element_visible(self.selectors.VERIFICATION_CODE_INPUT, timeout=2000):
logger.info("E-Mail-Verifikation erforderlich (Input-Field)")
return True
# Prüfe auf Verifikations-Text
page_content = self.automation.browser.page.content().lower()
verification_keywords = ["bestätigungscode", "verification code", "confirm email", "code eingeben"]
for keyword in verification_keywords:
if keyword in page_content:
logger.info(f"E-Mail-Verifikation erforderlich (Keyword: {keyword})")
return True
logger.info("Keine E-Mail-Verifikation erforderlich")
return False
except Exception as e:
logger.error(f"Fehler bei Verifikations-Check: {e}")
return False
def _wait_for_verification_code(self, email: str) -> Optional[str]:
"""
Wartet auf den Verifikationscode aus der E-Mail.
Args:
email: E-Mail-Adresse
Returns:
Optional[str]: Verifikationscode oder None
"""
logger.info(f"Warte auf Verifikationscode für {email}")
# Delegiere an Verification-Klasse
return self.automation.verification.wait_for_email_code(email, timeout=120)
def _enter_verification_code(self, code: str) -> bool:
"""
Gibt den Verifikationscode ein.
Args:
code: Verifikationscode
Returns:
bool: True bei Erfolg
"""
try:
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")
return False
# Weiter-Button klicken
continue_clicked = False
# Versuche verschiedene Selektoren
for text in self.selectors.get_button_texts("continue"):
selector = f"button:has-text('{text}')"
try:
if self.automation.browser.click_element(selector, timeout=1000):
logger.info(f"Verifikation fortgesetzt mit: {selector}")
continue_clicked = True
break
except:
continue
# Oder Enter drücken
if not continue_clicked:
self.automation.browser.page.keyboard.press("Enter")
logger.info("Verifikation mit Enter fortgesetzt")
# Warte auf Navigation
self.automation.human_behavior.wait_for_page_load()
# 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")
return True
except Exception as e:
logger.error(f"Fehler beim Eingeben des Verifikationscodes: {e}")
return False
def _check_registration_success(self) -> bool:
"""
Überprüft ob die Registrierung erfolgreich war.
Returns:
bool: True bei Erfolg
"""
try:
# Warte auf finale Navigation
self.automation.human_behavior.wait_for_page_load(multiplier=2.0)
# Screenshot
self.automation._take_screenshot("registration_final")
# Prüfe URL
current_url = self.automation.browser.page.url
logger.info(f"Finale URL: {current_url}")
# Erfolgs-URLs
success_patterns = [
"facebook.com/?",
"facebook.com/home",
"facebook.com/feed",
"welcome",
"onboarding"
]
for pattern in success_patterns:
if pattern in current_url:
logger.info(f"Registrierung erfolgreich (URL-Pattern: {pattern})")
return True
# Prüfe auf Erfolgs-Indikatoren
for indicator in self.selectors.SUCCESS_INDICATORS:
if self.automation.browser.is_element_visible(indicator, timeout=2000):
logger.info(f"Registrierung erfolgreich (Indikator: {indicator})")
return True
# Prüfe auf Fehler
if self.automation.browser.is_element_visible(self.selectors.ERROR_MESSAGE, timeout=1000):
error_text = self.automation.browser.get_text(self.selectors.ERROR_MESSAGE)
logger.error(f"Registrierungsfehler: {error_text}")
return False
# Bei Unsicherheit als erfolgreich werten wenn keine Login-Form mehr da ist
if not self.automation.browser.is_element_visible(self.selectors.REG_FIRSTNAME_FIELD, timeout=1000):
logger.info("Registrierung wahrscheinlich erfolgreich (kein Formular mehr sichtbar)")
return True
logger.warning("Registrierungsstatus unklar")
return False
except Exception as e:
logger.error(f"Fehler bei Erfolgs-Check: {e}")
return False

Datei anzeigen

@ -0,0 +1,173 @@
"""
Facebook-Selektoren für die Automatisierung.
Basierend auf dem aktuellen Facebook UI (2024/2025).
"""
from typing import List, Dict, Any
class FacebookSelectors:
"""
Zentrale Sammlung aller Facebook-Selektoren für die Automatisierung.
"""
# ===== COOKIE CONSENT =====
COOKIE_DIALOG = "div[role='dialog']"
COOKIE_DECLINE_BUTTON = "div.html-div span:has-text('Optionale Cookies ablehnen')"
COOKIE_DECLINE_BUTTON_ALT = "//span[contains(text(), 'Optionale Cookies ablehnen')]"
COOKIE_ACCEPT_BUTTON = "button:has-text('Alle Cookies erlauben')"
# ===== LANDING PAGE =====
CREATE_ACCOUNT_BUTTON = "a[data-testid='open-registration-form-button']"
CREATE_ACCOUNT_BUTTON_ALT = "a:has-text('Neues Konto erstellen')"
CREATE_ACCOUNT_BUTTON_ID = "#u_0_0_gL" # ID kann sich ändern
# ===== LOGIN FORM =====
LOGIN_EMAIL_FIELD = "input[name='email']"
LOGIN_PASSWORD_FIELD = "input[name='pass']"
LOGIN_BUTTON = "button[name='login']"
LOGIN_BUTTON_ALT = "button[data-testid='royal_login_button']"
# ===== REGISTRATION FORM =====
# Name fields
REG_FIRSTNAME_FIELD = "input[name='firstname']"
REG_LASTNAME_FIELD = "input[name='lastname']"
# Birthday selects
REG_BIRTHDAY_DAY = "select[name='birthday_day']"
REG_BIRTHDAY_MONTH = "select[name='birthday_month']"
REG_BIRTHDAY_YEAR = "select[name='birthday_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']"
# Contact info
REG_EMAIL_OR_PHONE = "input[name='reg_email__']"
REG_EMAIL_CONFIRM = "input[name='reg_email_confirmation__']" # Erscheint wenn Email eingegeben
# Password
REG_PASSWORD = "input[name='reg_passwd__']"
REG_PASSWORD_ALT = "input#password_step_input"
# Submit button
REG_SUBMIT_BUTTON = "button[name='websubmit']"
REG_SUBMIT_BUTTON_ALT = "button:has-text('Registrieren')"
REG_SUBMIT_BUTTON_EN = "button:has-text('Sign Up')"
# ===== EMAIL VERIFICATION =====
VERIFICATION_CODE_INPUT = "input#code_in_cliff"
VERIFICATION_CODE_INPUT_ALT = "input[name='code']"
VERIFICATION_CONTINUE_BUTTON = "button:has-text('Weiter')"
VERIFICATION_CONTINUE_BUTTON_EN = "button:has-text('Continue')"
# Verification success popup
VERIFICATION_OK_BUTTON = "a.layerCancel:has-text('OK')"
VERIFICATION_OK_BUTTON_ALT = "a[role='button']:has-text('OK')"
# ===== ERROR MESSAGES =====
ERROR_MESSAGE = "div[role='alert']"
ERROR_MESSAGE_ALT = "div.uiContextualLayer"
FIELD_ERROR = "div._5v-0._53im"
# ===== SUCCESS INDICATORS =====
SUCCESS_INDICATORS = [
"div[role='navigation']", # Navigation bar
"div[role='main']", # Main feed
"div[data-pagelet='Feed']", # Feed container
"a[href='/me/']", # Profile link
"div[aria-label='Facebook']", # Facebook logo
]
# ===== DIALOGS & POPUPS =====
DIALOG_CLOSE_BUTTON = "div[aria-label='Schließen']"
DIALOG_CLOSE_BUTTON_EN = "div[aria-label='Close']"
SKIP_BUTTON = "a:has-text('Überspringen')"
SKIP_BUTTON_EN = "a:has-text('Skip')"
NOT_NOW_BUTTON = "a:has-text('Jetzt nicht')"
NOT_NOW_BUTTON_EN = "a:has-text('Not Now')"
# ===== URLS =====
BASE_URL = "https://www.facebook.com"
BASE_URL_DE = "https://www.facebook.com/?locale=de_DE"
REGISTRATION_URL = "https://www.facebook.com/r.php"
LOGIN_URL = "https://www.facebook.com/login"
CONFIRM_EMAIL_URL = "https://www.facebook.com/confirmemail.php"
# ===== BUTTON TEXTS (für Fuzzy Matching) =====
BUTTON_TEXTS = {
"create_account": ["Neues Konto erstellen", "Create new account", "Sign up"],
"register": ["Registrieren", "Sign Up", "Register"],
"login": ["Anmelden", "Log In", "Login"],
"continue": ["Weiter", "Continue", "Next"],
"skip": ["Überspringen", "Skip", "Later"],
"decline_cookies": ["Optionale Cookies ablehnen", "Decline optional cookies", "Reject"],
"accept_cookies": ["Alle Cookies erlauben", "Allow all cookies", "Accept all"],
"ok": ["OK", "Okay"],
"not_now": ["Jetzt nicht", "Not Now", "Later"],
}
# ===== MONTH NAMES (für Birthday) =====
MONTH_NAMES_DE = {
1: "Jan.", 2: "Feb.", 3: "März", 4: "Apr.",
5: "Mai", 6: "Juni", 7: "Juli", 8: "Aug.",
9: "Sept.", 10: "Okt.", 11: "Nov.", 12: "Dez."
}
MONTH_NAMES_EN = {
1: "Jan", 2: "Feb", 3: "Mar", 4: "Apr",
5: "May", 6: "Jun", 7: "Jul", 8: "Aug",
9: "Sep", 10: "Oct", 11: "Nov", 12: "Dec"
}
@classmethod
def get_button_texts(cls, button_type: str) -> List[str]:
"""
Gibt eine Liste von möglichen Button-Texten zurück.
Args:
button_type: Typ des Buttons
Returns:
Liste von möglichen Texten
"""
return cls.BUTTON_TEXTS.get(button_type, [])
@classmethod
def get_month_name(cls, month: int, language: str = "de") -> str:
"""
Gibt den Monatsnamen für die Auswahl zurück.
Args:
month: Monatszahl (1-12)
language: Sprache ("de" oder "en")
Returns:
Monatsname
"""
if language == "de":
return cls.MONTH_NAMES_DE.get(month, str(month))
else:
return cls.MONTH_NAMES_EN.get(month, str(month))
@classmethod
def get_gender_selector(cls, gender: str) -> str:
"""
Gibt den passenden Selektor für das Geschlecht zurück.
Args:
gender: "male", "female" oder "custom"
Returns:
CSS-Selektor für das Geschlecht
"""
gender_map = {
"female": cls.REG_GENDER_FEMALE,
"male": cls.REG_GENDER_MALE,
"custom": cls.REG_GENDER_CUSTOM,
"weiblich": cls.REG_GENDER_FEMALE,
"männlich": cls.REG_GENDER_MALE,
"divers": cls.REG_GENDER_CUSTOM,
}
return gender_map.get(gender.lower(), cls.REG_GENDER_CUSTOM)

Datei anzeigen

@ -0,0 +1,341 @@
# social_networks/facebook/facebook_ui_helper.py
"""
Facebook UI Helper - Hilfsklasse für UI-Interaktionen bei Facebook
"""
import logging
import time
import random
from typing import List, Union, Optional
from .facebook_selectors import FacebookSelectors
from utils.text_similarity import TextSimilarity
from utils.logger import setup_logger
logger = setup_logger("facebook_ui_helper")
class FacebookUIHelper:
"""
Hilfsklasse für UI-Interaktionen bei Facebook.
Bietet Methoden für menschenähnliche Interaktionen.
"""
def __init__(self, automation):
"""
Initialisiert den UI Helper.
Args:
automation: Referenz auf die Hauptautomatisierungsklasse
"""
self.automation = automation
self.selectors = FacebookSelectors()
self.text_similarity = TextSimilarity(default_threshold=0.7)
logger.debug("Facebook UI Helper initialisiert")
def _ensure_browser(self) -> bool:
"""
Stellt sicher, dass der Browser verfügbar ist.
Returns:
bool: True wenn Browser verfügbar
"""
if not self.automation.browser or not hasattr(self.automation.browser, 'page'):
logger.error("Browser nicht verfügbar")
return False
return True
def type_text_human_like(self, selector: str, text: str, delay_range: tuple = (50, 150)) -> bool:
"""
Tippt Text menschenähnlich mit zufälligen Verzögerungen.
Args:
selector: CSS-Selektor des Eingabefelds
text: Einzugebender Text
delay_range: Bereich für Verzögerung zwischen Tastenanschlägen in ms
Returns:
bool: True bei Erfolg
"""
if not self._ensure_browser():
return False
try:
# Element fokussieren
if not self.automation.browser.click_element(selector):
logger.error(f"Konnte Element nicht fokussieren: {selector}")
return False
# Kurze Pause nach Fokus
self.automation.human_behavior.random_delay(0.2, 0.5)
# Feld leeren (dreifach-klick und löschen)
self.automation.browser.page.click(selector, click_count=3)
self.automation.browser.page.keyboard.press("Delete")
# Text Zeichen für Zeichen eingeben
for char in text:
self.automation.browser.page.keyboard.type(char)
# Zufällige Verzögerung zwischen Zeichen
delay_ms = random.randint(*delay_range)
time.sleep(delay_ms / 1000)
# Gelegentlich längere Pause (Denken)
if random.random() < 0.1:
self.automation.human_behavior.random_delay(0.3, 0.8)
# Sehr selten Tippfehler simulieren und korrigieren
if random.random() < 0.02 and len(text) > 5:
# Falschen Buchstaben tippen
wrong_char = random.choice('abcdefghijklmnopqrstuvwxyz')
self.automation.browser.page.keyboard.type(wrong_char)
time.sleep(random.randint(100, 300) / 1000)
# Korrigieren
self.automation.browser.page.keyboard.press("Backspace")
time.sleep(random.randint(50, 150) / 1000)
logger.debug(f"Text erfolgreich eingegeben in {selector}")
return True
except Exception as e:
logger.error(f"Fehler beim menschenähnlichen Tippen: {e}")
return False
def click_button_fuzzy(self, button_texts: Union[str, List[str]],
fallback_selector: str = None,
threshold: float = 0.7,
timeout: int = 5000) -> bool:
"""
Klickt einen Button mit Fuzzy-Text-Matching.
Args:
button_texts: Text oder Liste von Texten des Buttons
fallback_selector: CSS-Selektor für Fallback
threshold: Schwellenwert für Textähnlichkeit (0-1)
timeout: Zeitlimit für die Suche in Millisekunden
Returns:
bool: True bei Erfolg
"""
if not self._ensure_browser():
return False
try:
# Normalisiere button_texts zu einer Liste
if isinstance(button_texts, str):
button_texts = [button_texts]
logger.info(f"Suche nach Button mit Texten: {button_texts}")
# Versuche jeden Text
for target_text in button_texts:
# Methode 1: Exakter Text-Match mit has-text
selector = f"button:has-text('{target_text}')"
if self.automation.browser.is_element_visible(selector, timeout=1000):
if self.automation.browser.click_element(selector):
logger.info(f"Button geklickt (exakter Match): {target_text}")
return True
# Methode 2: Link als Button
selector = f"a:has-text('{target_text}')"
if self.automation.browser.is_element_visible(selector, timeout=1000):
if self.automation.browser.click_element(selector):
logger.info(f"Link-Button geklickt: {target_text}")
return True
# Methode 3: Div mit role="button"
selector = f"div[role='button']:has-text('{target_text}')"
if self.automation.browser.is_element_visible(selector, timeout=1000):
if self.automation.browser.click_element(selector):
logger.info(f"Div-Button geklickt: {target_text}")
return True
# Methode 4: Fuzzy-Matching mit allen Buttons
try:
all_buttons = self.automation.browser.page.query_selector_all("button, a[role='button'], div[role='button']")
for button in all_buttons:
button_text = button.inner_text().strip()
# Prüfe Ähnlichkeit mit jedem Zieltext
for target_text in button_texts:
similarity = self.text_similarity.calculate_similarity(button_text.lower(), target_text.lower())
if similarity >= threshold:
logger.info(f"Fuzzy-Match gefunden: '{button_text}' (Ähnlichkeit: {similarity:.2f})")
button.click()
return True
except Exception as e:
logger.debug(f"Fuzzy-Matching fehlgeschlagen: {e}")
# Fallback-Selektor verwenden
if fallback_selector:
if self.automation.browser.click_element(fallback_selector, timeout=timeout):
logger.info(f"Button geklickt mit Fallback-Selektor: {fallback_selector}")
return True
logger.warning(f"Konnte keinen Button mit Texten finden: {button_texts}")
return False
except Exception as e:
logger.error(f"Fehler beim Fuzzy-Button-Click: {e}")
return False
def scroll_to_element(self, selector: str) -> bool:
"""
Scrollt zu einem Element.
Args:
selector: CSS-Selektor des Elements
Returns:
bool: True bei Erfolg
"""
if not self._ensure_browser():
return False
try:
self.automation.browser.page.eval_on_selector(
selector,
"element => element.scrollIntoView({behavior: 'smooth', block: 'center'})"
)
# Warte auf Scroll-Animation
self.automation.human_behavior.random_delay(0.5, 1.0)
logger.debug(f"Zu Element gescrollt: {selector}")
return True
except Exception as e:
logger.error(f"Fehler beim Scrollen zu Element: {e}")
return False
def wait_for_element(self, selector: str, timeout: int = 10000, state: str = "visible") -> bool:
"""
Wartet auf ein Element.
Args:
selector: CSS-Selektor
timeout: Maximale Wartezeit in ms
state: Erwarteter Zustand ("visible", "hidden", "attached", "detached")
Returns:
bool: True wenn Element im erwarteten Zustand
"""
if not self._ensure_browser():
return False
try:
self.automation.browser.page.wait_for_selector(selector, timeout=timeout, state=state)
logger.debug(f"Element gefunden: {selector} (Zustand: {state})")
return True
except Exception as e:
logger.debug(f"Element nicht gefunden: {selector} - {e}")
return False
def handle_dialog(self, action: str = "accept") -> bool:
"""
Behandelt JavaScript-Dialoge (alert, confirm, prompt).
Args:
action: "accept" oder "dismiss"
Returns:
bool: True bei Erfolg
"""
if not self._ensure_browser():
return False
try:
# Dialog-Handler setzen
def handle_dialog(dialog):
logger.info(f"Dialog erkannt: {dialog.message}")
if action == "accept":
dialog.accept()
else:
dialog.dismiss()
self.automation.browser.page.on("dialog", handle_dialog)
# Kurz warten
time.sleep(0.5)
# Handler wieder entfernen
self.automation.browser.page.remove_listener("dialog", handle_dialog)
return True
except Exception as e:
logger.error(f"Fehler bei Dialog-Behandlung: {e}")
return False
def get_element_text(self, selector: str) -> Optional[str]:
"""
Holt den Text eines Elements.
Args:
selector: CSS-Selektor
Returns:
Optional[str]: Text des Elements oder None
"""
if not self._ensure_browser():
return None
try:
element = self.automation.browser.page.query_selector(selector)
if element:
return element.inner_text().strip()
return None
except Exception as e:
logger.error(f"Fehler beim Abrufen des Element-Texts: {e}")
return None
def fill_select_option(self, selector: str, value: str) -> bool:
"""
Wählt eine Option in einem Select-Element aus.
Args:
selector: CSS-Selektor des Select-Elements
value: Wert der zu wählenden Option
Returns:
bool: True bei Erfolg
"""
if not self._ensure_browser():
return False
try:
# Menschenähnliche Interaktion: Erst klicken, dann wählen
self.automation.browser.click_element(selector)
self.automation.human_behavior.random_delay(0.2, 0.5)
# Option auswählen
self.automation.browser.page.select_option(selector, value=value)
logger.debug(f"Option '{value}' ausgewählt in {selector}")
return True
except Exception as e:
logger.error(f"Fehler beim Auswählen der Option: {e}")
return False
def check_element_exists(self, selector: str, timeout: int = 1000) -> bool:
"""
Prüft ob ein Element existiert.
Args:
selector: CSS-Selektor
timeout: Maximale Wartezeit in ms
Returns:
bool: True wenn Element existiert
"""
if not self._ensure_browser():
return False
return self.automation.browser.is_element_visible(selector, timeout=timeout)

Datei anzeigen

@ -0,0 +1,293 @@
# social_networks/facebook/facebook_utils.py
"""
Facebook Utils - Hilfsfunktionen für Facebook-Automatisierung
"""
import logging
import random
import re
from typing import Optional, List, Dict, Any
from utils.logger import setup_logger
logger = setup_logger("facebook_utils")
class FacebookUtils:
"""
Hilfsklasse mit Utility-Funktionen für Facebook.
"""
def __init__(self, automation):
"""
Initialisiert die Utils-Klasse.
Args:
automation: Referenz auf die Hauptautomatisierungsklasse
"""
self.automation = automation
logger.debug("Facebook Utils initialisiert")
@staticmethod
def validate_email(email: str) -> bool:
"""
Validiert eine E-Mail-Adresse.
Args:
email: E-Mail-Adresse
Returns:
bool: True wenn gültig
"""
pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
return bool(re.match(pattern, email))
@staticmethod
def validate_phone(phone: str) -> bool:
"""
Validiert eine Telefonnummer.
Args:
phone: Telefonnummer
Returns:
bool: True wenn gültig
"""
# Entferne alle Nicht-Ziffern
digits_only = re.sub(r'\D', '', phone)
# Prüfe Länge (international 7-15 Ziffern)
return 7 <= len(digits_only) <= 15
@staticmethod
def generate_username_from_name(first_name: str, last_name: str) -> str:
"""
Generiert einen Benutzernamen aus Vor- und Nachname.
Args:
first_name: Vorname
last_name: Nachname
Returns:
str: Generierter Benutzername
"""
# Bereinige Namen
first_clean = re.sub(r'[^a-zA-Z]', '', first_name.lower())
last_clean = re.sub(r'[^a-zA-Z]', '', last_name.lower())
# Verschiedene Formate
formats = [
f"{first_clean}.{last_clean}",
f"{first_clean}{last_clean}",
f"{first_clean}_{last_clean}",
f"{first_clean[0]}{last_clean}",
f"{last_clean}.{first_clean}",
]
username = random.choice(formats)
# Füge optional Zahlen hinzu
if random.random() > 0.5:
username += str(random.randint(1, 999))
return username
@staticmethod
def format_phone_number(phone: str, country_code: str = "+49") -> str:
"""
Formatiert eine Telefonnummer.
Args:
phone: Telefonnummer
country_code: Ländervorwahl
Returns:
str: Formatierte Telefonnummer
"""
# Entferne alle Nicht-Ziffern
digits = re.sub(r'\D', '', phone)
# Füge Ländervorwahl hinzu wenn nicht vorhanden
if not phone.startswith('+'):
return f"{country_code}{digits}"
return f"+{digits}"
@staticmethod
def is_valid_password(password: str) -> bool:
"""
Prüft ob ein Passwort den Facebook-Anforderungen entspricht.
Facebook-Anforderungen:
- Mindestens 6 Zeichen
- Kombination aus Buchstaben, Zahlen und/oder Sonderzeichen empfohlen
Args:
password: Zu prüfendes Passwort
Returns:
bool: True wenn gültig
"""
if len(password) < 6:
return False
# Prüfe auf verschiedene Zeichentypen (empfohlen, nicht erforderlich)
has_letter = bool(re.search(r'[a-zA-Z]', password))
has_digit = bool(re.search(r'\d', password))
has_special = bool(re.search(r'[!@#$%^&*(),.?":{}|<>]', password))
# Mindestens 2 verschiedene Zeichentypen empfohlen
char_types = sum([has_letter, has_digit, has_special])
if char_types < 2:
logger.warning("Passwort sollte mindestens 2 verschiedene Zeichentypen enthalten")
return True
def detect_language(self) -> str:
"""
Erkennt die aktuelle Sprache der Facebook-Seite.
Returns:
str: Sprachcode ("de", "en", etc.)
"""
try:
# Prüfe HTML lang-Attribut
lang = self.automation.browser.page.get_attribute("html", "lang")
if lang:
return lang[:2] # Erste 2 Zeichen (de, en, etc.)
# Prüfe Meta-Tags
meta_lang = self.automation.browser.page.get_attribute(
"meta[property='og:locale']", "content"
)
if meta_lang:
return meta_lang[:2]
# Fallback: Prüfe Text-Inhalte
page_content = self.automation.browser.page.content().lower()
german_keywords = ["anmelden", "registrieren", "passwort", "konto"]
english_keywords = ["login", "register", "password", "account"]
german_count = sum(1 for kw in german_keywords if kw in page_content)
english_count = sum(1 for kw in english_keywords if kw in page_content)
if german_count > english_count:
return "de"
else:
return "en"
except Exception as e:
logger.error(f"Fehler bei Spracherkennung: {e}")
return "en" # Fallback zu Englisch
def extract_error_message(self) -> Optional[str]:
"""
Extrahiert Fehlermeldungen von der Seite.
Returns:
Optional[str]: Fehlermeldung oder None
"""
try:
# Verschiedene Fehler-Selektoren
error_selectors = [
"div[role='alert']",
"div.uiContextualLayer",
"div._5v-0._53im",
"div[data-testid='error']",
"span.error",
"div.error-message"
]
for selector in error_selectors:
try:
error_elem = self.automation.browser.page.query_selector(selector)
if error_elem and error_elem.is_visible():
error_text = error_elem.inner_text().strip()
if error_text:
logger.info(f"Fehlermeldung gefunden: {error_text}")
return error_text
except:
continue
# Prüfe auf bekannte Fehler-Keywords im Seiteninhalt
page_content = self.automation.browser.page.content()
error_patterns = [
r"(Fehler|Error):\s*([^<\n]+)",
r"(Problem|Issue):\s*([^<\n]+)",
r"class=\"error[^\"]*\"[^>]*>([^<]+)",
]
for pattern in error_patterns:
match = re.search(pattern, page_content, re.IGNORECASE)
if match:
error_text = match.group(1) if len(match.groups()) == 1 else match.group(2)
logger.info(f"Fehler-Pattern gefunden: {error_text}")
return error_text.strip()
return None
except Exception as e:
logger.error(f"Fehler beim Extrahieren der Fehlermeldung: {e}")
return None
@staticmethod
def parse_facebook_url(url: str) -> Dict[str, Any]:
"""
Parst eine Facebook-URL und extrahiert Informationen.
Args:
url: Facebook-URL
Returns:
Dict mit URL-Komponenten
"""
parsed = {
"is_facebook": "facebook.com" in url,
"is_login": "/login" in url or "/accounts/login" in url,
"is_registration": "/r.php" in url or "/reg" in url,
"is_checkpoint": "/checkpoint" in url,
"is_confirmation": "/confirmemail" in url,
"is_home": url.endswith("facebook.com/") or "/home" in url,
"has_error": "error=" in url or "err=" in url
}
# Extrahiere Query-Parameter
if "?" in url:
query_string = url.split("?")[1]
params = {}
for param in query_string.split("&"):
if "=" in param:
key, value = param.split("=", 1)
params[key] = value
parsed["params"] = params
return parsed
def take_debug_screenshot(self, name: str = "debug") -> str:
"""
Nimmt einen Debug-Screenshot auf.
Args:
name: Name für den Screenshot
Returns:
str: Pfad zum Screenshot
"""
return self.automation._take_screenshot(f"facebook_{name}")
@staticmethod
def get_random_user_agent() -> str:
"""
Gibt einen zufälligen User-Agent zurück.
Returns:
str: User-Agent String
"""
user_agents = [
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
]
return random.choice(user_agents)

Datei anzeigen

@ -0,0 +1,291 @@
# social_networks/facebook/facebook_verification.py
"""
Facebook-Verifikation - Klasse für die Verifikationsfunktionalität bei Facebook
Nutzt den gleichen EmailHandler wie Instagram.
"""
import logging
import time
import re
from typing import Optional, Dict, Any, List
from .facebook_selectors import FacebookSelectors
from utils.logger import setup_logger
logger = setup_logger("facebook_verification")
class FacebookVerification:
"""
Klasse für die Verifikation bei Facebook (E-Mail, SMS, etc.).
Nutzt den gleichen E-Mail-Service wie Instagram.
"""
def __init__(self, automation):
"""
Initialisiert die Facebook-Verifikations-Funktionalität.
Args:
automation: Referenz auf die Hauptautomatisierungsklasse
"""
self.automation = automation
self.selectors = FacebookSelectors()
logger.debug("Facebook-Verifikation initialisiert")
def wait_for_email_code(self, email: str, timeout: int = 120) -> Optional[str]:
"""
Wartet auf den Verifikationscode aus der E-Mail.
Nutzt den gleichen E-Mail-Service wie Instagram über EmailHandler.
Facebook-spezifisch:
- Betreff: "Dein Bestätigungscode lautet FB-12345"
- Code ist 5-stellig
Args:
email: E-Mail-Adresse
timeout: Maximale Wartezeit in Sekunden
Returns:
Optional[str]: 5-stelliger Verifikationscode oder None
"""
logger.info(f"Warte auf Verifikationscode für {email}")
try:
# Nutze den EmailHandler wie bei Instagram
verification_code = self.automation.email_handler.get_verification_code(
target_email=email,
platform="facebook",
max_attempts=timeout // 2, # 2 Sekunden pro Versuch
delay_seconds=2
)
if verification_code:
logger.info(f"Verifikationscode erhalten: {verification_code}")
return verification_code
logger.warning(f"Kein Verifikationscode nach {timeout} Sekunden erhalten")
return None
except Exception as e:
logger.error(f"Fehler beim Warten auf E-Mail-Code: {e}")
return None
def extract_code_from_email(self, email_content: str) -> Optional[str]:
"""
Extrahiert den Verifikationscode aus dem E-Mail-Inhalt.
Diese Methode wird vom EmailHandler aufgerufen.
Args:
email_content: Inhalt der E-Mail
Returns:
Optional[str]: 5-stelliger Code oder None
"""
try:
# Facebook-spezifische Patterns für Verifikationscode
# Betreff: "Dein Bestätigungscode lautet FB-12345"
patterns = [
r'FB-(\d{5})', # Format: FB-12345
r'Bestätigungscode lautet (\d{5})', # Deutscher Text
r'Bestätigungscode: (\d{5})', # Alternative
r'confirmation code is (\d{5})', # Englisch
r'verification code: (\d{5})', # Alternative Englisch
r'Code: (\d{5})', # Kurz
r'\b(\d{5})\b', # Jede 5-stellige Zahl als Fallback
]
for pattern in patterns:
match = re.search(pattern, email_content, re.IGNORECASE)
if match:
code = match.group(1) if '(' in pattern else match.group(0)
logger.info(f"Verifikationscode gefunden: {code}")
return code
logger.warning("Kein Verifikationscode im E-Mail-Inhalt gefunden")
return None
except Exception as e:
logger.error(f"Fehler beim Extrahieren des Codes: {e}")
return None
def handle_sms_verification(self, phone_number: str, timeout: int = 120) -> Optional[str]:
"""
Behandelt SMS-Verifikation (für zukünftige Implementierung).
Args:
phone_number: Telefonnummer
timeout: Maximale Wartezeit
Returns:
Optional[str]: SMS-Code oder None
"""
logger.info(f"SMS-Verifikation für {phone_number} angefordert")
# TODO: SMS-Service-Integration implementieren
# Könnte später den gleichen Service wie Instagram nutzen
logger.warning("SMS-Verifikation noch nicht implementiert")
return None
def handle_captcha(self) -> bool:
"""
Behandelt Captcha-Herausforderungen.
Returns:
bool: True bei Erfolg
"""
try:
logger.info("Prüfe auf Captcha")
# Captcha-Erkennung
captcha_selectors = [
"div[id*='captcha']",
"div[class*='captcha']",
"iframe[src*='recaptcha']",
"div[class*='recaptcha']"
]
captcha_found = False
for selector in captcha_selectors:
if self.automation.browser.is_element_visible(selector, timeout=1000):
captcha_found = True
logger.warning(f"Captcha erkannt: {selector}")
break
if captcha_found:
# Screenshot für manuelles Lösen
self.automation._take_screenshot("captcha_challenge")
# TODO: Captcha-Lösung implementieren
# Könnte die gleiche Strategie wie Instagram nutzen
logger.error("Captcha-Lösung noch nicht implementiert")
return False
logger.debug("Kein Captcha gefunden")
return True
except Exception as e:
logger.error(f"Fehler bei Captcha-Behandlung: {e}")
return False
def handle_identity_verification(self) -> bool:
"""
Behandelt Identitäts-Verifikation (Ausweis-Upload, etc.).
Returns:
bool: True bei Erfolg
"""
try:
logger.info("Prüfe auf Identitäts-Verifikation")
# Prüfe auf Identitäts-Verifikations-Anforderung
id_verification_keywords = [
"identität bestätigen",
"verify identity",
"ausweis hochladen",
"upload id",
"foto hochladen",
"upload photo"
]
page_content = self.automation.browser.page.content().lower()
for keyword in id_verification_keywords:
if keyword in page_content:
logger.warning(f"Identitäts-Verifikation erforderlich: {keyword}")
# Screenshot
self.automation._take_screenshot("identity_verification_required")
# Kann nicht automatisiert werden
return False
logger.debug("Keine Identitäts-Verifikation erforderlich")
return True
except Exception as e:
logger.error(f"Fehler bei Identitäts-Verifikations-Check: {e}")
return False
def handle_suspicious_activity(self) -> bool:
"""
Behandelt "Verdächtige Aktivität" Warnungen.
Returns:
bool: True wenn behandelt
"""
try:
logger.info("Prüfe auf verdächtige Aktivitäts-Warnungen")
# Prüfe auf Warnungen
suspicious_keywords = [
"verdächtige aktivität",
"suspicious activity",
"ungewöhnliche aktivität",
"unusual activity",
"sicherheitsprüfung",
"security check"
]
page_content = self.automation.browser.page.content().lower()
for keyword in suspicious_keywords:
if keyword in page_content:
logger.warning(f"Verdächtige Aktivitäts-Warnung: {keyword}")
# Screenshot
self.automation._take_screenshot("suspicious_activity")
# Versuche fortzufahren
continue_buttons = [
"button:has-text('Weiter')",
"button:has-text('Continue')",
"button:has-text('Fortfahren')"
]
for button in continue_buttons:
if self.automation.browser.click_element(button, timeout=2000):
logger.info("Verdächtige Aktivitäts-Dialog behandelt")
return True
return False
logger.debug("Keine verdächtige Aktivitäts-Warnung gefunden")
return True
except Exception as e:
logger.error(f"Fehler bei Behandlung verdächtiger Aktivität: {e}")
return False
def bypass_checkpoint(self) -> bool:
"""
Versucht Facebook Checkpoints zu umgehen.
Returns:
bool: True bei Erfolg
"""
try:
logger.info("Prüfe auf Facebook Checkpoint")
# Prüfe URL
current_url = self.automation.browser.page.url
if "checkpoint" in current_url:
logger.warning("Facebook Checkpoint erkannt")
# Screenshot
self.automation._take_screenshot("checkpoint")
# Checkpoint-Typen behandeln
# Diese könnten ähnlich wie bei Instagram behandelt werden
logger.error("Checkpoint-Umgehung noch nicht vollständig implementiert")
return False
logger.debug("Kein Checkpoint erkannt")
return True
except Exception as e:
logger.error(f"Fehler bei Checkpoint-Umgehung: {e}")
return False

Datei anzeigen

@ -0,0 +1,239 @@
# social_networks/facebook/facebook_workflow.py
"""
Facebook Workflow - Definiert die Arbeitsabläufe für Facebook-Automatisierung
"""
import logging
from typing import Dict, List, Any
from utils.logger import setup_logger
logger = setup_logger("facebook_workflow")
class FacebookWorkflow:
"""
Klasse zur Definition von Facebook-Workflows.
Enthält die Schritte für verschiedene Prozesse.
"""
@staticmethod
def get_registration_workflow() -> Dict[str, Any]:
"""
Gibt den Workflow für die Registrierung zurück.
Returns:
Dict mit Workflow-Schritten
"""
return {
"name": "Facebook Registration",
"steps": [
{
"id": "navigate",
"name": "Navigate to Facebook",
"description": "Öffne Facebook-Webseite",
"required": True,
"retry": 3
},
{
"id": "cookie_consent",
"name": "Handle Cookie Consent",
"description": "Lehne optionale Cookies ab",
"required": False,
"retry": 2
},
{
"id": "open_registration",
"name": "Open Registration Form",
"description": "Klicke auf 'Neues Konto erstellen'",
"required": True,
"retry": 3
},
{
"id": "fill_form",
"name": "Fill Registration Form",
"description": "Fülle Registrierungsformular aus",
"required": True,
"retry": 1,
"fields": [
"first_name",
"last_name",
"birth_date",
"gender",
"email_or_phone",
"password"
]
},
{
"id": "submit",
"name": "Submit Registration",
"description": "Klicke auf 'Registrieren'",
"required": True,
"retry": 2
},
{
"id": "email_verification",
"name": "Email Verification",
"description": "Verifiziere E-Mail-Adresse",
"required": False,
"retry": 3,
"timeout": 120
},
{
"id": "complete",
"name": "Complete Registration",
"description": "Schließe Registrierung ab",
"required": True,
"retry": 1
}
],
"error_handlers": {
"captcha": "handle_captcha",
"checkpoint": "handle_checkpoint",
"suspicious_activity": "handle_suspicious_activity"
}
}
@staticmethod
def get_login_workflow() -> Dict[str, Any]:
"""
Gibt den Workflow für den Login zurück.
Returns:
Dict mit Workflow-Schritten
"""
return {
"name": "Facebook Login",
"steps": [
{
"id": "navigate",
"name": "Navigate to Facebook",
"description": "Öffne Facebook-Webseite",
"required": True,
"retry": 3
},
{
"id": "cookie_consent",
"name": "Handle Cookie Consent",
"description": "Behandle Cookie-Banner",
"required": False,
"retry": 2
},
{
"id": "fill_credentials",
"name": "Fill Login Credentials",
"description": "Gebe E-Mail und Passwort ein",
"required": True,
"retry": 1
},
{
"id": "submit_login",
"name": "Submit Login",
"description": "Klicke auf 'Anmelden'",
"required": True,
"retry": 2
},
{
"id": "handle_2fa",
"name": "Handle 2FA",
"description": "Behandle Zwei-Faktor-Authentifizierung",
"required": False,
"retry": 3
},
{
"id": "handle_dialogs",
"name": "Handle Post-Login Dialogs",
"description": "Behandle Dialoge nach Login",
"required": False,
"retry": 1
},
{
"id": "verify_login",
"name": "Verify Login Success",
"description": "Überprüfe erfolgreichen Login",
"required": True,
"retry": 1
}
],
"error_handlers": {
"wrong_password": "handle_wrong_password",
"account_locked": "handle_account_locked",
"checkpoint": "handle_checkpoint"
}
}
@staticmethod
def get_profile_setup_workflow() -> Dict[str, Any]:
"""
Gibt den Workflow für die Profil-Einrichtung zurück.
Returns:
Dict mit Workflow-Schritten
"""
return {
"name": "Facebook Profile Setup",
"steps": [
{
"id": "skip_suggestions",
"name": "Skip Friend Suggestions",
"description": "Überspringe Freundschaftsvorschläge",
"required": False,
"retry": 1
},
{
"id": "skip_photo",
"name": "Skip Profile Photo",
"description": "Überspringe Profilbild-Upload",
"required": False,
"retry": 1
},
{
"id": "skip_interests",
"name": "Skip Interests",
"description": "Überspringe Interessen-Auswahl",
"required": False,
"retry": 1
},
{
"id": "privacy_settings",
"name": "Configure Privacy",
"description": "Konfiguriere Privatsphäre-Einstellungen",
"required": False,
"retry": 1
}
]
}
@staticmethod
def validate_workflow_step(step: Dict[str, Any], result: bool) -> bool:
"""
Validiert einen Workflow-Schritt.
Args:
step: Workflow-Schritt
result: Ergebnis des Schritts
Returns:
bool: True wenn Schritt erfolgreich oder optional
"""
if result:
logger.info(f"Schritt '{step['name']}' erfolgreich")
return True
elif not step.get("required", True):
logger.warning(f"Optionaler Schritt '{step['name']}' fehlgeschlagen, fahre fort")
return True
else:
logger.error(f"Erforderlicher Schritt '{step['name']}' fehlgeschlagen")
return False
@staticmethod
def get_step_timeout(step: Dict[str, Any]) -> int:
"""
Gibt das Timeout für einen Schritt zurück.
Args:
step: Workflow-Schritt
Returns:
int: Timeout in Sekunden
"""
return step.get("timeout", 30)

Datei anzeigen

@ -464,6 +464,41 @@ class XRegistration:
try:
page = self.automation.browser.page
# Zuerst auf "E-Mail verwenden" klicken, um vom Telefon- zum E-Mail-Formular zu wechseln
email_use_selectors = [
'span:has-text("E-Mail verwenden")',
'text="E-Mail verwenden"',
'span.css-1jxf684:has-text("E-Mail verwenden")',
'[class*="r-bcqeeo"]:has-text("E-Mail verwenden")',
'div:has-text("E-Mail verwenden")',
'a:has-text("E-Mail verwenden")',
'button:has-text("E-Mail verwenden")',
'[role="button"]:has-text("E-Mail verwenden")',
# Englische Versionen als Fallback
'span:has-text("Use email")',
'text="Use email"',
'span:has-text("Use email instead")',
'text="Use email instead"'
]
email_link_clicked = False
for selector in email_use_selectors:
try:
element = page.wait_for_selector(selector, timeout=2000, state="visible")
if element:
logger.info(f"'E-Mail verwenden' Link gefunden mit Selektor: {selector}")
element.click()
self.automation.human_behavior.random_delay(0.5, 1)
email_link_clicked = True
logger.info("Zu E-Mail-Registrierung gewechselt")
break
except Exception as e:
logger.debug(f"Selektor {selector} nicht gefunden: {e}")
continue
if not email_link_clicked:
logger.warning("'E-Mail verwenden' Link nicht gefunden, versuche trotzdem fortzufahren")
# Name eingeben
name_selectors = [
'input[name="name"]',

Datei anzeigen

@ -0,0 +1,340 @@
"""
Facebook-spezifischer Generator-Tab mit Geschlechtsauswahl.
"""
import logging
import random
from PyQt5.QtWidgets import (
QWidget, QVBoxLayout, QHBoxLayout, QGridLayout,
QLabel, QLineEdit, QSpinBox, QPushButton,
QGroupBox, QRadioButton, QButtonGroup, QProgressBar
)
from PyQt5.QtCore import pyqtSignal, Qt
logger = logging.getLogger("facebook_generator_tab")
class FacebookGeneratorTab(QWidget):
"""
Facebook-spezifischer Generator-Tab mit Geschlechtsauswahl.
"""
# Signale
start_requested = pyqtSignal(dict)
stop_requested = pyqtSignal()
account_created = pyqtSignal(str, dict) # (platform, account_data)
def __init__(self, platform_name, language_manager=None):
super().__init__()
self.platform_name = platform_name
self.language_manager = language_manager
self.init_ui()
if self.language_manager:
self.language_manager.language_changed.connect(self.update_texts)
self.update_texts()
def init_ui(self):
"""Initialisiert die UI mit Facebook-spezifischen Feldern."""
layout = QVBoxLayout(self)
layout.setContentsMargins(20, 20, 20, 20)
layout.setSpacing(20)
# Formular-Gruppe
self.form_group = QGroupBox("Account-Informationen")
grid_layout = QGridLayout()
grid_layout.setHorizontalSpacing(15)
grid_layout.setVerticalSpacing(10)
self.form_group.setLayout(grid_layout)
# Zeile 0: Vorname und Nachname
self.first_name_label = QLabel("Vorname:")
self.first_name_input = QLineEdit()
self.first_name_input.setPlaceholderText("Max")
self.last_name_label = QLabel("Nachname:")
self.last_name_input = QLineEdit()
self.last_name_input.setPlaceholderText("Mustermann")
grid_layout.addWidget(self.first_name_label, 0, 0)
grid_layout.addWidget(self.first_name_input, 0, 1)
grid_layout.addWidget(self.last_name_label, 0, 2)
grid_layout.addWidget(self.last_name_input, 0, 3)
# Zeile 1: Alter
self.age_label = QLabel("Alter:")
self.age_input = QLineEdit()
self.age_input.setMaximumWidth(100)
grid_layout.addWidget(self.age_label, 1, 0)
grid_layout.addWidget(self.age_input, 1, 1)
# Zeile 2: Geschlecht
self.gender_label = QLabel("Geschlecht:")
# Geschlechts-Widget
gender_widget = QWidget()
gender_layout = QHBoxLayout(gender_widget)
gender_layout.setContentsMargins(0, 0, 0, 0)
# Radio Buttons
self.gender_male = QRadioButton("Männlich")
self.gender_female = QRadioButton("Weiblich")
self.gender_custom = QRadioButton("Divers")
# Standard: Weiblich
self.gender_female.setChecked(True)
# Button Group für exklusive Auswahl
self.gender_group = QButtonGroup()
self.gender_group.addButton(self.gender_male, 1)
self.gender_group.addButton(self.gender_female, 2)
self.gender_group.addButton(self.gender_custom, 3)
# Füge Radio Buttons zum Layout
gender_layout.addWidget(self.gender_male)
gender_layout.addWidget(self.gender_female)
gender_layout.addWidget(self.gender_custom)
gender_layout.addStretch()
grid_layout.addWidget(self.gender_label, 2, 0)
grid_layout.addWidget(gender_widget, 2, 1, 1, 3)
layout.addWidget(self.form_group)
# Fortschrittsanzeige
self.progress_bar = QProgressBar()
self.progress_bar.setRange(0, 100)
self.progress_bar.setValue(0)
self.progress_bar.setMaximumHeight(20)
self.progress_bar.setMinimumWidth(300)
self.progress_bar.hide() # Versteckt bis zur Nutzung
layout.addWidget(self.progress_bar)
# Buttons
button_layout = QHBoxLayout()
button_layout.addStretch()
self.start_button = QPushButton("Account erstellen")
self.start_button.setMinimumWidth(150)
self.start_button.clicked.connect(self.on_start_clicked)
self.stop_button = QPushButton("Abbrechen")
self.stop_button.setMinimumWidth(150)
self.stop_button.clicked.connect(self.on_stop_clicked)
self.stop_button.setEnabled(False)
button_layout.addWidget(self.start_button)
button_layout.addWidget(self.stop_button)
layout.addLayout(button_layout)
# Spacer am Ende
layout.addStretch()
def get_params(self):
"""Sammelt alle Parameter für die Account-Erstellung."""
# Namen sammeln
first_name = self.first_name_input.text().strip()
last_name = self.last_name_input.text().strip()
full_name = f"{first_name} {last_name}"
# Alter verarbeiten
age_text = self.age_input.text().strip()
age = self.parse_age(age_text)
# Geschlecht bestimmen
gender = self.get_selected_gender()
params = {
"first_name": first_name,
"last_name": last_name,
"full_name": full_name,
"age": age,
"age_text": age_text,
"gender": gender,
"registration_method": "email",
"headless": False,
"debug": True,
"email_domain": "z5m7q9dk3ah2v1plx6ju.com"
}
logger.debug(f"Facebook Formulardaten: {params}")
return params
def parse_age(self, age_text):
"""Parst den Alters-Text und gibt ein numerisches Alter zurück."""
if not age_text:
return random.randint(18, 65)
# Versuche Range zu parsen (z.B. "18-25")
if '-' in age_text:
try:
min_age, max_age = age_text.split('-')
min_age = int(min_age.strip())
max_age = int(max_age.strip())
return random.randint(min_age, max_age)
except:
pass
# Versuche als einzelne Zahl
try:
return int(age_text)
except:
return random.randint(18, 65)
def get_selected_gender(self):
"""Gibt das ausgewählte Geschlecht zurück."""
if self.gender_group:
checked_button = self.gender_group.checkedButton()
if checked_button:
gender_id = self.gender_group.id(checked_button)
if gender_id == 1:
return 'male'
elif gender_id == 2:
return 'female'
else:
return 'custom'
# Fallback: zufällige Auswahl
return random.choice(['male', 'female'])
def validate_inputs(self, params):
"""Validiert die Eingaben."""
# Name prüfen
if not params.get('first_name') or not params.get('last_name'):
return False, "Vor- und Nachname sind erforderlich"
# Alter prüfen
age = params.get('age', 0)
if age < 13:
return False, "Mindestalter für Facebook ist 13 Jahre"
if age > 100:
return False, "Bitte geben Sie ein realistisches Alter ein"
return True, None
def on_start_clicked(self):
"""Behandelt den Start-Button-Klick."""
# Parameter sammeln
params = self.get_params()
# Validierung
valid, error_msg = self.validate_inputs(params)
if not valid:
self.show_error(error_msg)
return
# Status aktualisieren
self.set_status("Starte Account-Erstellung...")
# Signal senden
self.start_requested.emit(params)
def on_stop_clicked(self):
"""Behandelt den Stop-Button-Klick."""
self.stop_requested.emit()
def set_running(self, running: bool):
"""Setzt den Status auf 'Wird ausgeführt' oder 'Bereit'."""
self.start_button.setEnabled(not running)
self.stop_button.setEnabled(running)
if running:
self.set_status("Läuft...")
else:
self.progress_bar.setValue(0)
self.progress_bar.hide()
def set_progress(self, value: int):
"""Setzt den Fortschritt der Fortschrittsanzeige."""
if value > 0:
self.progress_bar.show()
self.progress_bar.setValue(value)
if value >= 100:
self.progress_bar.hide()
def show_error(self, message: str):
"""Zeigt eine Fehlermeldung an."""
title = "Fehler"
if self.language_manager:
title = self.language_manager.get_text(
"generator_tab.error_title", "Fehler"
)
from views.widgets.modern_message_box import show_error
show_error(self, title, message)
self.set_status("Fehler aufgetreten")
def show_success(self, message: str):
"""Zeigt eine Erfolgsmeldung an."""
title = "Erfolg"
if self.language_manager:
title = self.language_manager.get_text(
"generator_tab.success_title", "Erfolg"
)
from views.widgets.modern_message_box import show_success
show_success(self, title, message)
self.set_status("Erfolgreich abgeschlossen")
# Kompatibilitätsmethoden für bestehenden Code
def clear_log(self):
"""Kompatibilitätsmethode - tut nichts, da kein Log vorhanden."""
pass
def add_log(self, message: str):
"""Kompatibilitätsmethode - gibt an die Konsole aus."""
logger.info(message)
def store_created_account(self, result_data: dict):
"""Speichert die erstellten Account-Daten."""
if "account_data" in result_data:
self.account_created.emit(self.platform_name, result_data["account_data"])
def set_status(self, message):
"""Setzt den Status-Text."""
# Status-Label wurde entfernt - Log to console for debugging
logger.info(f"Status: {message}")
def update_texts(self):
"""Aktualisiert die Texte nach Sprachwechsel."""
if not self.language_manager:
return
# Labels
self.first_name_label.setText(
self.language_manager.get_text("generator.first_name", "Vorname") + ":"
)
self.last_name_label.setText(
self.language_manager.get_text("generator.last_name", "Nachname") + ":"
)
self.age_label.setText(
self.language_manager.get_text("generator.age", "Alter") + ":"
)
self.gender_label.setText(
self.language_manager.get_text("generator.gender", "Geschlecht") + ":"
)
# Radio Buttons
self.gender_male.setText(
self.language_manager.get_text("generator.gender_male", "Männlich")
)
self.gender_female.setText(
self.language_manager.get_text("generator.gender_female", "Weiblich")
)
self.gender_custom.setText(
self.language_manager.get_text("generator.gender_custom", "Divers")
)
# Buttons
self.start_button.setText(
self.language_manager.get_text("buttons.create", "Account erstellen")
)
self.stop_button.setText(
self.language_manager.get_text("buttons.cancel", "Abbrechen")
)
# GroupBox
self.form_group.setTitle(
self.language_manager.get_text("generator_tab.form_title", "Account-Informationen")
)