При интеграции 1С с внешними сайтами и веб-сервисами часто возникает необходимость использовать встроенный браузер — элемент управления Поле HTML документа. С его помощью можно не просто отображать веб-страницы, но и активно взаимодействовать с их содержимым (DOM-моделью). Типичные задачи разработчика в данном контексте — программно заполнить форму авторизации (ввести логин и пароль), нажать кнопку входа без участия пользователя, а также отследить, на какой именно элемент страницы кликнул пользователь.
В этой статье мы подробно разберем, как управлять элементами веб-страницы из кода 1С, как правильно обрабатывать интерактивные действия пользователя и какие важные архитектурные изменения платформы необходимо учитывать при написании такого кода.
Рассмотрим ситуацию, когда перед нами стоит задача автоматически авторизоваться на сайте. На форме сайта присутствует форма с идентификатором login-form, текстовые поля для ввода логина и пароля, а также кнопка отправки данных.
Для реализации этой задачи мы можем напрямую обратиться к объектной модели документа (DOM) через свойство поля HTML-документа. Проанализируем правильный и безопасный подход к получению элементов страницы по их идентификаторам и атрибутам.
Ниже представлен готовый код на стороне 1С, который находит нужные поля, заполняет их данными и имитирует нажатие на кнопку отправки:
// Получаем объект HTML-документа из элемента формы 1С
Документ = Элементы.ПолеHTMLДокумента.Документ;
Если Документ <> Неопределено Тогда
// Находим поля ввода по их уникальным ID на веб-странице
ПолеЛогин = Документ.getElementById("loginform-login");
ПолеПароль = Документ.getElementById("loginform-password");
Если ПолеЛогин <> Неопределено И ПолеПароль <> Неопределено Тогда
// Заполняем реквизиты авторизации
ПолеЛогин.value = "User_Login_123";
ПолеПароль.value = "Secure_Password_987";
// Находим кнопку отправки формы. Использование фиксированных индексов (например, Форма[5]) крайне нежелательно,
// так как любое изменение верстки сайта нарушит работу алгоритма.
// Ищем кнопку по имени (атрибуту "name") или классу.
КоллекцияКнопок = Документ.getElementsByName("login-button");
Если КоллекцияКнопок.length > 0 Тогда
КнопкаВойти = КоллекцияКнопок[0];
// Вызываем событие клика
КнопкаВойти.click();
Иначе
// Альтернативный поиск по классу, если имя не задано
КоллекцияКнопокПоКлассу = Документ.getElementsByClassName("btn-primary");
Если КоллекцияКнопокПоКлассу.length > 0 Тогда
КнопкаВойти = КоллекцияКнопокПоКлассу[0];
КнопкаВойти.click();
КонецЕсли;
КонецЕсли;
КонецЕсли;
КонецЕсли;
Обратите внимание на важную деталь, которую часто путают разработчики: метод поиска элементов по классу называется во множественном числе — getElementsByClassName (возвращает коллекцию), в то время как поиск по идентификатору выполняется в единственном числе — getElementById (возвращает один уникальный элемент).
Вторая частая задача — перехватить действия пользователя. Например, когда человек кликает по элементам на отображаемой веб-странице, нам нужно понять, по какому именно объекту (ссылке, картинке, строке таблицы) был произведен клик, чтобы выполнить соответствующее действие в самой 1С.
Для этого используется стандартное событие элемента формы 1С ПриНажатии (в некоторых версиях платформы или типах форм оно может называться onclick или регистрироваться через подписку на события DOM).
Выясним, как извлечь информацию о нажатом элементе. При генерации события платформа передает в обработчик параметр ДанныеСобытия. Именно в его свойстве Element содержится ссылка на целевой объект DOM-дерева.
Рассмотрим пример обработки этого события:
Процедура ПолеHTMLДокументаПриНажатии(Элемент, ДанныеСобытия, СтандартнаяОбработка)
// Получаем DOM-элемент, по которому пришелся клик
НажатыйЭлемент = ДанныеСобытия.Element;
Если НажатыйЭлемент <> Неопределено Тогда
// Определяем имя тега (всегда возвращается в верхнем регистре, например "A", "DIV", "INPUT", "SPAN")
ИмяТега = ВРег(НажатыйЭлемент.tagName);
Идентификатор = НажатыйЭлемент.id;
КлассЭлемента = НажатыйЭлемент.className;
// Пример 1: Обработка клика по конкретной кнопке с известным ID
Если ИмяТега = "BUTTON" И Идентификатор = "custom-action-button" Тогда
СтандартнаяОбработка = Ложь; // Отменяем переход по ссылке или стандартное действие браузера
ВыполнитьДействиеВ1С();
Возврат;
КонецЕсли;
// Пример 2: Клик по ссылке
Если ИмяТега = "A" Тогда
АдресПерехода = НажатыйЭлемент.href;
Сообщить("Пользователь переходит по ссылке: " + АдресПерехода);
КонецЕсли;
// Пример 3: Обработка клика по вложенному элементу (например, по иконке внутри ссылки)
// Если пользователь кликнул по картинке внутри ссылки, ДанныеСобытия.Element вернет тег "IMG".
// Чтобы получить саму ссылку, нам нужно подняться к родительскому элементу.
Родитель = НажатыйЭлемент.parentElement;
Пока Родитель <> Неопределено Цикл
Если ВРег(Родитель.tagName) = "A" Тогда
Сообщить("Кликнули по ссылке через вложенный элемент. URL: " + Родитель.href);
Прервать;
КонецЕсли;
Родитель = Родитель.parentElement;
КонецЦикла;
КонецЕсли;
КонецПроцедуры
Начиная с версии платформы 1С:Предприятие 8.3.14, фирма «1С» осуществила поэтапный отказ от использования устаревшего системного движка Internet Explorer (MSHTML) для отображения HTML-документов под управлением ОС Windows. Новым стандартным движком стал современный Chromium (WebKit).
Это нововведение значительно повысило скорость работы и совместимость с современными сайтами, однако повлекло за собой критические изменения в объектной модели 1С, о которых важно знать разработчику для предотвращения ошибок:
Документ.parentWindow. В новом движке Chromium свойство parentWindow не поддерживается. Вместо него необходимо использовать стандартное свойство defaultView.Документ возвращало COM-объект типа HTMLDocument, методы которого напрямую транслировались из библиотеки MSHTML. Теперь возвращается специальный платформенный тип ВнешнийОбъект. Некоторые специфичные методы IE могут не поддерживаться, поэтому рекомендуется писать максимально кроссбраузерный код на чистом JavaScript.Посмотрим на пример написания универсального кода, который будет корректно работать как на старых версиях платформы (с IE), так и на новых (с Chromium):
Документ = Элементы.ПолеHTMLДокумента.Документ;
ОкноБраузера = Неопределено;
Попытка
// Попытка для нового движка Chromium (WebKit)
ОкноБраузера = Документ.defaultView;
Исключение
Попытка
// Резервный вариант для старого движка Internet Explorer
ОкноБраузера = Документ.parentWindow;
Исключение
ЗаписьЖурналаРегистрации("ИнтеграцияHTML", УровеньЖурналаРегистрации.Предупреждение, , ,
"Не удалось получить глобальный контекст окна браузера.");
КонецПопытки;
КонецПопытки;
Если ОкноБраузера <> Неопределено Тогда
// Теперь мы можем безопасно вызывать JS функции, объявленные на странице
// Например, вызовем функцию очистки кэша или кастомной валидации формы:
ОкноБраузера.clearLogin();
КонецЕсли;
Иногда простой обработки события ПриНажатии недостаточно. Например, когда в процессе выполнения JavaScript-сценария на странице сформировался сложный объект с данными (массив товаров, JSON с результатами расчетов), который нужно передать в код 1С.
Для этого разработчики используют проверенный и надежный паттерн со «скрытой кнопкой»:
window), после чего программно вызывается событие нажатия на скрытую кнопку.Проанализируем программную реализацию этого механизма:
// Шаг 1: Добавление скрытого контейнера для обмена данными (внедряем в HTML)
// <button id="hidden_exchange_trigger" style="display:none;"></button>
// Шаг 2: JavaScript код на веб-странице, подготавливающий и отправляющий данные
// window.exchange_payload = JSON.stringify({status: "success", userId: 1045, token: "AbCDeF123"});
// document.getElementById("hidden_exchange_trigger").click();
// Шаг 3: Прием данных на стороне 1С
Процедура ПолеHTMLДокументаПриНажатии(Элемент, ДанныеСобытия, СтандартнаяОбработка)
НажатыйЭлемент = ДанныеСобытия.Element;
Если НажатыйЭлемент <> Неопределено И НажатыйЭлемент.id = "hidden_exchange_trigger" Тогда
СтандартнаяОбработка = Ложь; // Предотвращаем стандартное поведение
Документ = Элементы.ПолеHTMLДокумента.Документ;
Окно = ?(Документ.defaultView <> Неопределено, Документ.defaultView, Документ.parentWindow);
Если Окно <> Неопределено Тогда
// Извлекаем записанные JS данные
СтрокаДанныхJSON = Окно.exchange_payload;
Если ЗначениеЗаполнено(СтрокаДанныхJSON) Тогда
// Читаем JSON в структуру 1С
ЧтениеJSON = Новый ЧтениеJSON;
ЧтениеJSON.УстановитьСтроку(СтрокаДанныхJSON);
РезультатДанных = ПрочитатьJSON(ЧтениеJSON);
ЧтениеJSON.Закрыть();
// Обрабатываем полученные данные
ПоказатьПредупреждение(, "Успешно получены данные пользователя с ID: " + РезультатДанных.userId);
// Очищаем переменную обмена на странице
Окно.exchange_payload = "";
КонецЕсли;
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Если ваша конечная цель состоит исключительно в получении (парсинге) данных с сайта в автоматическом режиме (например, по расписанию в регламентном задании), использование визуального компонента Поле HTML документа на форме является крайне неэффективным решением. Оно потребляет оперативную память, требует контекста выполнения клиентского приложения и снижает общую производительность системы.
Платформа 1С предлагает мощный альтернативный инструментарий для загрузки и объектного разбора веб-страниц полностью на стороне сервера без создания каких-либо форм:
// 1. Устанавливаем соединение с удаленным сервером
Соединение = Новый HTTPСоединение("example-site.ru", , , , , 15);
Запрос = Новый HTTPЗапрос("/user/login");
Попытка
// Получаем тело страницы в виде текста
Ответ = Соединение.Получить(Запрос);
Если Ответ.КодСостояния = 200 Тогда
ТекстHTML = Ответ.ПолучитьТелоКакСтроку();
// 2. Инициализируем объект ЧтениеHTML для последовательного разбора
ЧтениеHTML = Новый ЧтениеHTML;
ЧтениеHTML.УстановитьСтроку(ТекстHTML);
// 3. Создаем ПостроительDOM для генерации объектного дерева в памяти
ПостроительDOM = Новый ПостроительDOM;
ДокументHTML = ПостроительDOM.Прочитать(ЧтениеHTML);
// Закрываем поток чтения
ЧтениеHTML.Закрыть();
// 4. Выполняем поиск необходимых элементов DOM без отрисовки интерфейса
// Например, найдем все ссылки на странице
КоллекцияСсылок = ДокументHTML.ПолучитьЭлементыПоИмени("a");
Для Каждого ТекущаяСсылка Из КоллекцияСсылок Цикл
Адрес = ТекущаяСсылка.ПолучитьАтрибут("href");
Если ЗначениеЗаполнено(Адрес) Тогда
ЗаписьЖурналаРегистрации("ПарсерDOM", УровеньЖурналаРегистрации.Информация, , , "Найдена ссылка: " + Адрес);
КонецЕсли;
КонецЦикла;
КонецЕсли;
Исключение
ВызватьИсключение "Ошибка при загрузке страницы: " + ОписаниеОшибки();
КонецПопытки;
Использование связки HTTPСоединение + ПостроительDOM позволяет решать задачи парсинга и анализа документов в фоновом режиме на сервере 1С. Это работает в десятки раз быстрее, стабильнее и не зависит от операционной системы и версии установленного браузера.