В современной веб-разработке все чаще встречается подход Single Page Application (SPA), когда сервер отдает браузеру лишь пустой каркас страницы и тяжелый JavaScript-сценарий. Этот сценарий при выполнении на стороне клиента отправляет фоновые запросы, получает данные и динамически строит DOM-дерево страницы — формирует тексты, таблицы, гиперссылки и изображения.
Если мы попытаемся получить содержимое такой страницы классическим HTTP-запросом через HTTPСоединение в 1С или просто сохраним ее код, то в результате получим лишь стартовый скрипт-загрузчик. Полноценного HTML-кода с нужными нам данными там не будет. Выясним, как решить эту задачу средствами платформы 1С 8.3, используя как штатные инструменты, так и продвинутые методы интеграции.
Рассмотрим по шагам несколько эффективных методов решения этой проблемы: от встроенных механизмов платформы до интеграции с внешними инструментами автоматизации.
Начиная с версии платформы 1С 8.3.14, встроенный элемент управления Поле HTML документа на операционной системе Windows использует современный движок Chromium (ранее использовался устаревший Internet Explorer/Trident). Это дает нам возможность полноценно выполнять клиентские JS-скрипты любой сложности прямо внутри управляемой формы 1С.
Типичная ошибка: Пытаться скачать сырой HTML-текст через HTTP-запрос, а затем присвоить его свойству поля HTML-документа. В этом случае скрипты сайта упадут с ошибками, так как они попытаются загрузить вспомогательные файлы по относительным путям в локальной папке платформы 1С.
Правильный алгоритм действий:
Строка (например, АдресСайта) и вынесем его на форму.Строка (например, СодержимоеСтраницы), перетащим его на форму и укажем вид элемента: Поле HTML документа.Рассмотрим пример кода инициализации перехода:
&НаКлиенте
Процедура ЗагрузитьСайт(Команда)
// Указываем адрес целевого динамического ресурса
АдресРесурса = "https://golikov.dev/web/index.html";
Элементы.СодержимоеСтраницы.Перейти(АдресРесурса);
КонецПроцедуры
Основная хитрость заключается в том, что парсить страницу нужно только после того, как JavaScript полностью отработает и сформирует итоговое DOM-дерево. Для этого мы должны использовать событие поля HTML-документа ДокументСформирован.
Проанализируем пример обработки сформированного документа для получения списка гиперссылок:
&НаКлиенте
Процедура СодержимоеСтраницыДокументСформирован(Элемент)
// Получаем DOM-модель документа из поля HTML-дерева
ДокументHTML = Элемент.Документ;
// Получаем коллекцию всех тегов "а" (гиперссылок) на странице
ВсеСсылки = ДокументHTML.getElementsByTagName("a");
Для Каждого Ссылка Из ВсеСсылки Цикл
// Извлекаем атрибут href
АдресСсылки = Ссылка.getAttribute("href");
Если ЗначениеЗаполнено(АдресСсылки) Тогда
// Обрабатываем полученную ссылку по бизнес-логике вашей системы
ОбработатьАдрес(АдресСсылки);
КонецЕсли;
КонецЦикла;
КонецПроцедуры
&НаКлиенте
Процедура ОбработатьАдрес(ЗначениеСсылки)
// Пример вывода в окно сообщений
Сообщить("Найдена ссылка: " + ЗначениеСсылки);
КонецПроцедуры
В тех случаях, когда объектная модель 1С для работы с DOM кажется слишком громоздкой, мы можем внедрить и выполнить собственный JS-код прямо в контексте загруженной страницы с помощью метода eval:
&НаКлиенте
Процедура СодержимоеСтраницыДокументСформирован(Элемент)
ОкноДокумента = Элемент.Документ.defaultView;
// JS-скрипт соберет все ссылки в одну строку с разделителем "|"
СценарийJS = "
|var links = document.getElementsByTagName('a');
|var result = [];
|for (var i = 0; i < links.length; i++) {
| result.push(links[i].href);
|}
|result.join('|');
|";
СтрокаСсылок = ОкноДокумента.eval(СценарийJS);
МассивСсылок = СтрРазделить(СтрокаСсылок, "|");
Для Каждого Ссылка Из МассивСсылок Цикл
Сообщить("JS Нашел: " + Ссылка);
КонецЦикла;
КонецПроцедуры
Даже если сайт защищен, а клиентский скрипт обфусцирован, сам браузер пользователя все равно общается с сервером по стандартным протоколам. Скрипт запрашивает данные с сервера (чаще всего в формате JSON) и только потом отрисовывает их в браузере.
Вместо того чтобы эмулировать браузер и выполнять тяжелые скрипты рендеринга, мы можем перехватить эти запросы и отправлять их напрямую из 1С.
Выполним следующие шаги для анализа сайта:
После того как структура запроса станет понятна, мы можем воссоздать этот запрос средствами 1С. Посмотрим на пример реализации HTTP-запроса к скрытому API сайта:
&НаСервере
Процедура ПолучитьДанныеЧерезAPI()
// Настраиваем защищенное соединение
ЗащищенноеСоединение = Новый ЗащищенноеСоединениеOpenSSL();
// Указываем хост и создаем HTTP-соединение
Соединение = Новый HTTPСоединение("api.targetsite.com", , , , , 15, ЗащищенноеСоединение);
// Формируем запрос к эндпоинту, который возвращает нужные данные
Запрос = Новый HTTPЗапрос("/v1/catalog/products?page=1");
// Обязательно эмулируем заголовки браузера, чтобы сервер не заблокировал запрос
Запрос.Заголовки.Вставить("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36");
Запрос.Заголовки.Вставить("Accept", "application/json");
Попытка
Ответ = Соединение.Получить(Запрос);
Если Ответ.КодСостояния = 200 Тогда
СтрокаJSON = Ответ.ПолучитьТелоКакСтроку();
// Парсим готовый структурированный JSON в структуру 1С
ЧтениеJSON = Новый ЧтениеJSON;
ЧтениеJSON.УстановитьСтроку(СтрокаJSON);
Данные = ПрочитатьJSON(ЧтениеJSON);
ЧтениеJSON.Закрыть();
// Обрабатываем полученные данные
Для Каждого Товар Из Данные.products Цикл
Сообщить(Товар.name + " - " + Товар.url);
КонецЦикла;
Иначе
Сообщить("Ошибка сервера. Код ответа: " + Ответ.КодСостояния);
EndIf;
Исключение
Сообщить("Не удалось выполнить запрос: " + ОписаниеОшибки());
КонецПопытки;
КонецПроцедуры
Преимущества данного метода: Скорость работы возрастает в десятки раз. Нам не нужно запускать графический интерфейс браузера, тратить память на рендеринг картинок и стилей. Мы получаем чистые данные напрямую.
Бывают ситуации, когда скрипты инициализации сайта генерируют сложные токены подписи каждого запроса на основе отпечатков браузера (Canvas Fingerprinting, сложные шифры), что делает прямые HTTP-запросы из 1С невозможными. В таких случаях нам необходим полноценный внешний эмулятор браузера под нашим управлением.
Для автоматизации этого процесса часто применяются скрипты на языке Python с использованием библиотеки Selenium или Playwright. Они могут работать в фоновом (headless) режиме без вывода графического окна на экран.
Разберем схему интеграции 1С с внешним Python-скриптом:
Пример кода на Python (скрипт parser.py):
# Шаг 1. Скрипт запускает браузер в фоновом режиме
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
import json
options = Options()
options.add_argument('--headless') # Фоновый режим
driver = webdriver.Chrome(options=options)
try:
driver.get('https://example.com')
# Дожидаемся отрисовки динамических элементов
driver.implicitly_wait(10)
# Находим все теги "а"
elements = driver.find_elements("tag name", "a")
links = [el.get_attribute('href') for el in elements if el.get_attribute('href')]
# Сохраняем в файл результатов
with open('result.json', 'w', encoding='utf-8') as f:
json.dump(links, f, ensure_ascii=False)
finally:
driver.quit()
Код запуска и чтения результатов в модуле 1С:
&НаСервере
Процедура ВыполнитьПарсингЧерезPython()
ПутьКСкрипту = """C:\Scrapers\parser.py""";
ПутьКФайлуРезультатов = "C:\Scrapers\result.json";
// Удаляем старый файл результатов перед запуском
ФайлРезультатов = Новый Файл(ПутьКФайлуРезультатов);
Если ФайлРезультатов.Существует() Тогда
УдалитьФайлы(ПутьКФайлуРезультатов);
КонецЕсли;
// Запускаем интерпретатор Python и ждем завершения выполнения (третий параметр = Истина)
КомандаЗапуска = "python " + ПутьКСкрипту;
ЗапуститьПриложение(КомандаЗапуска, , Истина);
// Считываем результат работы скрипта
Если ФайлРезультатов.Существует() Тогда
ЧтениеJSON = Новый ЧтениеJSON;
ЧтениеJSON.ОткрытьФайл(ПутьКФайлуРезультатов);
НайденныеСсылки = ПрочитатьJSON(ЧтениеJSON);
ЧтениеJSON.Закрыть();
Для Каждого Адрес Из НайденныеСсылки Цикл
Сообщить("Успешно импортировано: " + Адрес);
КонецЦикла;
Иначе
Сообщить("Ошибка: Скрипт парсинга не сформировал файл результатов.");
КонецЕсли;
КонецПроцедуры
Рассмотрим нестандартный подход, предложенный участниками обсуждения. Если сайт имеет защиту от парсинга, но ссылки на целевые объекты жестко завязаны на имена динамически загружаемых картинок-превью (например, ссылка на страницу товара формируется из ID картинки 12345.jpg), мы можем использовать локальный веб-сервер в качестве проксирующего звена.
При таком подходе мы:
Этот метод демонстрирует, что даже при максимальном уровне обфускации скриптов на стороне клиента, всегда существуют альтернативные технические лазейки для решения сложных задач автоматизации.
Выбор оптимального инструмента зависит от сложности целевого веб-ресурса: