Парсинг сайта Госзакупок (ЕИС закупки)

от автора

Для оценки контрагента довольно полезную информацию можно получить с сайта «ЕИС закупки», в частности из реестра недобросовестных поставщиков. Расскажу, как быстро проверить контрагентов, имея список ИНН.

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

Для быстрой проверки, когда ИНН заемщиков слишком много, был написан код на 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. Далее смотрим на наличие блоков с информацией:

    a. если их нет, то идем на шаг 4;

    b. если есть, то идем дальше по функции;

  3. идем по блокам циклом и заполняем поля класса в соответствие с названием;

    a. если ИНН поисковой не соответствует инн в блоке то переходим на следующую итерацию;

    b. если соответствует идем дальше, добавляем даты и класс добавляем в список;

  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;         }     }

Далее используем эту функцию на списке ИНН:

List<Provider> providers = new List<Provider>();             foreach(string inn in INNs)             {                 providers = providers.Concat(Metods.GetProviderFromSite(inn)).ToList();             }             providers.Write();

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


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


Комментарии

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

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