- PVSM.RU - https://www.pvsm.ru -
Уже второй год я занимаюсь государственными открытыми данными РФ и работой с госорганами и пора бы начинать рассказывать интересные истории о том, как появляются данные. Однако сегодня речь пойдет о более привычной для разработчика области — парсинге данных для проекта «Декларатор» и о том, какую неожиданную пользу могут при этом принести открытые данные.
«Декларатор» — это постоянно пополняемая база деклараций о доходах и имуществе публичных должностных лиц: депутатов, чиновников, судей, представителей региональной и муниципальной власти, иных органов, госкорпораций и госкомпанией. Проект работает как информационно-справочная база для СМИ, активистов, занимающихся общественным контролем, и исследователей.
В России сведения о доходах должны публиковать более миллиона человек.
Интересный факт: существуют единые правила для госсайтов по размещению деклараций о доходах (в частности, они всегда находятся в разделе «Противодействие коррупции») и отвечает за всю эту тему Министерство труда и социальной защиты РФ. Массовое размещение деклараций происходит в мае. Далее у Минтруда есть всего месяц на то, чтобы провести мониторинг по всем без исключения сайтам, обязанным размещать информацию. Мониторинг проводится вручную.
Есть несколько проблем, связанных с публикацией деклараций:
Интересующиеся могут прочитать подробности в приказе Минтруда 530н [2], а если кратко: раздел «Противодействие коррупции» должен находиться в одном клике от главной страницы и содержать несколько обязательных подразделов с жестко заданными названиями, среди которых нас интересует один – «Сведения о доходах, расходах, об имуществе и обязательствах имущественного характера». Именно в нем, без ограничения доступа, в табличной форме, в том числе в форматах .doc, .docx, .excel, .rtf (п.15 Требований), размещаются декларации о доходах госчиновников.
При этом, как прямо указано в документе, «должна быть обеспечена возможность поиска по тексту файла и копирования фрагментов текста» — вот это и делает возможным создание парсеров.
Декларация о доходах каждого чиновника содержит информацию об объектах недвижимости, находящихся в собственности, в пользовании, сведения о транспортных средствах, сведения о доходах и источниках доходов. В декларации перечислены не только чиновники, но и члены их семей. Если повезет, сводный файл создается по предложенному Минтрудом шаблону формы сведений о доходах [3], что сильно облегчает задачи написания универсального парсера.
Первым объектом интереса стало Министерство образования и науки. Пробный парсер [4], для деклараций о доходах федеральных государственных служащих за 2014 год [5] на 306 человек, был написан быстро и достаточно безболезненно. После этого мы решили перейти к тому, что обычно вызывает наибольшее количество запросов исследователей – сведениям о доходах ректоров вузов. И тут-то начались сложности с декларациями за 2014 год подведомственных учреждений Минобрнауки [6].
Быстрый анализ показал, что только ректоров в этом файле 272 человека и их явно надо как-то группировать. Группировать решили по регионам. Однако в декларации указывается лишь должность и название учреждения.
Почти три сотни уникальных высших учебных заведений разыскивать руками совсем не хотелось. Вот здесь и пригодились открытые данные Рособрнадзора под названием «Сводный реестр лицензий на осуществление образовательной деятельности» [7]. Реестр очень информативный, но имеет достаточно сложный формат и заслуживает отдельной статьи. К чести Рособрнадзора, он представлен в формате xml вместо традиционного для госорганов csv, и не содержит ошибок в структуре, поэтому его удалось использовать в качестве базы данных без какой-либо предварительной обработки. (ссылка по состоянию на 16.05.2016 временно не работает, поэтому реестр пока можно взять здесь [8]).
Итак, исходная задача: вытащить из декларации о доходах данные по ректорам, определить для них регион и сгенерировать файлы xml специального формата [9] для плагина Заполнятор, через который происходит загрузка данных на сайт Декларатора.
Плагин имитирует действия пользователя на сайте, автоматически заполняя формы. И как выяснилось в процессе тестирования, у него есть ограничения на количество записей, которые он способен обработать за один раз…
На входе имеем файл формата .doc [6], содержащий в себе данные о доходах 1561 чиновников. Так как нам нужны данные не только по чиновникам, но и по членам их семей, по факту мы должны обработать информацию по 3347 людям.
Детали реализации парсера деклараций смотрите на гитхабе [4], скажу только, что понадобилось много предварительной обработки для удаления лишних и зачастую неожиданных символов: @"[rnabu000b]", а также шаманство с транспортными средствами, до сих пор не законченное из-за таких вот случаев (это одна ячейка таблицы в MS Word):
Переходим к основной задаче – матчингу названий вузов деклараций и реестра Рособрнадзора. Ее решение с подбором регулярных выражений в результате заняло значительно больше времени, чем написание самого парсера. Хотя кода там получилось намного меньше.
Записи для каждой лицензии в реестре Рособрнадзора имеют (в очень сокращенном виде) такую структуру:
<Certificate>
<RegionName>г. Москва</RegionName>
<RegionCode>77</RegionCode>
<EduOrgFullName>федеральное государственное бюджетное образовательное учреждение высшего профессионального образования «Московский государственный университет дизайна и технологии»</EduOrgFullName>
<EduOrgShortName>ФГБОУ ВПО «МГУДТ»</EduOrgShortName>
<ActualEducationOrganization>
<Id>58302c2c-16f2-0772-3cf1-ebacbde89ecd</Id>
<FullName>федеральное государственное бюджетное образовательное учреждение высшего профессионального образования «Московский государственный университет дизайна и технологии»</FullName>
<ShortName>ФГБОУ ВПО «МГУДТ»</ShortName>
<RegionName>г. Москва</RegionName>
<RegionCode>77</RegionCode>
</ActualEducationOrganization>
<ActualEducationOrganization>
…
</ActualEducationOrganization>
</Certificate>
EduOrgFullName — это сведения о самой лицензии, для головной организации. В тегах ActualEducationOrganization содержится информация обо всех учреждениях, подчиненных головной организации (а их может быть очень много — институты в составе университета, филиалы и многое другое). Поэтому решение выглядело просто и очевидно: найти соответствия названий из деклараций для тега FullName или ShortName реестра и выяснить, какой регион им соответствует.
Особенности реестра: в качестве кавычек используются исключительно «елки», наименование типа учреждения («федеральное государственное…») в теге FullName записывается полностью в нижнем регистре.
Однако, по-видимому, формат написания названий вузов в декларациях был ограничен лишь фантазией тех, кто подавал декларации. В итоге имеем разнообразие регистров и написаний, от Федеральное государственное бюджетное учреждение высшего образования «Московский государственный университет технологий и управления имени К.Г. Разумовского (ПКУ)» и ФГАОУ ВПО «Национальный исследовательский ядерный университет „МИФИ“ до ФГАОУ „ВПО БФУ ИМ.И.КАНТА“ (причем в другом месте декларации он был записан уже как ФГАОУ ВПО „Балтийский федеральный университет имени Иммануила Канта“). Свой вуз я долго не могла найти парсером. Неудивительно для ФГБОУ ВПО „МГУДТ“…
Большое разнообразие наблюдалось в написании кавычек. В основном в декларациях записаны прямые «английские» кавычки вместо привычных русских елочек, самый убийственный вариант для парсинга был »Санкт-Петербургский государственный электротехнический университет «ЛЭТИ» им. В.И. Ульянова (Ленина)" (похоже, его не осилил и парсер хабра). Дважды встретились экзотические «“”» (Волгоград, Москва), а в Ростове додумались до варианта ФГБОУ ВПО <<Ростовский государственный экономический университет (РИНХ)>> (между прочим, 10 вхождений в декларации).
Так вот, оказалось, что XPath в xml ищет очень быстро, умеет находить частичные соответствия, но увы – только в полном соответствии с регистром букв. Если переопределить функцию поиска, проблема исчезает, и с ней заодно исчезает и скорость.
Первым делом пришлось убрать повторяющуюся часть — тип учреждения — и оставить только фактическое название. И здесь ждало открытие: помимо ФГБОУ (а также ФГАОУ, ФГБУ) ВПО, ДПО ли ВО оказалось, что есть еще учреждения «инклюзивного высшего образования», то есть ФГБОУИ ВО… А стандартная формулировка «федеральное государственное бюджетное образовательное учреждение высшего профессионального образования» может заменяться на «федеральное государственное бюджетное учреждение высшего профессионального образования» — сможете найти отличие?
В итоге получилась вот такая конструкция на регулярных выражениях:
orgname = Regex.Replace(orgname, @"(.*)(ФГ(Б|А)ОУs)((В|Д)П?О)?", "");
orgname = Regex.Replace(orgname,
@"(федеральн[а-яё]*s|Федеральн[а-яё]*s)?(государственн[а-яё]*s|Государственн[а-яё]*s)?(.*)?(учрежден[а-яё]*s|Учрежден[а-яё]*s)(инклюзивн[а-яё]*s|инклюзивн[а-яё]*s)?(дополнит[а-яё]*s|Дополнит[а-яё]*s|высше[а-яё]*s|Высше[а-яё]*s)(профессиональн[а-яё]*s|Профессиональн[а-яё]*s)?(образован[а-яё]*|Образован[а-яё]*)", "");
orgname = Regex.Replace(orgname, @"(федеральн[а-яё]*s|Федеральн[а-яё]*s)?(государственн[а-яё]*s|Государственн[а-яё]*s)?(.*)?(учрежден[а-яё]*s|Учрежден[а-яё]*s)", "");
Причем порядок команд здесь имеет большое значение. Ну и борьба с кавычками:
if (orgname.Contains("<<"))
orgname = Regex.Replace(orgname, @"(.*<<)(.+)(>>.*)", "$2");
if (orgname.Contains('«'))
orgname = Regex.Replace(orgname, @"(.*«)(.+)(».*)", "$2");
if (orgname.Contains('“'))
orgname = Regex.Replace(orgname, @"(.*“)(.+)(”.*)", "$2");
Большая проблема оказалась с вузами, которые были названы в чью-то честь, так как:
Из-за непредсказуемости написания было проще убрать «имени кого» целиком:
orgname = Regex.Replace(orgname, "(имени.*)", "");
orgname = Regex.Replace(orgname, @"(им..*)", "");
К счастью, название вуза при этом не теряло в уникальности.
И все равно оставались «упрямые» случаи, которые не хотели находиться никаким образом. Это были вузы, названия которых состояли из аббревиатур: ЛЭТИ, НИНХ, СТАНКИН и снова мой любимый МГУДТ. Решение:
Match tempmatch = Regex.Match(orgname, @"[А-ЯЁ]{2,}");
tempname = orgname.Substring(tempmatch.Index, tempmatch.Length);
Как ни странно, даже после этого в неопознанные попало несколько десятков вузов. Анализ показал, что часть их них были написаны с опечатками, в основном из-за пропуска или перестановки букв. Лидером стала опечатка «Москвоский». А в Кузбассе, судя по капсу, очень любят свой вуз, но вот грамотность у них подкачала: «Федеральное государственное бюджетное образовательное учереждение высшего профессионального образования КУЗБАССКИЙ ГОСУДАРСТВЕННЫЙ ТЕХНИЧЕСКИЙ УНИВЕРСИТЕТ ИМЕНИ Т.Ф. ГОРБАЧЕВА».
Много проблем было с пробелами:
Но количество неопознанных вузов почему-то не спешило сокращаться. И дело было в совсем неожиданной проблеме, которая в итоге привела к модификации алгоритма поиска. Оказалось, что лицензия на образовательную деятельность могла быть зарегистрирована на одно название учреждения, а официальное название вуза чуть-чуть, но отличалось. Например, были пары «академия – университет», «институт – университет».
В реестре это выглядело так:
<EduOrgFullName>федеральное государственное бюджетное образовательное учреждение высшего профессионального образования «Брянская государственная инженерно-технологическая академия»</EduOrgFullName>
<EduOrgShortName>ФГБОУ ВПО «БГИТА»</EduOrgShortName>)
и
<FullName>федеральное государственное бюджетное образовательное учреждение высшего образования «Брянский государственный инженерно-технологический университет»</FullName>
<ShortName>ФГБОУ ВО «Брянский государственный инженерно-технологический университет», ФГБОУ ВО «БГИТУ», БГИТУ</ShortName>
Причем в декларации могло быть указано любое из них. Несколько вузов по не известной пока причине вообще не имели тегов FullName и ShortName.
Отдельно про Крым: »федеральное государственное автономное образовательное учреждение высшего образования «Крымский федеральный университет имени В.И. Вернадского» вообще не имело в реестре указания на регион.
Окончательная на данный момент версия алгоритма парсинга [4] выдает вот такие результаты [10].
Пример готового файла для Заполнятора [11] (вузы для г.Москва).
В декларации подведов Минобрнауки 1561 работников организаций, вместе с членами семей их 3347 человек, в файле 770 страниц, неожиданно 32 таблицы.
272 ректора, т.е. более 272 уникальных вузов, из них 8 вузов написаны с ошибками или опечатками.
4 вуза вообще не значатся в реестре Рособрнадзора. Это:
В заключение еще раз ссылка на проект [4]. Парсер будет работать и на декларациях других госорганов, созданных по тому же шаблону.
НПА:
Указ Президента Российской Федерации от 8 июля 2013 г. № 613 «Вопросы противодействия коррупции» [1], ст. 6 про обязанности Министерства труда и социальной защиты.
Указ Президента Российской Федерации от 8 июля 2013 г. № 613 «Вопросы противодействия коррупции» [1], Порядок размещения сведений о доходах, расходах, об имуществе и обязательствах имущественного характера отдельных категорий лиц и членов их семей на официальных сайтах федеральных государственных органов, органов государственной власти субъектов Российской Федерации и организаций и предоставления этих сведений общероссийским средствам массовой информации для опубликования про обязанности Министерства труда и социальной защиты, п. 4 «Сведения о доходах, расходах, об имуществе и обязательствах имущественного характера … ежегодно обновляются в течение 14 рабочих дней со дня истечения срока, установленного для их подачи».
Указ Президента Российской Федерации от 8 июля 2013 г. № 613 «Вопросы противодействия коррупции» [1], Статья 8. Обязанность представлять сведения о доходах, об имуществе и обязательствах имущественного характера.
Все НПА по антикоррупционному законодательству [12].
НПА Минтруда [13]
Программирование:
Сервис проверки регулярных выражений [14]
Хелп по регулярным выражениям в C# [15]
Классы знаков регулярных выражений для C# [16], а также проект с простой реализацией безрегистрового поиска по xml: ссылка [17].
Автор: nike32
Источник [18]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/programmirovanie/121363
Ссылки в тексте:
[1] Указом Президента Российской Федерации от 8 июля 2013 г. № 613 «Вопросы противодействия коррупции»: http://goo.gl/Ikr9Xk
[2] приказе Минтруда 530н: http://www.rosmintrud.ru/docs/mintrud/orders/157/
[3] шаблону формы сведений о доходах: http://www.rosmintrud.ru/docs/mintrud/orders/157/Prilozhenie_1.doc
[4] парсер: https://github.com/Shorstko/DeclaratorParser
[5] деклараций о доходах федеральных государственных служащих за 2014 год: http://минобрнауки.рф/media/events/files/41d56010ef2047959b2c.doc
[6] декларациями за 2014 год подведомственных учреждений Минобрнауки: http://минобрнауки.рф/media/events/files/41d56010e2e950409427.doc
[7] «Сводный реестр лицензий на осуществление образовательной деятельности»: http://www.obrnadzor.gov.ru/opendata/7701537808-FBDRL/
[8] здесь: https://goo.gl/vSudq9
[9] специального формата: https://goo.gl/xZO54G
[10] результаты: https://goo.gl/EIUw3z
[11] файла для Заполнятора: https://goo.gl/Xk56n2
[12] антикоррупционному законодательству: http://fsin.su/anticorrup2014/document/zakonodatelstvo/
[13] НПА Минтруда: http://www.rosmintrud.ru/ministry/anticorruption/legislation/1
[14] Сервис проверки регулярных выражений: http://planetcalc.ru/708/
[15] Хелп по регулярным выражениям в C#: http://professorweb.ru/my/csharp/charp_theory/level4/4_10.php
[16] Классы знаков регулярных выражений для C#: https://msdn.microsoft.com/ru-ru/library/20bw873z%28v=vs.110%29.aspx
[17] ссылка: http://www.codeproject.com/Articles/15372/Custom-XPath-Functions
[18] Источник: https://habrahabr.ru/post/301436/?utm_source=habrahabr&utm_medium=rss&utm_campaign=sandbox
Нажмите здесь для печати.