Почему при парсинге сайта в 1С выводится неверная цена и как получить реальные данные?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При разработке интеграций и парсинге сторонних интернет-магазинов или веб-сервисов разработчики 1С часто сталкиваются с ситуацией, когда на самом сайте отображаются актуальные цены и остатки, а при загрузке страницы в 1С вместо реальной стоимости считывается значение «100 р.» или пустая строка. Рассмотрим, почему возникает эта проблема и как правильно организовать парсинг данных в 1С.

Причина проблемы: динамическая загрузка через JavaScript

Выясним причину такого поведения платформы. Объекты 1С HTTPСоединение, HTTPЗапрос, а также ЧтениеHTML и ПостроительDOM работают исключительно с сетевым HTTP-ответом и статическим HTML-кодом. Они не имеют встроенного движка выполнения скриптов (JavaScript).

Многие современные сайты используют клиентский рендеринг (Single Page Applications или библиотеки jQuery/React/Vue). При отправке обычного GET-запроса сервер возвращает каркас страницы, в котором подставлены базовые значения-заглушки (например, «100 р.» в таблице по умолчанию). Затем браузер пользователя выполняет встроенный сценарий JavaScript, делает дополнительный запрос (AJAX/Fetch) к внутреннему API и подставляет настоящую цену в DOM-дерево. Поскольку встроенные средства HTTP-запросов 1С не исполняют JS, они получают только первичный шаблон страницы.

Проанализируем исходный код, выдающий неверный результат

Разберем пример кода, в котором попытка разобрать DOM-дерево HTML-страницы приводит к считыванию статических заглушек:


&НаКлиенте
Функция ПолучитьСтраницуВОбъектDOM(Знач Адрес)
    
    АдресСтруктура = СтруктураАдреса(Адрес);
    Соединение = Новый HTTPСоединение(АдресСтруктура.ИмяСервера, АдресСтруктура.Порт);
    ВебЗапрос = Новый HTTPЗапрос(АдресСтруктура.ПутьНаСервере);
    
    Попытка
        Результат = Соединение.Получить(ВебЗапрос);
    Исключение
        Сообщить("Ошибка соединения");
        ВызватьИсключение;
    КонецПопытки;
    
    Ответ = Результат.ПолучитьТелоКакСтроку(КодировкаТекста.UTF8);
    
    Чтение = Новый ЧтениеHTML;
    Чтение.УстановитьСтроку(Ответ);
    ОбъектыDOM = Новый ПостроительDOM;
    
    Возврат ОбъектыDOM.Прочитать(Чтение);
    
КонецФункции

При обработке полученного объекта DOMDocument поиск элементов по тегам tbody или tr вернет только первичные статичные теги, сформированные до работы скриптов.

Решение проблемы: перехват данных JSON или вызов API

Для получения реальных данных проанализируем структуру ответа сервера или исходный текст страницы. В большинстве случаев данные товаров передаются в виде массива объектов JSON — либо внутри тега script в теле страницы, либо отдельным AJAX-запросом.

Посмотрим на пример извлечения данных из тела ответа с помощью HTTP-запроса или объекта COM MSXML2.XMLHTTP:


WinHttp = Новый COMОбъект("MSXML2.XMLHTTP.6.0");
WinHttp.Open("GET", "https://example.com/catalog/item_id", Ложь);
WinHttp.Send();

ТекстОтвета = WinHttp.ResponseText;

В тексте ответа находится не только HTML, но и блок с данными вида:


data: [{"IdStore":"13325","Region":"Челябинск","Cat":"Vag","Name":"ГЕНЕРАТОР","Price":18715.01,"Days":19}, ...]

Разберем по шагам извлечение и обработку цен в 1С

  1. Нахождение данных в ответе: Найдём подстроку, содержащую JSON-массив с товарами и ценами (например, используя функции Найти и Сред).
  2. Десериализация JSON: Преобразуем найденную подстроку JSON в структуру или массив 1С с помощью объектов ЧтениеJSON и ПрочитатьJSON().
  3. Получение реквизитов: Считаем значение реквизита Price напрямую из полученной структуры 1С.

Рассмотрим пример кода на стороне 1С для работы со встроенными средствами HTTPСоединение и разбором JSON:


&НаСервере
Функция ПолучитьАктуальныеЦеныССайта(ИмяСервера, ПутьНаСервере)
    
    Соединение = Новый HTTPСоединение(ИмяСервера, 443, , , , 10, Новый ЗащищенноеСоединениеOpenSSL());
    Запрос = Новый HTTPЗапрос(ПутьНаСервере);
    
    // Передаем необходимые заголовки для имитации браузера
    Запрос.Заголовки.Вставить("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)");
    Запрос.Заголовки.Вставить("X-Requested-With", "XMLHttpRequest");
    
    Ответ = Соединение.Получить(Запрос);
    
    Если Ответ.КодСостояния = 200 Тогда
        ТекстОтвета = Ответ.ПолучитьТелоКакСтроку(КодировкаТекста.UTF8);
        
        // Извлекаем JSON-строку из текста ответа
        ПозицияНачала = Найти(ТекстОтвета, "data: [");
        Если ПозицияНачала > 0 Тогда
            СтрокаJSON = Сред(ТекстОтвета, ПозицияНачала + 6);
            ПозицияКонца = Найти(СтрокаJSON, "]}");
            Если ПозицияКонца > 0 Тогда
                СтрокаJSON = Лев(СтрокаJSON, ПозицияКонца + 1);
                
                // Читаем JSON
                ЧтениеJSON = Новый ЧтениеJSON;
                ЧтениеJSON.УстановитьСтроку(СтрокаJSON);
                МассивТоваров = ПрочитатьJSON(ЧтениеJSON);
                
                Возврат МассивТоваров;
            КонецЕсли;
        КонецЕсли;
    КонецЕсли;
    
    Возврат Неопределено;
    
КонецФункции

Альтернативные способы решения

Если данные подгружаются отдельным внутренним API-эндопоинтом (XHR), рекомендуется изучить сетевые запросы страницы в консоли разработчика браузера (вкладка Network / Сеть). Направив HTTPЗапрос непосредственно на URL этого API, вы получите чистый JSON с ценами без необходимости распарсивать HTML-документ.

В случаях, когда сайт требует полноценной эмуляции браузера для генерации сессионных ключей на JS, на клиентской стороне 1С можно использовать элемент формы ПолеHTMLДокумента, который выполняет JS-скрипты, после чего извлекать итоговый DOM из объекта документа Элементы.ПолеHTML.Документ.

← На главную