SOAP, XML и Python: получаем данные с zakupki.gov.ru
Эта статья написана для начинающих пользователей, которые хотят разобраться в работе сервиса отдачи информации zakupki.gov.ru. Мы шаг за шагом разберем, как получить токен для физического лица, как выглядит XML-документ для запроса и как написать простую программу на Python для взаимодействия с сервисом. Это не руководство от профессионала, а скорее дневник выживания: как не сойти с ума, пока пытаешься подружиться с сервисом zakupki.gov.ru
С 1 января 2025 года доступ к FTP-серверу zakupki.gov.ru будет закрыт, и вся информация станет доступна только через сервисы отдачи данных. До этой даты физические лица могут получать общедоступную информацию через сервис https://int44.zakupki.gov.ru/eis-integration/services/getDocsLE2 без необходимости использовать токены или электронную цифровую подпись (ЭЦП). Однако с нового года работа с сервисом потребует токенов или настройки инфраструктуры для подписания запросов ЭЦП.
Открытые данные закупок — это мощный инструмент для анализа, прозрачности государственного управления и создания полезных сервисов, как коммерческих, так и общественных. Например, на их основе можно анализировать расходы государства, выявлять нарушения или автоматизировать поиск тендеров. Ранее доступ был через FTP-сервер, сейчас данную возможность закрывают, а вместо него предлагается получать данные по протоколу SOAP. У меня нет технического образования и складывается такое ощущение, что государство хочет таким ненавязчивым способом восполнить пробелы в моих знаниях.
SOAP (Simple Object Access Protocol) — это протокол обмена данными, при котором запросы и ответы представляют собой строго структурированные XML-документы. Для многих разработчиков (включая меня) это может быть первое знакомство с этим протоколом. Более того, практическая информация по работе с SOAP и конкретно с сервисом закупок zakupki.gov.ru представлена в сети крайне ограниченно.
Структура статьи:
Получение токена для работы с сервисом
Структура xml-документа
Пример программы на python
Получение токена для работы с сервисом
Получить токен можно следуя инструкции «ИНСТРУКЦИЯ ПО ИСПОЛЬЗОВАНИЮ СЕРВИСОВ ОТДАЧИ ИНФОРМАЦИИ ЕИС ДЛЯ ЮРИДИЧЕСКИХ И ФИЗИЧЕСКИХ ЛИЦ», размещенном на zakupki.gov.ru. Но для того, чтобы не открывать лишних окон, вкратце опишу процесс здесь:
Нужно перейти по адресу: https://zakupki.gov.ru/pmd/auth/welcome (естественно через поддерживаемый браузер).
Проходим авторизацию через Госуслуги, выбираем «Регистрация нового потребителя машиночитаемых данных», далее «Физическое лицо, индивидуальный предприниматель», заполняем все сведения, отправляем запрос и происходит перенаправление на новую страницу с токеном.
Готово! Сохраняем токен в надежное место
Пример токена: 5d035886–82af-4f98–8a74–278bf72ff457 (был указан в инструкции, не работающий)
Структура xml-документа
Формирование правильного XML-документа — одна из главных сложностей при работе с сервисом. Любая ошибка, например, нарушение порядка тегов или отсутствие обязательного параметра, может привести к некорректному ответу сервера. Сервер либо возвращает сообщение об ошибке («Ошибка валидации полученного запроса по интеграционной схеме»), либо повторяет отправленный запрос без обработки.
Основные требования к XML-документам
Порядок тегов имеет значение. Это может быть неочевидно для начинающих, но даже малейшее отклонение от порядка, описанного в интеграционной схеме, вызовет ошибку.
Каждый запрос должен содержать токен. Его необходимо указывать в элементе
внутри
.Использование метода. Название метода запроса указывается в
внутри
.Обязательные параметры для каждого метода. Список обязательных параметров для каждого метода можно найти в интеграционной схеме https://int44.zakupki.gov.ru/eis-integration/services/getDocsIP? xsd=getDocsIP-ws-api.xsd
Создание идеального XML — это как готовить торт: ингредиенты строго по списку, порядок добавления важен, а итоговая структура должна быть идеальной
Поддерживаемые методы:
getDocsByReestrNumberRequest — запрос формирования в ХД архивов с документами по реестровому номеру
getDocsByOrgRegionRequest — запрос формирования в ХД архивов с документами по региону заказчика и типу документа;
getDocSignaturesByUrlRequest — запрос формирования в ХД архивов с подписями документов;
getNsiRequest — запрос в хранилище документов (ХД) данных справочника
Далее я приведу пример работающего шаблона xml документа. Все взаимодействие с сервисом происходит через url https://int44.zakupki.gov.ru/eis-integration/services/getDocsIP. Для работы с этим сервисом каждый xml файл в soapenv: Header должен содержать элемент individualPerson_token со значение вашего токена. Пример:
5d035886-82af-4f98-8a74-278bf72ff457
В основной части направляется название метода и структурные элементы, которые ему соответствуют. Для каждого запроса должен быть index, в котором есть id, дата создания и режим работы сервиса (TEST или PROD, но лучше сразу PROD указывать). Пример:
3f227a50-418d-47ea-a3f7-e9a85f3af6e7
2024-12-25T16:34:29
PROD
И затем в selectionParams надо указать параметры отбора файлов.
Если мы используем getDocsByReestrNumberRequest, то надо указать тип подсистемы и реестровый номер. Пример:
PRIZ
0888200000224000038
В целом файл для метода getDocsByOrgRegionRequest будет выглядеть следующим образом:
5d035886-82af-4f98-8a74-278bf72ff457
3f227a50-418d-47ea-a3f7-e9a85f3af6e7
2024-12-25T16:34:29
PROD
PRIZ
0888200000224000038
Для каждого метода существуют свои обязательные поля. Подробнее посмотреть обязательные параметры можно тут: https://int44.zakupki.gov.ru/eis-integration/services/getDocsIP? xsd=getDocsIP-ws-api.xsd. Порядок параметров важен!
Например, для метода getDocsByOrgRegionRequest я перепутал порядок и сначала у меня стоял subsystemType, а затем orgRegion и сервер выдавал ошибку несоответствия запросу интеграционной схеме. Пример правильного xml файла для этого метода:
5d035886-82af-4f98-8a74-278bf72ff457
3f227a50-418d-47ea-a3f7-e9a85f3af6e8
2024-12-25T16:38:45
PROD
72
PRIZ
epNotificationEF2020
2024-12-24
Пример программы на Python
Для отправки запроса и получения результата мы будем использовать python.
Для начала импортируем библиотеки, которые пригодятся в будущем:
import uuid
import datetime
import os
import requests
import xmltodict
Для автоматизированной отправки запросов для метода , сформируем шаблон xml файла, в котором будут автоматически из кода подставляться токен, ID и время запроса и назовем его test.xml:
{{ token }}
{{ UUID }}
{{ created_time }}
PROD
PRIZ
0888200000224000038
Теперь нам надо получить заполненный шаблон:
file_path = 'test.xml' # расположение файла-шаблона
token = '5d035886-82af-4f98-8a74-278bf72ff457' # вставьте сюда ваше токен
with open(file_path, 'r', encoding='utf-8') as file:
xml_content = file.read()
generated_uuid = str(uuid.uuid4()) # уникальный id для запроса
generated_datetime = datetime.datetime.strftime(datetime.datetime.now(), '%Y-%m-%dT%H:%M:%S') # текущая дата
xml_data = xml_content.replace("{{ UUID }}", generated_uuid).replace("{{ created_time }}", generated_datetime).replace("{{ token }}", token) # заполнение шаблона
Далее нам остается только отправить данные на сервер:
url = 'https://int44.zakupki.gov.ru/eis-integration/services/getDocsIP'
headers = {
'Content-Type': 'text/xml; charset=utf-8',
}
response = requests.post(url, data=xml_data, headers=headers, timeout=30)
В ответ мы получаем xml файл, в котором есть ссылка на архив. Пример ответа:
8e5e2386-c1e9-499c-88e8-f23313667472
e4858318-62c6-41c0-99a5-879cdc103b39
2024-12-25T14:42:25.180
PROD
ССЫЛКА
Для парсинга xml воспользуемся библиотекой xmltodict и получим url архива:
response_content = xmltodict.parse(response.content)
url_archive = response_content['soap:Envelope']['soap:Body']['ns2:getDocsByOrgRegionResponse']['dataInfo']['archiveUrl']
Далее не совсем очевидный момент, который не отражен в инструкции. Для скачивания архива, нам также потребуется отправлять токен. Я долго не мог понять, почему архив так долго готовится и его нельзя скачать, пока не заметил, что в примере в инструкции в headers отправляется токен:
подчеркивание — это моя работа :)
В самой инструкции об этом не слова и на мой взгляд это большое упущение. На python данный запрос будет выглядеть так:
headers = {
'individualPerson_token': token
}
response_get_archive = requests.get(url_archive, headers=headers, timeout=120)
И далее нам остается только сохранить архив:
with open('archive.zip', 'wb') as f:
f.write(response_get_archive.content)
Полный код программы:
import uuid
import datetime
import os
import requests
import xmltodict
file_path = 'test.xml'
token = '5d035886-82af-4f98-8a74-278bf72ff457' # вставьте сюда ваше токен
with open(file_path, 'r', encoding='utf-8') as file:
xml_content = file.read()
generated_uuid = str(uuid.uuid4())
generated_datetime = datetime.datetime.strftime(datetime.datetime.now(), '%Y-%m-%dT%H:%M:%S')
xml_data = xml_content.replace("{{ UUID }}", generated_uuid).replace("{{ created_time }}", generated_datetime).replace("{{ token }}", token)
url = 'https://int44.zakupki.gov.ru/eis-integration/services/getDocsIP'
headers = {
'Content-Type': 'text/xml; charset=utf-8',
}
response = requests.post(url, data=xml_data, headers=headers, timeout=30)
response_content = xmltodict.parse(response.content)
url_archive = response_content['soap:Envelope']['soap:Body']['ns2:getDocsByOrgRegionResponse']['dataInfo']['archiveUrl']
headers = {
'individualPerson_token': token
}
response_get_archive = requests.get(url_archive, headers=headers, timeout=120)
with open('archive.zip', 'wb') as f:
f.write(response_get_archive.content)
Надеюсь данная статья послужит толчком для изучения протокола работы с SOAP и поможет разобраться с сервисом отдачи информации и документов zakupki.gov.ru
Habrahabr.ru прочитано 1685 раз