This commit is contained in:
unknown
2026-02-12 00:19:38 +05:00
parent be7aadf218
commit c348a19052
5 changed files with 391 additions and 70 deletions

View File

@@ -443,3 +443,193 @@ class BrowserService:
except Exception as e:
logging.error(f"❌ Ошибка при выборе вкладки по индексу {tab_index}: {e}")
return False
def select_tab_by_multiple_methods(self, tab_text, timeout=15):
"""Пытается выбрать вкладку на странице перебором всех элементов.
Args:
tab_text (str): Текст вкладки для поиска
timeout (int): Общее время ожидания в секундах
Returns:
bool: True, если вкладка найдена и выбрана, иначе False
"""
end_time = time.time() + timeout
attempt = 0
# Нормализуем текст для поиска
tab_text_normalized = tab_text.strip()
tab_text_lower = tab_text_normalized.lower()
logging.info(f"🔍 Начинаю поиск вкладки: '{tab_text}'")
while time.time() < end_time:
attempt += 1
logging.info(f" Попытка {attempt}: перебираю все элементы на странице...")
try:
# Ищем и кликаем через JavaScript в одном скрипте
script = """
var searchText = arguments[0].toLowerCase();
var allElements = document.querySelectorAll('*');
var foundElements = [];
console.log('Ищу элемент с текстом:', searchText);
for (var i = 0; i < allElements.length; i++) {
var el = allElements[i];
var elementText = el.textContent || el.innerText || '';
var visibleText = elementText.trim();
// Проверяем только прямой текст элемента (не включая детей)
var directText = '';
for (var j = 0; j < el.childNodes.length; j++) {
if (el.childNodes[j].nodeType === 3) { // TEXT_NODE
directText += el.childNodes[j].nodeValue;
}
}
directText = directText.trim();
// Совпадение по прямому тексту или полному тексту
var match = false;
if (directText.toLowerCase() === searchText ||
visibleText.toLowerCase() === searchText) {
match = true;
} else if (directText.toLowerCase().includes(searchText) ||
visibleText.toLowerCase().includes(searchText)) {
match = true;
}
if (match) {
// Проверяем видимость элемента
var rect = el.getBoundingClientRect();
var style = window.getComputedStyle(el);
if (rect.width > 0 && rect.height > 0 &&
style.display !== 'none' &&
style.visibility !== 'hidden' &&
style.opacity !== '0') {
foundElements.push({
element: el,
tag: el.tagName.toLowerCase(),
text: visibleText.substring(0, 50),
directText: directText.substring(0, 50)
});
}
}
}
console.log('Найдено элементов:', foundElements.length);
// Пытаемся кликнуть на каждый найденный элемент
for (var k = 0; k < foundElements.length; k++) {
var item = foundElements[k];
var elem = item.element;
try {
// Прокручиваем к элементу (без анимации для скорости)
elem.scrollIntoView({block: 'center', behavior: 'auto'});
// Небольшая пауза для стабильности (выполняется синхронно)
var startWait = Date.now();
while (Date.now() - startWait < 200) {
// Ждем 200мс
}
console.log('Пробую кликнуть элемент:', item.tag, item.text);
// Сначала находим САМЫЙ кликабельный элемент в иерархии
var targetToClick = elem;
// Ищем родителя который является ссылкой или кнопкой
var clickableParent = elem.closest('a, button, [role="tab"], [role="button"], li');
if (clickableParent) {
console.log('Найден кликабельный родитель:', clickableParent.tagName, clickableParent.className);
targetToClick = clickableParent;
}
// Теперь пробуем все методы клика на найденном элементе
var methods = [
{
name: 'direct click',
fn: function(el) { el.click(); }
},
{
name: 'mousedown+mouseup',
fn: function(el) {
el.dispatchEvent(new MouseEvent('mousedown', {bubbles: true, cancelable: true}));
el.dispatchEvent(new MouseEvent('mouseup', {bubbles: true, cancelable: true}));
el.dispatchEvent(new MouseEvent('click', {bubbles: true, cancelable: true}));
}
},
{
name: 'dispatchEvent click',
fn: function(el) {
el.dispatchEvent(new MouseEvent('click', {
view: window,
bubbles: true,
cancelable: true,
clientX: el.getBoundingClientRect().left + 5,
clientY: el.getBoundingClientRect().top + 5
}));
}
},
{
name: 'focus + click',
fn: function(el) {
if (el.focus) el.focus();
el.click();
}
}
];
// Пробуем каждый метод
for (var m = 0; m < methods.length; m++) {
try {
console.log('Пробую метод:', methods[m].name, 'на', targetToClick.tagName);
methods[m].fn(targetToClick);
console.log('✅ Успешно кликнул методом:', methods[m].name);
return {success: true, tag: targetToClick.tagName, text: item.text, method: methods[m].name};
} catch(err) {
console.log('✗ Метод', methods[m].name, 'не сработал:', err.message);
}
}
} catch(err) {
console.log('Общая ошибка при обработке элемента:', err.message);
}
}
return {success: false, found: foundElements.length, message: 'Элементы найдены, но ни один метод клика не сработал'};
"""
result = self.driver.execute_script(script, tab_text_lower)
if result and isinstance(result, dict):
if result.get('success'):
method = result.get('method', 'unknown')
tag = result.get('tag', 'unknown')
text = result.get('text', '')
logging.info(f" ✅ УСПЕХ! Метод: {method}, тег: <{tag}>, текст: '{text}'")
time.sleep(0.5)
return True
else:
found_count = result.get('found', 0)
message = result.get('message', 'Не найдено')
if found_count > 0:
logging.warning(f" ✗ Попытка {attempt}: найдено {found_count} элементов, но кликнуть не удалось")
else:
logging.warning(f" ✗ Попытка {attempt}: {message}")
else:
logging.warning(f" ✗ Попытка {attempt}: некорректный результат от JavaScript")
time.sleep(1)
except Exception as e:
logging.warning(f" ✗ Ошибка при попытке {attempt}: {e}")
import traceback
logging.debug(traceback.format_exc())
time.sleep(1)
logging.error(f"Не удалось найти и кликнуть на вкладку '{tab_text}' за {timeout} секунд после {attempt} попыток")
return False

