Время прочтения: 4 мин.

Нахождение контрагента на сайте ЕИС закупки в реестре недобросовестных поставщиков / подрядных организаций вероятнее всего повлияет на решение сотрудничества с ним, так и на формирование резервов под него (например, в банковском кредитовании).

Для быстрой проверки, когда ИНН заемщиков слишком много, был написан код на c# для удобного поиска по этому списку:

Сначала из перечня ИНН формирую list:

List<string> INNs = new List<string>();
            using(StreamReader sr=new StreamReader(path/to/file))
            {
                string line;
                while ((line = sr.ReadLine()) != null)
                {
                    INNs.Add(line.Trim());
                }
            }

Информация, которую можно получить из реестра:

Дальше создаю класс поставщика с той информацией, которую можно собрать. Применю методы для возврата названий и значений полей.

public class Provider
    {
        public string INN { get; set; }
        public string Name { get; set; }
        public DateTime? DateAdd { get; set; } = null;
        public DateTime? DateUpdate { get; set; } = null;
        public DateTime? DateEnd { get; set; } = null;
        public string FZ { get; set; }
        public string SomethingNum { get; set; }
        public string Country { get; set; }
        public string Url { get; set; }
        public Provider() { }
        
        public string GetTitle()
        {
            return "inn\tName\tDateAdd\tDateUpdate\tDateEnd\tFZ\tSomethingNum";
        }
        public string GetStr()
        {
            return this.INN + "\t" + this.Name + "\t" + this.DateAdd + "\t" + this.DateUpdate + "\t" + this.DateEnd + "\t" + this.FZ + "\t" + this.SomethingNum;
        }
    } 

Изначально я хотел в конструкторе написать код по получению информации, но возникли случаи, когда возвращается несколько значений поиска, например, поставщик попадал несколько раз в реестр, так что я отказался от такой идеи.

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

  1. В первой части функции идет запрос к сайту и получение html
  2. Далее смотрю на наличие блоков с информацией:
    • если их нет, то идем на шаг 4;
    • если есть, то идем дальше по функции;
  3. Иду по блокам циклом и заполняем поля класса в соответствие с названием;
    • если ИНН поисковой не соответствует ИНН в блоке, то необходимо перейти на следующую итерацию;
    • если соответствует, то иду дальше, добавляю даты и класс в список;
  4. Возвращение списка
    public static class Metods
    {
        public static void Write(this List<Provider> providers)
        {
            using (StreamWriter sw = new StreamWriter("res.txt"))
            {
                sw.WriteLine(new Provider().GetTitle());
                foreach (Provider provider in providers)
                {
                    sw.WriteLine(provider.GetStr());
                }
            }
        }
        public static List<Provider> GetProviderFromSite(string inn)
        {
            List<Provider> providers = new List<Provider>();
            HttpWebRequest Request = (HttpWebRequest)HttpWebRequest.Create(String.Format("https://zakupki.gov.ru/epz/dishonestsupplier/search/results.html?morphology=on&sortBy=UPDATE_DATE&pageNumber=1&sortDirection=false&recordsPerPage=_10&showLotsInfoHidden=false&fz94=on&fz223=on&ppRf615=on&customerINN={0}", inn));
            Request.UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36";
            Request.Headers.Add("Accept-Language", "ru-RU,ru;q=0.8,en-US;q=0.5,en;q=0.3");
            Request.Headers.Add("TE", "Trailers");
            Request.Headers.Add("Cache-Control", "no-cache");
            Request.Headers.Add("Pragma", "no-cache");
            Request.Headers.Add("Accept-Encoding", "gzip, deflate, br");
            Request.Headers.Add("TE", "Trailers");
            Request.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8";
            Request.AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip;
            HttpWebResponse Response = (HttpWebResponse)Request.GetResponse();
            HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument();
            doc.Load(Response.GetResponseStream(), Encoding.UTF8);
            HtmlNodeCollection divs = doc.DocumentNode.SelectNodes("//div[@class='row no-gutters registry-entry__form mr-0']");/*[0].SelectNodes(".//a[@class='bloko-link']");*/
            if (divs == null) return providers;
            foreach (HtmlNode div in divs)
            {
                Provider provider = new Provider();
                HtmlNodeCollection blocks = divs[0].SelectNodes("//div[@class='registry-entry__body-block']");
                foreach (HtmlNode htmlNode in blocks)
                {
                    List<HtmlNode> childDiv = htmlNode.ChildNodes.Where(r => r.Name == "div").ToList();
                    switch (childDiv[0].InnerText.Trim().Replace("\n", ""))
                    {
                        case "ИНН (аналог ИНН)":
                            provider.INN = childDiv[1].InnerText;
                            continue;
                        case "Страна":
                            provider.Country = childDiv[1].InnerText;
                            continue;
                        case "Наименование (ФИО) недобросовестной подрядной организации":
                        case "Наименование (ФИО) недобросовестного поставщика":
                            provider.Name = childDiv[1].InnerText.Replace("\n", "").Replace("\t", "").Replace("\r", "").Replace("   ", "");
                            continue;
                        default:
                            string a = childDiv[0].InnerText.Trim().Replace("\n", "");
                            continue;
                    }
                }

                if (inn != provider.INN)
                {
                    continue;
                }
                provider.SomethingNum = divs[0].SelectNodes(".//div[@class='registry-entry__header-mid__number']")[0].InnerText.Trim();
                provider.Url = divs[0].SelectNodes(".//div[@class='registry-entry__header-mid__number']")[0].SelectNodes(".//a")[0].Attributes["href"].Value;
                provider.FZ = divs[0].SelectNodes(".//div[@class='registry-entry__header-top__title text-truncate']")[0].InnerText.Replace("\n", "").Replace("\t", "").Replace("\r", "").Trim();

                HtmlNode DataBlock = divs[0].SelectNodes(".//div[@class='col d-flex flex-column registry-entry__right-block b-left ']")[0];
                HtmlNodeCollection DataBlocks = DataBlock.SelectNodes(".//div[@class='data-block__value']");
                if (DataBlocks.Count < 4)
                {
                    List<DateTime> dates = new List<DateTime>();
                    foreach (HtmlNode htmlNode in DataBlocks)
                    {
                        if (htmlNode.ParentNode.Attributes["class"].Value == "col-6") dates.Add(Convert.ToDateTime(htmlNode.InnerText));
                    }
                    dates = dates.OrderBy(r => r).ToList();
                    provider.DateAdd = dates[0];
                    provider.DateUpdate = dates[1];
                    HtmlNode end = DataBlocks.Where(r => r.ParentNode.Attributes["class"].Value != "col-6").FirstOrDefault();
                    if (end != null) { provider.DateEnd = Convert.ToDateTime(end.InnerText); }
                }
                else
                {
                    string a = "";
                };
                providers.Add(provider);
            }
            return providers;
        }
    }

Таким образом, у меня получилось собрать информацию об интересующих контрагентах. От себя хотелось бы добавить, что сайт имеет особенность: по тем ИНН, где информацию получить не удалось, попробуйте запустить скрипт еще раз: есть шанс, что найдется информация по ним.