При разработке интеграций или автоматизации работы с веб-сервисами внутри 1С программисты часто сталкиваются с необходимостью программного взаимодействия с веб-страницами. Одной из самых частых задач является поиск определенной кнопки на странице и имитация ее нажатия пользователем. В этой статье мы подробно разберем, как реализовать логику, аналогичную поиску элементов в C#, используя встроенные механизмы 1С и объектную модель HTML-документа (DOM).
Прежде чем переходить к коду, проанализируем важный технический нюанс: в Обычных формах 1С (платформа 8.2 и 8.3) элемент ПолеHTMLдокумента использует движок Internet Explorer, установленный в системе. Это означает, что при написании кода мы будем обращаться к COM-объектам этого браузера. Это дает нам мощные инструменты для манипуляции страницей, но требует осторожности при проверке типов данных и состояния готовности документа.
Если у кнопки на веб-странице есть уникальный атрибут id, задача решается максимально просто. Мы воспользуемся методом getElementById. Однако важно помнить, что обращаться к документу можно только после того, как он полностью загружен в поле.
Рассмотрим пример кода в обработчике события ДокументСформирован. Это событие гарантирует, что базовая структура страницы уже доступна для анализа:
Процедура ПолеHTMLДокумента1ДокументСформирован(Элемент)
// Получаем объект документа
ДокументHTML = ЭлементыФормы.ПолеHTMLДокумента1.Документ;
// Пытаемся найти элемент по ID
Кнопка = ДокументHTML.getElementById("findlink");
// Важно проверить, что элемент найден, прежде чем вызывать методы
Если Кнопка <> Неопределено Тогда
Кнопка.click();
КонецЕсли;
КонецПроцедуры
Иногда событие ДокументСформирован срабатывает, когда DOM-дерево еще не заполнено данными (например, при сложной структуре скриптов на сайте). Выясним причину, по которой метод click() может выдавать ошибку "Значение не является значением объектного типа". Чаще всего это происходит из-за того, что объект he (element) оказался равен null или undefined в контексте COM.
Разберем улучшенный вариант проверки с анализом содержимого body:
Процедура ПолеHTMLДокумента1ДокументСформирован(Элемент)
ПолеHTML = ЭлементыФормы.ПолеHTMLДокумента1;
// Проверяем, что тело документа не пустое
Если ПолеHTML.Документ.body.innerText <> "" Тогда
ПоискЭлемента = ПолеHTML.Документ.getElementById("button_id");
Попытка
ПоискЭлемента.click();
Исключение
Сообщить("Не удалось нажать кнопку: " + ОписаниеОшибки());
КонецПопытки;
КонецЕсли;
КонецПроцедуры
В исходном вопросе автор использовал сложную логику поиска по CSS-классам и регулярным выражениям. В 1С мы можем реализовать это через перебор коллекций элементов. Если нам нужно найти кнопку, у которой задан определенный класс (например, style-scope tt-icon-button), мы проанализируем все теги button на странице.
Рассмотрим, как это сделать по шагам:
button через getElementsByTagName.className нашему условию.
// Пример поиска кнопки по классу
ВсеКнопки = ЭлементыФормы.ПолеHTMLДокумента1.Документ.getElementsByTagName("button");
Для Каждого ТекущаяКнопка Из ВсеКнопки Цикл
// В COM-объекте IE атрибут class доступен через свойство className
Если Найти(ТекущаяКнопка.className, "tt-icon-button") > 0 Тогда
ТекущаяКнопка.click();
Прервать; // Выходим из цикла после нажатия
КонецЕсли;
КонецЦикла;
Если на компьютере установлена современная версия Internet Explorer (IE8 и выше), мы можем использовать более продвинутый метод querySelector. Это позволяет искать элементы так же, как в jQuery или современных браузерах, что значительно сокращает объем кода 1С.
Посмотрим на пример поиска кнопки со сложным набором классов:
// Используем CSS-селектор для поиска кнопки с классом tt-icon-button
Кнопка = ЭлементыФормы.ПолеHTMLДокумента1.Документ.querySelector("button.style-scope.tt-icon-button");
Если Кнопка <> Неопределено Тогда
Кнопка.click();
КонецЕсли;
Бывают ситуации, когда прямой вызов метода click() не приводит к результату (например, если на кнопку навешаны сложные обработчики событий). В таких случаях проанализируем возможность принудительного вызова события (FireEvent) или выполнение кода через JavaScript.
Способ 1: FireEvent
Для старых версий движка IE используется метод инициации события:
Кнопка.fireEvent("onclick");
Способ 2: Исполнение JavaScript (eval)
Это самый надежный способ, так как код выполняется непосредственно в контексте браузера, минуя возможные проблемы с маршалингом объектов между 1С и COM. Мы можем отправить команду на нажатие прямо в окно документа:
// Выполнение произвольного JS-кода
ТекстСкрипта = "document.getElementById('button').click();";
ЭлементыФормы.ПолеHTMLДокумента1.Документ.parentWindow.eval(ТекстСкрипта);
Современные веб-приложения часто подгружают контент (включая кнопки) асинхронно после загрузки основной страницы. В 1С событие ДокументСформирован может произойти раньше, чем скрипты сайта отрисуют нужную нам кнопку. Выясним, как решить эту проблему с помощью обработчика ожидания.
Алгоритм действий:
ПодключитьОбработчикОжидания.
Процедура ПолеHTMLДокумента1ДокументСформирован(Элемент)
// Запускаем проверку каждые 1 секунду
ПодключитьОбработчикОжидания("НайтиИНажатьКнопку", 1);
КонецПроцедуры
Процедура НайтиИНажатьКнопку() Экспорт
Документ = ЭлементыФормы.ПолеHTMLДокумента1.Документ;
Кнопка = Документ.getElementById("dynamic_button");
Если Кнопка <> Неопределено Тогда
// Кнопка появилась! Нажимаем и отключаем таймер
Кнопка.click();
ОтключитьОбработчикОжидания("НайтиИНажатьКнопку");
КонецЕсли;
КонецПроцедуры
Как упоминалось в обсуждении, если логика поиска на C# уже написана и она слишком сложна для воспроизведения на встроенном языке 1С, можно использовать механизмы .NET Bridge. Это позволяет скомпилировать ваш C# код в DLL, сделать его ComVisible и вызывать напрямую из 1С, передавая внутрь объект Документ. В этом случае ваш метод на C# будет принимать object, приводить его к IHTMLDocument2 и выполнять все необходимые проверки IsVoid и регулярные выражения внутри привычной среды .NET.
Подводя итог, отметим, что для успешного нажатия кнопки в 1С необходимо убедиться в трех вещах: документ полностью загружен, элемент успешно найден в дереве DOM (проверка на Неопределено), и выбран правильный метод инициации события (click, fireEvent или eval).