Для оценки контрагента довольно полезную информацию можно получить с сайта «ЕИС закупки», в частности из реестра недобросовестных поставщиков. Расскажу, как быстро проверить контрагентов, имея список ИНН.
Нахождение контрагента в реестре недобросовестных поставщиков / подрядных организаций вероятнее всего повлияет на решение сотрудничества с ним, так и на формирование резервов под него (например, в банковском кредитовании).
Для быстрой проверки, когда ИНН заемщиков слишком много, был написан код на 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;
}
}
Изначально я хотел в конструкторе написать код по получению информации, но возникли случаи, когда возвращается несколько значений поиска, например, поставщик попадал несколько раз в реестр, так что я отказался от такой идеи.
Поэтому функция по получению информации реализована в отдельном классе, а заодно и метод для того, чтобы записать результат из списка:
В первой части функции идет запрос к сайту и получение html.
-
Далее смотрим на наличие блоков с информацией:
a. если их нет, то идем на шаг 4;
b. если есть, то идем дальше по функции;
-
идем по блокам циклом и заполняем поля класса в соответствие с названием;
a. если ИНН поисковой не соответствует инн в блоке то переходим на следующую итерацию;
b. если соответствует идем дальше, добавляем даты и класс добавляем в список;
возвращаем список.
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();
Таким образом, у меня получилось собрать информацию об интересующих контрагентах. От себя хотелось бы добавить, что сайт имеет особенность: по тем ИНН, где информацию получить не удалось, попробуйте запустить скрипт еще раз: есть шанс, что найдется информация по ним.
Комментарии (3)
balankt
19.05.2022 14:42+3Еще данные по РНП хранятся ftp по адресу: ftp://ftp.zakupki.gov.ru/fcs_fas/unfairSupplier2022 (free / free). Можно оттуда выгружать периодически.
micbal
Где Python?
NewTechAudit Автор
Поправили, спасибо.