Что не так с выгрузками
ФТП на ftp.zakupki.gov.ru выглядит просто: регионы, дни, ZIP с XML внутри. На деле всё интереснее. Документация рваная, схемы ссылаются на несуществующие типы, а форматы меняются без предупреждения. Один день тег обязательный, на следующий — уже нет.
В одном архиве спокойно лежат документы разных версий схем. XSD-валидация регулярно падает на реальных данных. ФТП иногда отдаёт пустые файлы или рвёт соединение. Если делать парсер «по книжке» со строгой валидацией — он будет ломаться каждую неделю.
Мой подход: парсер, который прощает
Я сразу решил, что данные будут грязными, а схема — устаревшей. Поэтому парсер должен:
- вытаскивать максимум даже из кривого файла;
- не падать на незнакомых тегах;
- писать в лог расхождения, но не останавливать работу;
- отправлять непонятный документ в очередь, а не терять.
На практике это значит lxml в режиме recover, несколько XPath-вариантов на каждое поле и отдельный слой проверки уже после парсинга.
Как выглядит код
Вот упрощённый пример, как я читаю извещение:
from lxml import etree
from dataclasses import dataclass, field
from typing import Optional
NS = { ... }
@dataclass
class Notice:
purchase_number: str
publish_date: Optional[str] = None
...
def parse_notice(xml_bytes: bytes):
parser = etree.XMLParser(recover=True, huge_tree=True)
root = etree.fromstring(xml_bytes, parser)
# дальше ищу поля по списку XPath от конкретного к общему
Главное — recover=True и список путей для каждого поля. Если завтра переименуют тег, меняю только этот список.
Маппинг версий и очередь повторов
Чтобы не плодить if version, держу маппинг в отдельном словаре или YAML. Новую версию добавляю одной строчкой.
Битые файлы не выбрасываю. Кидаю их в таблицу parse_retry_queue. Воркер пробует заново через экспоненциальную задержку. Часто через день-два выходит обновлённая выгрузка и всё парсится само.
Регресс-тесты каждый день
Самая большая опасность — тихая потеря поля. Поэтому держу набор эталонных XML и раз в сутки прогоняю по ним парсер. Плюс мониторю долю документов с пустыми ключевыми полями. Резкий скачок — сигнал, что появилась новая разновидность XML.
Что в итоге
Такой подход работает у меня уже несколько лет без постоянного ручного вмешательства. Данные приходят чистые, можно строить дашборды и модели. Если и вам нужно собирать закупки — берите идею на вооружение, она реально спасает.
