From a255e9296f8d963d8c37f092a25b90e1e5395c52 Mon Sep 17 00:00:00 2001 From: jze9 Date: Thu, 12 Feb 2026 01:41:09 +0500 Subject: [PATCH] ff1 --- services/browser_service.py | 399 ++++++++++++------------------------ services/processor.py | 9 + 2 files changed, 143 insertions(+), 265 deletions(-) diff --git a/services/browser_service.py b/services/browser_service.py index 423b61f..7bcaf45 100644 --- a/services/browser_service.py +++ b/services/browser_service.py @@ -4,6 +4,7 @@ import time import logging import os +import shutil import sys import platform import subprocess @@ -37,7 +38,16 @@ class BrowserService: def _find_firefox_path(): """Автоматически находит путь к Firefox для текущей ОС.""" system = platform.system() - found_path = None + + # 1. Проверка через shutil.which (Поиск в PATH) - работает и на Win и на Linux + path_from_which = shutil.which("firefox") + if path_from_which: + # На Windows shutil.which может вернуть .EXE, проверим существует ли + if os.path.exists(path_from_which): + logging.info(f"✅ Firefox найден в PATH: {path_from_which}") + return path_from_which + + possible_paths = [] if system == "Windows": # Windows пути - разные места установки Firefox @@ -47,6 +57,7 @@ class BrowserService: os.path.expandvars(r"%PROGRAMFILES%\Mozilla Firefox\firefox.exe"), os.path.expandvars(r"%PROGRAMFILES(X86)%\Mozilla Firefox\firefox.exe"), os.path.expandvars(r"%LOCALAPPDATA%\Mozilla Firefox\firefox.exe"), + os.path.expandvars(r"%APPDATA%\Mozilla Firefox\firefox.exe"), ] # Пытаемся найти через реестр (Windows) @@ -72,10 +83,12 @@ class BrowserService: else: # Linux # Linux пути possible_paths = [ - "/snap/bin/firefox", "/usr/bin/firefox", + "/usr/bin/firefox-esr", + "/snap/bin/firefox", "/usr/local/bin/firefox", "/opt/firefox/firefox", + "/usr/lib/firefox/firefox", ] # Ищем Firefox в возможных местах @@ -84,17 +97,16 @@ class BrowserService: logging.info(f"✅ Firefox найден: {path}") return path - # Пытаемся найти через which/where команды + # Последний шанс: subprocess (если shutil.which пропустил что-то специфичное) try: - if system == "Windows": - result = subprocess.run(["where", "firefox.exe"], capture_output=True, text=True, timeout=5) - else: - result = subprocess.run(["which", "firefox"], capture_output=True, text=True, timeout=5) + cmd = ["where", "firefox.exe"] if system == "Windows" else ["which", "firefox"] + result = subprocess.run(cmd, capture_output=True, text=True, timeout=5) if result.returncode == 0 and result.stdout.strip(): firefox_path = result.stdout.strip().split('\n')[0] - logging.info(f"✅ Firefox найден через {system} search: {firefox_path}") - return firefox_path + if os.path.exists(firefox_path): + logging.info(f"✅ Firefox найден через команду search: {firefox_path}") + return firefox_path except: pass @@ -112,10 +124,6 @@ class BrowserService: firefox_options.set_preference("browser.download.useDownloadDir", True) firefox_options.set_preference("browser.helperApps.neverAsk.saveToDisk", "application/octet-stream") - # ===== ОТКЛЮЧАЕМ HEADLESS (окно ДОЛЖНО быть видимым) ===== - # Убедимся, что headless режим НЕ установлен - # (это заставит браузер открыться в нормальном режиме) - # Устанавливаем путь к Firefox только если он найден if self.firefox_binary_path: logging.info(f" ✅ Используется Firefox: {self.firefox_binary_path}") @@ -126,20 +134,45 @@ class BrowserService: logging.info("🚀 Запуск Firefox драйвера с ВИДИМЫМ окном...") # Попытка 1: Использовать webdriver-manager (самый надежный способ) - if HAS_WEBDRIVER_MANAGER: + if HAS_WEBDRIVER_MANAGER and not self.driver: try: logging.info(" Попытка 1: webdriver-manager...") service = FirefoxService(GeckoDriverManager().install()) self.driver = webdriver.Firefox(service=service, options=firefox_options) + logging.info(" ✅ Успешно запущено через webdriver-manager") except Exception as e: logging.warning(f" webdriver-manager не сработал: {e}") self.driver = None - # Попытка 2: Прямой запуск (Selenium сам найдет geckodriver в PATH) + # Попытка 2: Локальный драйвер в папке проекта + if not self.driver: + logging.info(" Попытка 2: Поиск локального geckodriver...") + system = platform.system() + driver_filename = "geckodriver.exe" if system == "Windows" else "geckodriver" + + possible_driver_paths = [ + os.path.join(os.getcwd(), driver_filename), + os.path.join(os.getcwd(), "drivers", driver_filename), + os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", driver_filename), # В корне проекта + ] + + for dp in possible_driver_paths: + if os.path.exists(dp): + try: + logging.info(f" ⚠️ Нашел локальный драйвер: {dp}") + service = FirefoxService(executable_path=dp) + self.driver = webdriver.Firefox(service=service, options=firefox_options) + logging.info(" ✅ Успешно запущено через локальный драйвер") + break + except Exception as e: + logging.warning(f" Ошибка локального драйвера {dp}: {e}") + + # Попытка 3: Прямой запуск (Selenium сам найдет geckodriver в PATH) if not self.driver: try: - logging.info(" Попытка 2: Прямой запуск (Selenium ищет geckodriver в PATH)...") + logging.info(" Попытка 3: Прямой запуск (Selenium ищет geckodriver в PATH)...") self.driver = webdriver.Firefox(options=firefox_options) + logging.info(" ✅ Успешно запущено через системный PATH") except Exception as e: logging.warning(f" Прямой запуск не сработал: {e}") self.driver = None @@ -154,6 +187,18 @@ class BrowserService: self.wait = WebDriverWait(self.driver, 10) logging.info("✅ Браузер открыт и готов к работе.") + except Exception as e: + logging.error(f"❌ Ошибка при настройке драйвера: {e}") + logging.error(f"\n Решения:") + logging.error(f" 1. Убедитесь, что Firefox установлен") + logging.error(f" 2. Скачайте geckodriver для вашей ОС и положите рядом с программой") + logging.error(f" 3. Ссылка на драйвер: https://github.com/mozilla/geckodriver/releases") + time.sleep(2) + + self.driver.set_page_load_timeout(300) + self.wait = WebDriverWait(self.driver, 10) + logging.info("✅ Браузер открыт и готов к работе.") + except Exception as e: logging.error(f"❌ Ошибка при настройке драйвера: {e}") logging.error(f"\n Решения:") @@ -180,119 +225,24 @@ class BrowserService: def click_button_by_text(self, button_text, exact_match=False, timeout=10): """ - Ищет и нажимает кнопку по тексту в различных формах. + Ищет и нажимает кнопку (или любой элемент) по тексту, используя продвинутый метод поиска. Args: button_text (str): Текст кнопки для поиска - exact_match (bool): Точное совпадение или частичное + exact_match (bool): Игнорируется в новой реализации (используется умный поиск) timeout (int): Время ожидания в секундах Returns: bool: True если кнопка найдена и нажата, False иначе """ - try: - logging.info(f"🔎 Ищу кнопку: '{button_text}'") - button = self._find_button_by_text(button_text, exact_match, timeout) - - if button: - logging.info(f"✅ Кнопка найдена, нажимаю...") - # Скролл к кнопке если нужно - self.driver.execute_script("arguments[0].scrollIntoView(true);", button) - time.sleep(0.5) - button.click() - logging.info(f"✅ Кнопка '{button_text}' нажата успешно.") - time.sleep(1) - return True - else: - logging.warning(f"⚠️ Кнопка '{button_text}' не найдена.") - return False - except Exception as e: - logging.error(f"❌ Ошибка при нажатии кнопки '{button_text}': {e}") - return False + logging.info(f"🔎 Ищу кнопку/элемент с текстом: '{button_text}' (Robust)") + return self.select_tab_by_multiple_methods(button_text, timeout) def _find_button_by_text(self, button_text, exact_match=False, timeout=10): - """ - Находит кнопку по тексту различными способами. - - Args: - button_text (str): Текст для поиска - exact_match (bool): Точное совпадение - timeout (int): Время ожидания - - Returns: - WebElement или None - """ - button_text_lower = button_text.lower().strip() - end_time = time.time() + timeout - - while time.time() < end_time: - # Вариант 1: Поиск по тегу