Apache NiFi. Загрузка файлов через HTTPS

от автора

В одном из проектов возникла необходимость перевести процессы импорта данных сторонних систем на микросервисную архитектуру. В качестве инструмента выбран Apache NiFi. В качестве первого подопытного выбран импорт ЕГРЮЛ ФНС.
Шаг первый — загрузка файлов. Предполагался FTPS, а оказался HTTPS…

Источник данных

Получение данных из ЕГРЮЛ осуществляется в рамках услуги ФНС «Интеграция и доступ к базам данных ЕГРЮЛ и ЕГРИП». Описание модели взаимодействия представлено здесь.
Данные предоставляются в виде XML-файлов, упакованных в ZIP-архивы. Архивы ежедневно выкладывают на сервер в отдельный каталог для соответствующей даты. Для доступа к серверу выдается ключ #PKCS12. В описании указано, что это FTP-сервер. Но по FTP подключиться почему-то не удалось. Да и все пути ведут именно к ресурсу https://ftp.egrul.nalog.ru/, и естественно он благополучно открывается в браузере.

https://ftp.egrul.nalog.ru/?dir=EGRUL

Настройка DataFlow в Apache NiFi

DataFlow должен выполнять следующие операции:
1. Генерация ссылки на каталог с вчерашней выгрузкой — процессор GenerateFlowFile
2. Получение содержимого каталога — процессор InvokeHTTP
3. Получение ссылок на файлы архивов — процессор GetHTMLElement
4. Получение архивов — процессор InvokeHTTP
5. Распаковка архивов — процессор UnpackContent.

Генерация ссылки на каталог с вчерашней выгрузкой

Для генерации ссылки используется процессор GenerateFlowFile.

Скриншоты процессора GenerateFlowFile

Он запускается каждые 24 часа и создает FlowFile с атрибутом fnsEgrulURL, в который записывается значение выражения NiFi Expression Language:

${literal('https://ftp.egrul.nalog.ru/?dir=EGRUL/'):append(${now():toNumber():minus(86400000):format('dd.MM.yyyy')})} 

На выходе генерируетсяFlowFile следующего вида.

Скриншоты FlowFile

Получение содержимого каталога

Для получения содержимого каталога используется процессор InvokeHTTP. Он выполняет GET-запрос по ссылке, сгенерированной предыдущим процессором. В ответ процессор получает HTML-код страницы каталога с выгрузкой за вчерашнюю дату и добавляет этот HTML-код в FlowFile в качестве контента.

Скриншоты процессора InvokeHTTP

Процессор имеет следующие настройки:
HTTPMethod — метод GET;
Remote URL — выражение ${fnsEgrulURL}, т.е. значение берется из FlowFile из атрибута fnsEgrulURL;
SSL Context Service — необходимо создать контроллер типа SSLContextService или StandardRestrictedSSLContextService и настроить его для обращения к сайту ФНС через HTTPS.
Остальные параметры оставлены по умолчанию.

Контроллер SSLContextService

Скриншоты контроллера SSLContextService

В настройках котроллера SSLContexService необходимо указать путь и пароль к файлу ключа #PKCS12 и путь и пароль к хранилищу доверенных сертификатов, в котором размещен промежуточный сертификат из цепочки сертификатов, используемых при взаимодействии с ресурсом ФНС.

В качестве хранилища доверенных сертификатов использовано хранилище cacerts из состава JDK. В него необходимо импортировать промежуточный сертификат. Для получения промежуточного сертификата необходимо открыть страницу https://fns.egrul.nalog.ru в браузере, использовав ключ #PKCS12. В адресной строке нажать иконку защищенного соединения и открыть сертификат.

В цепочке сертификата необходимо выбрать сертификат Russian DPC Tax Service и экспортировать его в формате .CER в кодировке DER. Далее необходимо импортировать сертификат из полученного файла в хранилище cacerts c помощью утилиты keytool. Например, так:

C:\Program Files\Java\jdk1.8.0_121\bin> keytool -importcert -keystore "C:\Program Files\Java\jdk1.8.0_121\jre\lib\security\cacerts" -file {Путь к файлу .CER}

Пароль к cacerts по умолчанию — changeit.

Далее файл ключа и cacerts необходимо расположить там, где NiFi будет иметь к ним доступ. Например, в Persistent Volume. Соответствующие пути необходимо указать в параметрах контроллера SSLContextService. Там же для ключа необходимо указать тип PKSC12, а для cacerts — тип JKS.

