This commit is contained in:
2026-02-16 10:36:43 +05:00
parent a255e9296f
commit 862113bb65
2 changed files with 112 additions and 82 deletions

View File

@@ -1,3 +1,25 @@
class BrowserService:
"""Сервис для автоматизации работы с браузером."""
# ...existing code...
def click_tab_and_wait(self, url, tab_text, wait_before_click=5, wait_after_click=5):
"""Открывает страницу, ждёт, нажимает вкладку по тексту, ждёт загрузку."""
try:
logging.info(f"🌐 Открываю страницу: {url}")
self.driver.get(url)
logging.info(f"⏳ Жду {wait_before_click} сек перед кликом...")
time.sleep(wait_before_click)
logging.info(f"🔍 Нажимаю вкладку: '{tab_text}'")
result = self.select_tab_by_multiple_methods(tab_text, timeout=10)
if result:
logging.info(f"✅ Вкладка '{tab_text}' нажата, жду {wait_after_click} сек...")
time.sleep(wait_after_click)
else:
logging.warning(f"Не удалось нажать вкладку '{tab_text}'")
return result
except Exception as e:
logging.error(f"❌ Ошибка click_tab_and_wait: {e}")
return False
"""
Модуль для автоматизации работы с браузером через Selenium
"""
@@ -260,20 +282,18 @@ class BrowserService:
return False
def upload_file(self, file_path, selector='input[type="file"]', by=By.CSS_SELECTOR):
"""Загружает файл через input."""
"""Загружает файл через input[type='file'] с максимальной надёжностью."""
try:
logging.info(f"📤 Загружаю файл: {Path(file_path).name}")
# Попытка кликнуть на область загрузки
try:
drop_area = self.driver.find_element(By.CSS_SELECTOR, '.upload-area, .drop-zone, [data-upload]')
drop_area.click()
time.sleep(1)
logging.info(" Найдена область загрузки")
except:
pass
file_input = self.wait.until(EC.presence_of_element_located((by, selector)))
# Если input скрыт, делаем его видимым через JS
is_displayed = file_input.is_displayed()
if not is_displayed:
try:
self.driver.execute_script("arguments[0].style.display = 'block'; arguments[0].style.visibility = 'visible'; arguments[0].style.opacity = 1; arguments[0].style.height = 'auto'; arguments[0].style.width = 'auto';", file_input)
logging.info(" Сделал input[type='file'] видимым через JS")
except Exception as e:
logging.warning(f" Не удалось сделать input[type='file'] видимым: {e}")
file_input.send_keys(file_path)
logging.info(f"✅ Файл загружен: {Path(file_path).name}")
time.sleep(1)
@@ -395,110 +415,120 @@ class BrowserService:
return False
def select_tab_by_multiple_methods(self, tab_text, timeout=15):
"""Пытается выбрать вкладку на странице перебором всех элементов.
"""Пытается выбрать вкладку или кнопку на странице перебором всех элементов.
Args:
tab_text (str): Текст вкладки для поиска
tab_text (str): Текст вкладки или кнопки для поиска
timeout (int): Общее время ожидания в секундах
Returns:
bool: True, если вкладка найдена и выбрана, иначе False
bool: True, если элемент найден и выбран, иначе False
"""
from selenium.webdriver.common.action_chains import ActionChains
end_time = time.time() + timeout
attempt = 0
tab_text_normalized = tab_text.strip().lower()
logging.info(f"🔍 Начинаю поиск вкладки/кнопки: '{tab_text}' (v3)")
# Нормализуем текст для поиска
tab_text_normalized = tab_text.strip()
logging.info(f"🔍 Начинаю поиск вкладки: '{tab_text}' (v2)")
tag_selector = 'a, div, span, li, button, td, th, input, label, strong, b, em, i, p, section, header, footer, article, aside, nav, form'
while time.time() < end_time:
attempt += 1
logging.info(f" Попытка {attempt}: поиск элементов через JS...")
try:
# Ищем и кликаем через JavaScript в одном скрипте
script = """
var searchText = arguments[0].toLowerCase();
var allElements = document.querySelectorAll('a, div, span, li, button, td, th');
script = f"""
var searchText = arguments[0];
var allElements = document.querySelectorAll('{tag_selector}');
var foundElements = [];
for (var i = 0; i < allElements.length; i++) {
for (var i = 0; i < allElements.length; i++) {{
var el = allElements[i];
if (el.offsetParent === null) continue; // Skip hidden
var elementText = el.innerText || el.textContent || '';
var cleanText = elementText.trim().toLowerCase();
// Strict match or contains if short
if (cleanText === searchText || (cleanText.includes(searchText) && cleanText.length < searchText.length + 50)) {
if (el.offsetParent === null) continue;
var elementText = (el.innerText || el.textContent || '').trim().toLowerCase();
var aria = (el.getAttribute('aria-label') || '').trim().toLowerCase();
var title = (el.getAttribute('title') || '').trim().toLowerCase();
if (
elementText == searchText ||
elementText.includes(searchText) ||
aria == searchText ||
aria.includes(searchText) ||
title == searchText ||
title.includes(searchText)
) {{
foundElements.push(el);
}
}
}}
var children = el.querySelectorAll('span, b, strong, em, i');
for (var j = 0; j < children.length; j++) {{
var childText = (children[j].innerText || children[j].textContent || '').trim().toLowerCase();
if (childText == searchText || childText.includes(searchText)) {{
foundElements.push(el);
break;
}}
}}
}}
return foundElements;
"""
candidates = self.driver.execute_script(script, tab_text_normalized)
if not candidates:
logging.info(" ⚠️ JS поиск ничего не дал, пробую XPath...")
try:
xpath = f"//*[contains(text(), '{tab_text}')]"
xpath = (
f"//*[contains(translate(text(), 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'), '{tab_text_normalized}') "
f"or contains(translate(@aria-label, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'), '{tab_text_normalized}') "
f"or contains(translate(@title, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'), '{tab_text_normalized}')]"
)
candidates = self.driver.find_elements(By.XPATH, xpath)
except:
pass
except Exception as e_xpath:
logging.warning(f" XPath fail: {e_xpath}")
logging.info(f" Найдено кандидатов: {len(candidates)}")
for i, element in enumerate(candidates):
try:
if not element.is_displayed():
continue
# Подсветка
self.driver.execute_script("arguments[0].style.border='3px solid red';", element)
time.sleep(0.5)
logging.info(f" 👉 Кандидат #{i+1} (<{element.tag_name}>): '{element.text[:40]}'")
# 1. ActionChains
try:
ActionChains(self.driver).move_to_element(element).click().perform()
logging.info(" ✅ ActionChains click OK")
self.driver.execute_script("arguments[0].style.border='';", element)
return True
except Exception as e1:
logging.warning(f" ActionChains fail: {e1}")
# 2. Native Click
try:
element.click()
logging.info(" ✅ Element click OK")
self.driver.execute_script("arguments[0].style.border='';", element)
return True
except Exception as e2:
logging.warning(f" Native click fail: {e2}")
# 3. JS Click
self.driver.execute_script("arguments[0].click();", element)
logging.info(" ✅ JS click OK")
self.driver.execute_script("arguments[0].style.border='';", element)
return True
if not element.is_displayed():
continue
self.driver.execute_script("arguments[0].style.border='3px solid red';", element)
time.sleep(0.5)
try:
logging.info(f" 👉 Кандидат #{i+1} (<{element.tag_name}>): text='{element.text[:40]}', aria-label='{element.get_attribute('aria-label')}', title='{element.get_attribute('title')}'")
except Exception as elog:
logging.info(f" 👉 Кандидат #{i+1} (<unknown>): {elog}")
# Сохраняем текущее содержимое body
old_body = self.driver.execute_script("return document.body.innerHTML;")
# 1. ActionChains
try:
ActionChains(self.driver).move_to_element(element).click().perform()
logging.info(" ✅ ActionChains click OK")
self.driver.execute_script("arguments[0].style.border='';", element)
except Exception as e1:
logging.warning(f" ActionChains fail: {e1}")
# 2. Native Click
try:
element.click()
logging.info(" ✅ Element click OK")
self.driver.execute_script("arguments[0].style.border='';", element)
except Exception as e2:
logging.warning(f" Native click fail: {e2}")
# 3. JS Click
self.driver.execute_script("arguments[0].click();", element)
logging.info(" ✅ JS click OK")
self.driver.execute_script("arguments[0].style.border='';", element)
# Проверяем изменение содержимого body
try:
WebDriverWait(self.driver, 5).until(lambda d: d.execute_script("return document.body.innerHTML;") != old_body)
logging.info(" ✅ Содержимое страницы изменилось после клика")
return True
except Exception:
logging.warning(" ⚠️ Содержимое страницы не изменилось после клика")
continue
except Exception as e:
logging.error(f" Ошибка обработки элемента: {e}")
try:
self.driver.execute_script("arguments[0].style.border='';", element)
except:
pass
time.sleep(1)
except Exception as e:
logging.warning(f" ✗ Ошибка при попытке {attempt}: {e}")
time.sleep(1)
logging.error(f"Не удалось найти и кликнуть на вкладку '{tab_text}' за {timeout} секунд")
logging.error(f"Не удалось найти и кликнуть на элемент '{tab_text}' за {timeout} секунд")
return False

4
ui.py
View File

@@ -123,7 +123,7 @@ class UIManager:
self.upload_buttons_entry = tk.Entry(main_frame, font=self.font_label)
self.upload_buttons_entry.pack(anchor="w", fill=tk.X, pady=(0, 5))
self.upload_buttons_entry.insert(0, "Загрузить файл, Выбрать файл, Добавить файл")
self.upload_buttons_entry.insert(0, "Выберите файл, Выбрать файл, Добавить файл")
upload_label = tk.Label(
main_frame,
@@ -136,7 +136,7 @@ class UIManager:
self.process_buttons_entry = tk.Entry(main_frame, font=self.font_label)
self.process_buttons_entry.pack(anchor="w", fill=tk.X, pady=(0, 5))
self.process_buttons_entry.insert(0, "Загрузить, Обработать, Преобразовать, Изменить, Конвертировать")
self.process_buttons_entry.insert(0, "Исправить, Обработать, Преобразовать, Изменить, Конвертировать")
process_label = tk.Label(
main_frame,