View File

@@ -35,13 +35,14 @@ class FileProcessorService:
logging.info("🚀 ИНИЦИАЛИЗАЦИЯ ПРОЦЕССОРА ФАЙЛОВ")
logging.info("=" * 70)
def start_processing(self, upload_button_texts=None, process_button_texts=None):
def start_processing(self, upload_button_texts=None, process_button_texts=None, selected_tab=None):
"""
Запускает процесс поиска и загрузки файлов.
Args:
upload_button_texts (list): Варианты текста кнопки загрузки файла
process_button_texts (list): Варианты текста кнопки обработки
selected_tab (str): Название вкладки на странице для выбора
Returns:
dict: Результаты обработки
@@ -92,12 +93,20 @@ class FileProcessorService:
logging.info("=" * 70)
try:
# Открываем новую вкладку для каждого файла (кроме первого)
if idx > 1:
logging.info(f" Открываю новую вкладку для файла...")
if not self.browser.open_new_tab(self.url):
logging.warning(f"⚠️ Не удалось открыть новую вкладку")
self.browser.wait_page_load(3)
# Открываем новую вкладку для КАЖДОГО файла (включая первый)
logging.info(f" Открываю новую вкладку в браузере для файла...")
if not self.browser.open_new_tab(self.url):
logging.warning(f"⚠️ Не удалось открыть новую вкладку")
self.browser.wait_page_load(3)
# Выбор вкладки на странице (если указана)
if selected_tab:
logging.info(f"🔍 Выбираю вкладку на странице: '{selected_tab}'")
if self.browser.select_tab_by_multiple_methods(selected_tab, timeout=15):
logging.info(f"✅ Вкладка '{selected_tab}' успешно выбрана")
self.browser.wait_page_load(2)
else:
logging.warning(f"⚠️ Не удалось выбрать вкладку '{selected_tab}'")
# Поиск и клик по кнопке загрузки
upload_button_found = False