Как реализовать автоматическую загрузку курсов валют Сербии с сайта NBS в 1С?

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

При работе с иностранными контрагентами часто возникает необходимость автоматизировать получение актуальных курсов валют. В случае с Народным банком Сербии (NBS) задача осложняется тем, что основная страница сайта использует сложную разметку, и прямой HTTP-запрос к главной странице может не вернуть нужных данных. В этой статье мы подробно разберем, как обойти эти ограничения, проанализируем различные методы интеграции и напишем программный код для автоматической загрузки курсов.

Проблема получения данных с динамических страниц

Рассмотрим стандартную ситуацию: при попытке получить тело страницы через HTTPСоединение и метод Получить(), мы часто видим программный код разметки, но самих значений курсов в тексте нет. Это происходит потому, что данные могут подгружаться скриптами или находиться внутри фреймов. Для решения этой задачи нам нужно найти "чистый" источник данных или страницу с упрощенной структурой.

Проанализируем структуру сайта банка. Вместо основной страницы лучше использовать специализированный модуль для отображения курсов, который отдает таблицу в более доступном для парсинга виде. Один из таких адресов: /kursnaListaModul/srednjiKurs.faces?lang=cir.

Метод 1: Парсинг HTML-таблицы с помощью XPath и DOM

Этот метод является наиболее гибким, так как не требует регистрации в официальных сервисах банка. Мы загрузим содержимое страницы, построим дерево DOM и извлечем данные с помощью XPath-запроса. Разберем этот процесс по шагам.

Для начала настроим защищенное соединение, так как сайт работает по протоколу HTTPS. Используем объект ЗащищенноеСоединениеOpenSSL. Далее выполним запрос и получим тело ответа.

Важный нюанс в 1С: чтобы корректно обработать HTML как дерево объектов, его иногда полезно прогнать через цепочку ЧтениеHTML -> ПостроительDOM -> ЗаписьXML. Это позволяет "вылечить" возможные ошибки в верстке страницы. Рассмотрим пример реализации:


Хост = "nbs.rs";
Адрес = "/kursnaListaModul/srednjiKurs.faces?lang=cir";

// Настройка защищенного соединения
Защита = Новый ЗащищенноеСоединениеOpenSSL();
HTTPСоединение = Новый HTTPСоединение(Хост, 443, , , , , Защита); 
HTTPЗапрос = Новый HTTPЗапрос(Адрес); 

Попытка
    РезультатЗапроса = HTTPСоединение.Получить(HTTPЗапрос);
    ТекстHTML = РезультатЗапроса.ПолучитьТелоКакСтроку();
Исключение
    Сообщить("Ошибка подключения: " + ОписаниеОшибки());
    Возврат;
КонецПопытки;

// Парсинг через DOM
ЧтениеHTML = Новый ЧтениеHTML;
ЧтениеHTML.УстановитьСтроку(ТекстHTML);
ПостроительDOM = Новый ПостроительDOM;
ДокументHTML = ПостроительDOM.Прочитать(ЧтениеHTML);

// Преобразуем в XML для стабильности XPath
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.УстановитьСтроку("UTF-8");
ЗаписьDOM = Новый ЗаписьDOM;
ЗаписьDOM.Записать(ДокументHTML.Тело, ЗаписьXML);

ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.УстановитьСтроку(ЗаписьXML.Закрыть());
ДокументDOM = ПостроительDOM.Прочитать(ЧтениеXML);

// Используем XPath для поиска данных в таблице
Разименовыватель = Новый РазыменовательПространствИменDOM(ДокументDOM);
ВыражениеXPath = ".//*/table[@id='index:srednjiKursLista']/tbody/tr/td/text()";
РезультатXPath = ДокументDOM.ВычислитьВыражениеXPath(ВыражениеXPath, ДокументDOM, Разименовыватель);

После выполнения этого кода в переменной РезультатXPath будет содержаться итератор по всем ячейкам таблицы. Нам остается только обойти их в цикле и заполнить ТаблицаЗначений. Обратите внимание, что структура таблицы обычно содержит фиксированное количество колонок (код валюты, название, количество единиц, курс).

Заполнение таблицы курсов

Проанализируем, как правильно обработать полученные узлы DOM. Поскольку данные идут сплошным списком ячеек, будем использовать счетчик колонок для определения начала новой строки.


ТаблицаКурсов = Новый ТаблицаЗначений;
ТаблицаКурсов.Колонки.Добавить("Код");
ТаблицаКурсов.Колонки.Добавить("Наименование");
ТаблицаКурсов.Колонки.Добавить("Номинал");
ТаблицаКурсов.Колонки.Добавить("Курс");

