При интеграции 1С с внешними сайтами, парсинге каталогов поставщиков или получении данных с веб-страниц разработчики часто сталкиваются с необходимостью извлечь нужную информацию из HTML-разметки. Разберем основные способы решения этой задачи, начиная со штатных средств платформы и заканчивая специализированными альтернативными подходами.
Платформа 1С:Предприятие предоставляет встроенные инструменты для чтения и синтаксического анализа разметки: объекты ЧтениеHTML и ПостроительDOM. Они позволяют преобразовать веб-страницу в объектную модель документа (DOM) и работать с ней программно.
Рассмотрим базовый пример создания DOM-дерева из веб-страницы:
ЧтениеHTML = Новый ЧтениеHTML;
ПостроительDOM = Новый ПостроительDOM;
ЧтениеHTML.ОткрытьФайл("http://forum.mista.ru", "windows-1251");
ДокументHTML = ПостроительDOM.Прочитать(ЧтениеHTML);
Однако на практике метод ОткрытьФайл с передачей прямого URL имеет серьезные ограничения: он не позволяет передать заголовки запроса (например, User-Agent, авторизационные куки или заголовки сжатия). Из-за этого многие современные веб-серверы блокируют подобные запросы или отдают страницу с ошибкой.
Разберем по шагам более надежный и правильный подход, в котором загрузка данных и их последующий разбор разделены:
HTTPСоединение и настраиваемого HTTPЗапрос.ЧтениеHTML через метод УстановитьСтроку().ДокументHTML с помощью объекта ПостроительDOM.Посмотрим на практический пример реализации:
Соединение = Новый HTTPСоединение("site.example.com", 443, , , , 30, Новый ЗащищенноеСоединениеOpenSSL);
ЗапросHTTP = Новый HTTPЗапрос("/catalog/items");
ЗапросHTTP.Заголовки.Вставить("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)");
ОтветHTTP = Соединение.Получить(ЗапросHTTP);
Если ОтветHTTP.КодСостояния = 200 Тогда
ТекстHTML = ОтветHTTP.ПолучитьТелоКакСтроку();
ПарсерHTML = Новый ЧтениеHTML;
ПарсерHTML.УстановитьСтроку(ТекстHTML);
Построитель = Новый ПостроительDOM;
ДокументDOM = Построитель.Прочитать(ПарсерHTML);
// Получаем доступ к тегам страницы
Элементы = ДокументDOM.ПолучитьЭлементыПоИмениТега("div");
Для Каждого Элемент Из Элементы Цикл
// Обработка узлов DOM
КонецЦикла;
ПарсерHTML.Закрыть();
КонецЕсли;
Важное ограничение: штатный ПостроительDOM крайне чувствителен к валидности кода. Если на странице присутствуют незакрытые теги, грубые синтаксические ошибки или некорректная вложенность, метод Прочитать() может вызвать исключение.
Когда документ успешно прочитан в объект ДокументHTML, искать нужные элементы последовательным перебором циклом не всегда удобно. Платформа поддерживает язык запросов XPath, который позволяет адресовать конкретные узлы документа по их атрибутам, структуре или пути.
Для работы с XPath используются объекты ВыражениеXPath и РазыменовательПространствИменDOM. Проанализируем пример получения таблицы с заданным классом:
Разыменователь = ДокументDOM.СоздатьРазыменовательПространствИмен(ДокументDOM.ЭлементДокумента);
Выражение = ДокументDOM.СоздатьВыражениеXPath("//table[@class='price-table']//tr", Разыменователь);
РезультатXPath = Выражение.Вычислить(ДокументDOM, ТипРезультатаXPath.НеупорядоченныйНаборУзлов);
Узел = РезультатXPath.ПолучитьСледующий();
Пока Узел <> Неопределено Цикл
ТекстСтроки = Узел.ТекстовоеСодержимое;
Узел = РезультатXPath.ПолучитьСледующий();
КонецЦикла;
Этот подход значительно ускоряет выборку данных со сложных страниц с глубокой вложенностью элементов.
Если страница содержит невалидную HTML-разметку, штатный ПостроительDOM не сможет ее обработать. В операционных системах семейства Windows отличным решением является COM-объект htmlfile (движок MSHTML). Его ключевое преимущество заключается в том, что он автоматически исправляет ошибки синтаксиса и строит корректное дерево документа.
Рассмотрим пример загрузки и обработки строки с помощью htmlfile:
HTMLДокумент = Новый COMОбъект("htmlfile");
HTMLДокумент.open();
HTMLДокумент.write(ТекстHTML);
HTMLДокумент.close();
// Поиск элементов по тегу или классу
ВсеТаблицы = HTMLДокумент.getElementsByTagName("table");
Для Счетчик = 0 По ВсеТаблицы.length - 1 Цикл
Таблица = ВсеТаблицы.item(Счетчик);
// Извлечение нужных данных
КонецЦикла;
Обратите внимание: данный способ работает исключительно на серверах и клиентах под управлением Windows и не может использоваться на серверах под Linux.
Если с веб-страницы требуется получить всего одно или два значения (например, номер заказа, CSRF-токен, артикул или цену товара), построение полного DOM-дерева избыточно и ресурсоемко. В таких ситуациях эффективно применить строковые функции платформы (Найти, Сред, СтрШаблон) или регулярные выражения.
В современных версиях платформы реализован встроенный объект РегулярноеВыражение:
Выражение = Новый РегулярноеВыражение("<span class=""price"">(.*?)</span>");
Результат = Выражение.Найти(ТекстHTML);
Если Результат <> Неопределено Тогда
Цена = Результат.Группы[1].Значение;
КонецЕсли;
Если встроенный объект регулярных выражений недоступен в вашей версии платформы, в среде Windows можно использовать COMОбъект("VBScript.RegExp").
Выясним причину, по которой парсинг может не приносить результата. Если сайт разработан с использованием динамических JavaScript-фреймворков (Single Page Applications) или подгружает каталог через асинхронные AJAX-запросы, то исходный HTML, полученный через HTTPСоединение или ЧтениеHTML, не будет содержать полезных данных.
В этом случае применимы следующие решения:
ПолеHTMLДокумента, дождаться завершения скриптов и прочитать свойство Документ (подходит только для клиентских сценариев).