Процессор InvokeHTTP добавит в FlowFile атрибуты, содержащие параметры запроса и ответа, и контент — HTML-код запрошенной страницы.

Получение ссылок на файлы архивов

Получение ссылок на файлы архивов выполняется процессором GetHTMLElement, который извлекает содержимое требуемого HTML-элемента из контента FlowFile-а. В данном случае нам требуется получить ссылки на ZIP-архивы.

Фрагмент страницы с требуемыми элементами

<div id="page-content" class="container">     <div id="directory-list-header">         <div class="row">             <div class="col-md-7 col-sm-6 col-xs-10">Файл</div>             <div class="col-md-2 col-sm-2 col-xs-2 text-right">Размер</div>             <div class="col-md-3 col-sm-4 hidden-xs text-right">Последнее изменение</div>         </div>     </div>     <ul id="directory-listing" class="nav nav-pills nav-stacked">                             <li data-name=".." data-href="https://ftp.egrul.nalog.ru/?dir=EGRUL">                 <a href="https://ftp.egrul.nalog.ru/?dir=EGRUL" class="clearfix" data-name="..">                     <div class="row">                         <span class="file-name col-md-7 col-sm-6 col-xs-9">                             <i class="fa fa-level-up fa-fw"></i>                             ..                                </span>                         <span class="file-size col-md-2 col-sm-2 col-xs-3 text-right">                             -                                </span>                         <span class="file-modified col-md-3 col-sm-4 hidden-xs text-right">                             2020-04-05 22:00:00                                </span>                     </div>                 </a>             </li>                             <li data-name="EGRUL_2020-04-05_1.zip" data-href="EGRUL/05.04.2020/EGRUL_2020-04-05_1.zip">                 <a href="EGRUL/05.04.2020/EGRUL_2020-04-05_1.zip" class="clearfix" data-name="EGRUL_2020-04-05_1.zip">                     <div class="row">                         <span class="file-name col-md-7 col-sm-6 col-xs-9">                             <i class="fa fa-file-archive-o fa-fw"></i>                             EGRUL_2020-04-05_1.zip                                </span>                         <span class="file-size col-md-2 col-sm-2 col-xs-3 text-right">                             528.78KB                                </span>                         <span class="file-modified col-md-3 col-sm-4 hidden-xs text-right">                             2020-04-05 22:00:24                                </span>                     </div>                 </a>                                          <a href="javascript:void(0)" class="file-info-button">                         <i class="fa fa-info-circle"></i>                     </a>             </li>     </ul> </div>

Скриншоты процессора GetHTMLElement

Параметры процессора:
URL — базовый URL обрабатываемой HTML-страницы;
CSS Selector — селектор для выбора интересующего нас элемента. li[data-name^=EGRUL] — элемент li, который содержит атрибут data-name, значение которого начинается с EGRUL;
Output TypeAttribute — данные будут извлечены из атрибута HTML-элемента;
Destinationflowfile-attribute — результат будет помещен в атрибут FlowFile-а (атрибут всегда называется HTMLElement);
Attribute Name — данный параметр описывает, какое значение должно быть получено в результате. abs:${literal('data-href')} — базовый URL + значение атрибута data-href для элемента, найденного CSS-селектором.

Для каждого элемента, найденного CSS-селектором будет создан отдельный FlowFile.

Получение архивов

Для получения архивов с файлами выписок ЕГРЮЛ используется процессор InvokeHTTP. Его настройки аналогичны процессору InvokeHTTP для получения HTML-кода страницы. SSLContextService используется тот же самый. Запрашиваемый URL берется из FlowFile-а из атрибута HTMLElement, т.е. — ссылка на ZIP-архив.

Скриншоты процессора InvokeHTTP

Процессор скачивает ZIP-архив по ссылке из атрибута HTMLElement и помещает его в FlowFile в качестве контента.

Распаковка архивов

Для распаковки архивов используется процессор UnpackContent. В параметрах процессора достаточно выбрать только тип архива — ZIP.

Скриншоты процессора UnpackContent

На выходе процессор создает FlowFile для каждого XML-файла, распакованного из ZIP-архива.

Далее…

Далее каждый XML требуется преобразовать в JSON и разбить его по организациям, т.к. каждый XML содержит от 1 до 1000 выписок ЕГРЮЛ. А из JSON уже в дальнейшем можно будет загрузить данные в SQL или NoSQL хранилище.

О преобразовании XML в JSON и о AVROSchema — в следующей статье.

ссылка на оригинал статьи https://habr.com/ru/post/496900/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *