При интеграции 1С:Предприятия с внешними сайтами или веб-сервисами разработчики часто используют COM-соединение с браузером через объект InternetExplorer.Application. В процессе написания кода для взаимодействия с веб-страницей можно столкнуться с неожиданной проблемой: при попытке получить доступ к форме или элементу коллекции по его индексу привычным способом Document.Forms[0] платформа 1С возвращает ошибку «Получение элемента по индексу не определено». При этом в отладчике объект и его коллекция видны, но обратиться к конкретному элементу через квадратные скобки напрямую не получается.
В этой статье мы подробно разберем, почему возникает данная ошибка, как правильно обращаться к коллекциям DOM-документа из 1С и какие современные альтернативы существуют, если целевой сайт перестал поддерживать Internet Explorer.
Для начала проанализируем поведение платформы 1С:Предприятие при работе с внешними COM-объектами. Когда мы обращаемся к свойству ie.document.forms, COM-сервер возвращает нам специальный объект коллекции (тип HTMLCollection или NodeList). В языке JavaScript, который выполняется внутри самого браузера, эти объекты являются массивоподобными, поэтому к ним можно без проблем обращаться с использованием квадратных скобок: forms[0].
Однако среда 1С взаимодействует с COM-объектом через универсальный интерфейс IDispatch. Платформа 1С:Предприятие не умеет автоматически транслировать синтаксис квадратных скобок [] во внутренний индексатор COM-объекта, если этот объект явно не описывает свойство по умолчанию. Так как у COM-объекта коллекции Internet Explorer нет явного свойства по умолчанию, понятного 1С, обращение по индексу в квадратных скобках вызывает ошибку выполнения.
Для обхода этой проблемы необходимо использовать явный вызов методов COM-объекта. Все стандартные коллекции DOM-элементов в Internet Explorer поддерживают метод item(), который принимает в качестве параметра числовой индекс элемента (начиная с 0) или его имя/идентификатор в виде строки.
Рассмотрим подробнее пример правильного кода для получения первой формы на веб-странице:
// Создаем объект браузера и переходим на сайт
ie = Новый COMОбъект("InternetExplorer.Application");
ie.Visible = Ложь; // Запускаем в фоновом режиме
ie.Navigate("https://example.com/login");
// Ожидаем завершения загрузки страницы
Пока ie.ReadyState < 4 Цикл
ОбработкаПрерыванияПользователя();
КонецЦикла;
Документ = ie.document;
// Попытка обратиться через квадратные скобки вызовет ошибку:
// Неправильно: Форма = Документ.forms[0];
// Правильное обращение через метод item():
Попытка
Форма = Документ.forms.item(0);
Сообщить("Форма успешно получена! Имя формы: " + Форма.name);
Исключение
Сообщить("Не удалось получить форму: " + ОписаниеОшибки());
КонецПопытки;
Важное примечание: Обратите внимание на написание метода. Метод называется именно item (в единственном числе, без буквы "s" на конце). Ошибка в названии метода (например, написание items(0)) также приведет к аварийному завершению работы скрипта.
Если на странице присутствует несколько форм и нам необходимо перебрать их все, мы можем использовать свойство length для организации стандартного цикла:
КоличествоФорм = Документ.forms.length;
Для Индекс = 0 По КоличествоФорм - 1 Цикл
ТекущаяФорма = Документ.forms.item(Индекс);
Сообщить("Найдена форма с ID: " + ТекущаяФорма.id);
КонецЦикла;
Чтобы сделать ваш код более отказоустойчивым и независимым от порядка расположения элементов (ведь порядок форм на странице может измениться в любой момент, и индекс 0 станет неактуальным), мы рекомендуем использовать другие методы поиска элементов в DOM:
id, используйте метод getElementById. Он возвращает конкретный элемент напрямую, минуя коллекции.
// Получаем элемент напрямую по его ID
Форма = Документ.getElementById("main_login_form");
Если Форма <> Неопределено Тогда
// Работаем с формой напрямую
Форма.submit();
КонецЕсли;
// Обращение к элементу по его строковому имени внутри коллекции
ПолеВвода = Форма.elements.item("USER_LOGIN");
ПолеВвода.value = "Администратор";
Современные веб-технологии стремительно развиваются, и многие сайты полностью прекращают поддержку браузера Internet Explorer (даже версии IE11), называя его устаревшим. В результате скрипты автоматизации 1С через COM-объект InternetExplorer.Application начинают завершаться с ошибками выполнения JavaScript на стороне сайта.
Проанализируем современные варианты решения этой проблемы в среде 1С:Предприятие:
Если ваша задача состоит в отображении сайта и управлении им непосредственно в интерактивном режиме внутри формы 1С, вам больше не нужен Internet Explorer. Начиная с версии платформы 8.3.14, фирма «1С» полностью перевела встроенный элемент управления «Поле HTML-документа» на современный движок WebKit / Chromium.
Теперь любой сайт будет отображаться корректно прямо внутри формы вашей обработки. Однако при переходе на новый движок WebKit изменятся методы программного управления страницей из кода 1С:
parentWindow (которое использовалось в IE для вызова скриптов) необходимо использовать свойство defaultView.eval().Пример программного взаимодействия с новым движком WebKit в управляемой форме 1С:
// Получаем объект окна браузера WebKit
ОкноБраузера = Элементы.ПолеHTMLДокумента.Документ.defaultView;
// Заполняем поле формы и отправляем ее через выполнение JS-кода
СкриптЗаполнения = "
|document.forms[0].elements['USER_LOGIN'].value = 'Администратор';
|document.forms[0].submit();
|";
ОкноБраузера.eval(СкриптЗаполнения);
Если вам требуется фоновая автоматизация внешнего полноценного браузера без показа интерфейса пользователю, напрямую запустить Chrome через COM-объект наподобие Новый COMОбъект("GoogleChrome.Application") не получится, так как современные браузеры не предоставляют COM-интерфейсов для Windows.
Для решения этой задачи используется профессиональный инструмент автоматизации — Selenium WebDriver. Схема взаимодействия выглядит следующим образом:
chromedriver.exe для браузера Google Chrome). Этот драйвер выступает в роли локального HTTP-сервера.HTTPСоединение отправляются команды на этот локальный сервер в формате JSON-запросов (по протоколу W3C WebDriver).Посмотрим на пример отправки HTTP-запроса из 1С к ChromeDriver для инициализации новой сессии браузера Chrome:
// Настраиваем соединение с запущенным chromedriver.exe (по умолчанию порт 9515)
Соединение = Новый HTTPСоединение("localhost", 9515);
// Подготавливаем JSON-параметры запуска Chrome
ПараметрыЗапуска = Новый Соответствие;
ПараметрыЗапуска.Вставить("capabilities", Новый Соответствие);
ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку();
ЗаписатьJSON(ЗаписьJSON, ПараметрыЗапуска);
ТелоЗапроса = ЗаписьJSON.Закрыть();
HTTPЗапрос = Новый HTTPЗапрос("/session");
HTTPЗапрос.УстановитьТелоИзСтроки(ТелоЗапроса, КодировкаТекста.UTF8, ИспользованиеByteOrderMark.НеИспользовать);
Попытка
HTTPОтвет = Соединение.ОтправитьДляОбработки(HTTPЗапрос);
Если HTTPОтвет.КодСостояния = 200 Тогда
Сообщить("Сессия Chrome успешно запущена. Браузер готов к автоматизации!");
КонецЕсли;
Исключение
Сообщить("Не удалось запустить Chrome через WebDriver: " + ОписаниеОшибки());
КонецПопытки;
Использование связки 1С и Selenium WebDriver позволяет полностью отказаться от устаревших COM-объектов Internet Explorer, обеспечивая быструю, стабильную и современную работу с любыми веб-ресурсами непосредственно из кода вашей конфигурации.