fix
This commit is contained in:
@@ -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]}'")
|
||||
|
||||
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)
|
||||
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)
|
||||
# Проверяем изменение содержимого 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
4
ui.py
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user