СчетчикКолонок = 0;
Пока Истина Цикл
    ЭлементDOM = РезультатXPath.ПолучитьСледующий();
    Если ЭлементDOM = Неопределено Тогда
        Прервать;
    КонецЕсли;
    
    // Каждая строка в таблице сайта содержит 5 колонок
    Если СчетчикКолонок = 0 Тогда
        НоваяСтрока = ТаблицаКурсов.Добавить();
    КонецЕсли;
    
    Значение = СокрЛП(ЭлементDOM.ТекстовоеСодержимое);
    
    Если СчетчикКолонок = 0 Тогда
        НоваяСтрока.Код = Значение;
    ИначеЕсли СчетчикКолонок = 2 Тогда // Пример: Пропускаем цифровой код, берем название
        НоваяСтрока.Наименование = Значение;
    ИначеЕсли СчетчикКолонок = 3 Тогда
        НоваяСтрока.Номинал = Число(СтрЗаменить(Значение, ",", "."));
    ИначеЕсли СчетчикКолонок = 4 Тогда
        НоваяСтрока.Курс = Число(СтрЗаменить(Значение, ",", "."));
    КонецЕсли;
    
    СчетчикКолонок = СчетчикКолонок + 1;
    Если СчетчикКолонок = 5 Тогда
        СчетчикКолонок = 0;
    КонецЕсли;
КонецЦикла;

Важный момент: в сербских курсах разделителем дробной части часто выступает запятая. Для корректного преобразования в Число в 1С необходимо предварительно заменить запятую на точку с помощью функции СтрЗаменить.

Метод 2: Официальный Web-сервис (SOAP)

Народный банк Сербии предоставляет официальный программный интерфейс для взаимодействия. Это более надежный способ, так как он не зависит от изменений в дизайне сайта. Сервис доступен через протокол SOAP.

Разберем особенности работы с ним:

  1. Регистрация: Для доступа к сервису требуется Username и Password. Их можно получить, отправив запрос в ИТ-отдел банка.
  2. Методы: Основные методы, которые нас интересуют: GetExchangeRateByDate (курс на определенную дату) и GetCurrentExchangeRate (текущий курс).
  3. Реализация в 1С: Для работы используйте объект WSПрокси. Вам потребуется адрес WSDL, который указан в документации банка.

Преимущество этого метода в том, что ответ приходит в типизированном виде, и вам не нужно заниматься парсингом HTML. Однако из-за необходимости регистрации этот метод часто выбирают только для крупных корпоративных систем.

Метод 3: Использование альтернативных форматов (XML/CSV)

Если веб-сервис кажется слишком сложным, а парсинг HTML — нестабильным, можно использовать возможность экспорта данных. На сайте банка предусмотрена форма, отправляющая POST-запрос для выгрузки файла в формате XML или Excel.

Выясним причину, почему это удобно: 1С имеет встроенные высокопроизводительные средства для работы с XML (объект ЧтениеXML). Вы можете программно сформировать HTTPЗапрос, передав в теле параметры даты и типа файла, и получить в ответ готовый XML-документ.

Технические нюансы и рекомендации

Проанализируем несколько критически важных моментов, которые часто упускают при разработке подобных загрузчиков:

1. Кодировка текста. Сайт NBS активно использует кириллицу. При получении данных всегда проверяйте кодировку ответа. Обычно это UTF-8. Если вы видите некорректные символы, убедитесь, что при вызове ПолучитьТелоКакСтроку() не произошло искажения.

2. Временные рамки. Официальный средний курс в Сербии обычно публикуется на следующий рабочий день. То есть курс, опубликованный сегодня днем, фактически начнет действовать только с завтрашнего числа. Учитывайте это при записи данных в регистр сведений КурсыВалют.

3. Обработка ошибок. Сетевые запросы склонны к сбоям. Всегда оборачивайте блоки работы с HTTPСоединение в конструкцию Попытка ... Исключение. Также полезно проверять статус-код ответа: Ответ.КодСостояния должен быть равен 200.

4. ViewState. Если вы решите парсить основную страницу через POST-запросы, помните, что технология JavaServer Faces (.faces) требует передачи скрытого параметра javax.faces.ViewState. Без него сервер может вернуть ошибку сессии или неактуальные данные.

Подводя итог, наиболее быстрым и эффективным способом для программиста 1С является парсинг страницы через DOM и XPath, так как он позволяет получить данные здесь и сейчас без бюрократических процедур регистрации в API банка.

← На главную