Проверка контрагентов. Парсинг fedresurs

от автора

В этой статье хочу познакомить читателя с таким ресурсом, как «Единый федеральный реестр сведений о фактах деятельности юридических лиц» (fedresurs.ru), рассказать о его применимости и показать возможность прошерстить ресурс не руками по большому количеству клиентов, а с использованием C# (в вашем случае можете использовать любой другой язык, который вам нравится, подходы, думаю, не изменятся) и море проксей, ну разумеется будем парсить. Возможно, тем кто этим займется, пригодятся статья, идеи или, чем черт не шутит, куски кода, а тем, кто просто проводит проверку контрагентов сможет либо понять, что можно взять с сайта либо придумает, что можно еще проверить.

Периодически возникает потребность в получении данных для анализа клиентов/заемщиков/контрагентов и эти данные мы можем получить из этого сайта. Что же нам предлагается?!

Возникновение обременений (залог, лизинг и т.д.) – посмотреть, например, на возможность заключения фиктивных договоров лизинга или на уже заложенное имущество и т.д.

Различные сообщения по клиенту, например, сообщения о банкротстве и уже с ними – проверка, все ли сообщает клиент и может пора пошевелиться в сторону него и предпринять какие-либо меры.

Торги и т.д.

Составляем запрос для получения желаемого

string strQuery;         linq2: switch (inn.Length)             {                 case (10):                     strQuery = "https://fedresurs.ru/backend/companies?limit=15&offset=0&code=" + inn;                     break;                 case (12):                     strQuery = "https://fedresurs.ru/backend/persons?limit=15&offset=0&code=" + inn;                     break;                 case (9):                 case (11):                     inn = 0 + inn;                     goto linq2;                 default:                     return;             }

Определяем по длине строки, с кем имеем дело – с физическим или юридическим лицом (10 символов – юрик, 12 символов – физик) от этого зависит запрос. Бывает, что 0 впереди ИНН куда-то теряется, так что можем поставить проверку, что если 9 или 11 символов, то дописываем 0 впереди. В худшем случае добудем избыточную информацию.

HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(strQuery);             request.UserAgent = "Mozila/4.0 (compatible; MSIE 6.0;Windows NT 5.1; SV1; MyIE2; ";             request.CookieContainer = new CookieContainer();             request.Accept = "image/gif, image/x-xbitmap, image/jpeg,image / pjpeg, application / x - shockwave - flash, application / vnd.ms - excel, application / vnd.ms - powerpoint,  application / msword,";             request.Headers.Add("Accept-Language", "ru");             request.ContentType = "application/json";             request.KeepAlive = true;             request.Timeout = 200000;             request.Referer = "https://fedresurs.ru/search/entity?code=" + inn;             HttpWebResponse response = new HttpWebResponse();     response = (HttpWebResponse)request.GetResponse();

Стоит обратить внимание на Referer – без него, сервер будет отпинывать, сообщая, что страница не найдена.

Берем любой ИНН, например 3327848813 и делаем запрос. Вернется нам json:

{"pageData":[{"guid":"b99c2ded-1a6c-4239-b728-804461ad074b","ogrn":"1103327002393","inn":"3327848813","name":"ООО \"СУЗДАЛЬСКАЯ ПИВОВАРНЯ\"","egrulAddress":"600033, ОБЛАСТЬ ВЛАДИМИРСКАЯ, ГОРОД ВЛАДИМИР, УЛИЦА СУЩЁВСКАЯ, ДОМ 37, ПОМЕЩЕНИЕ 12","status":"Юридическое лицо признано несостоятельным (банкротом) и в отношении него открыто конкурсное производство","statusUpdateDate":"2017-11-28T00:00:00","isActive":true}],"found":1}

При разложении в таблицу выглядит чуть проще:

И вот мы получили guid и еще чуть-чуть информации сверху.

Дальше можем получить список сообщений по данному клиенту и вот запрос:

string strQuery, referer;                     switch (search.inn.Length)                     {                         case (10):                             strQuery = "https://fedresurs.ru/backend/companies/" + search.guid + "/publications?" +                                 "&limit=" + limit +                                 "&offset=" + offset +                                 "&searchCompanyEfrsb=true" +                                 "&searchAmReport=true" +                                 "&searchFirmBankruptMessage=true" +                                 "&searchFirmBankruptMessageWithoutLegalCase=false" +                                 "&searchSfactsMessage=true" +                                 "&searchSroAmMessage=true" +                                 "&searchTradeOrgMessage=true";                             referer = "https://fedresurs.ru/company/b99c2ded-1a6c-4239-b728-804461ad074b" + search.guid;                             break;                         case (12):                             strQuery = "https://fedresurs.ru/backend/persons/" + search.guid + "/publications?" +                                 "limit=" + limit +                                 "&offset=" + offset +                                 "&searchPersonEfrsbMessage=true&searchAmReport=true" +                                 "&searchPersonBankruptMessage=true" +                                 "&searchMessageOnlyWithoutLegalCase=false" +                                 "&searchSfactsMessage=true" +                                 "&searchArbitrManagerMessage=true" +                                 "&searchTradeOrgMessage=true";                             referer = "https://fedresurs.ru/person/b99c2ded-1a6c-4239-b728-804461ad074b" + search.guid;                             break;                         default:                             return pageDatas;                     }

Ничего неожиданного, все так же надо определять юр или физ лицо мы смотрим, подставлять guid, limit-количество сколько выведет сообщений, offset-сколько пропустить сообщений, все так же необходимо указывать Referer.

Делаем запрос и получаем:

{"pageData":[{"guid":"A10151349AE45D484C24D08CF2451AA7","number":"7344583","datePublish":"2021-09-17T12:37:52.11","isAnnuled":false,"isLocked":false,"title":"Объявление о проведении торгов","publisherName":"Потапов Павел  Викторович","type":"BankruptcyMessage","publisherType":"ArbitrManager","bankruptName":"ООО \"СУЗДАЛЬСКАЯ ПИВОВАРНЯ\"","isRefuted":false},….

Часть данных обрезал, чтоб сильно не захламлять текст. И по традиции табличный вид

А теперь перейду к нюансу, куда же без них иначе было бы неинтересно. По какой-то причине сайт готов выдавать только первые 500 сообщений, не более. Чтобы обойти эту данность, можно начать ставить фильтры либо на типы сообщений, либо на промежуток времени, по которому смотрим, либо и то, и другое Все это записывается в запрос.

После составления запроса добавляется

if (useDate)                     {                         endDate = startDate.AddDays(deltDays);                         strQuery += string.Format("&startDate=" + GetDateStr(startDate) + "T00:00:00.000Z&endDate=" + GetDateStr(endDate) + "T00:00:00.000Z");                     }

А после части, где получаем ответ от сайта

if (found > 500 && deltDays > 0)                     {                         if (useDate)                         {                             deltDays /= 2; // меняем кол-во дней если слишком много сообщений                             break;                         }                         else                         {                             useDate = true; // включаем поиск по датам если слишком много сообщений                             break;                         }                     }

После получения ответа смотрим сколько всего сообщений есть и если их больше 500, то начинаем добавлять к запросу фильтр по датам Если в ответе все равно много, то снова уменьшаем период времени и так пока не станет <= 500.

Теперь если просто информации что за сообщение, нам недостаточно, и мы хотим (аналитик хочет, а мы вынуждены) получить больше информации, то как и прежде берем guid, только на этот раз это guid сообщения и таким же образом строим запрос:

HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create("https://fedresurs.ru/backend/sfactmessages/" + guid);             request.UserAgent = "Mozila/4.0 (compatible; MSIE 6.0;Windows NT 5.1; SV1; MyIE2; ";             request.CookieContainer = new CookieContainer();             request.Accept = "image/gif, image/x-xbitmap, image/jpeg,image / pjpeg, application / x - shockwave - flash, application / vnd.ms - excel, application / vnd.ms - powerpoint,  application / msword,";             request.Headers.Add("Accept-Language", "ru");             request.ContentType = "application/json";             request.Referer = "fedresurs.ru";             request.Proxy = ProxyClass.GetProxy();             request.KeepAlive = true;             request.Referer = "https://fedresurs.ru/sfactmessage/" + guid;

Не стану повторяться, но тут есть момент, а именно, что запрос формируется исходя из типа сообщения. Т.е. sfactmessage (существенные факты) в запросе и в Referer соответственно может принять значения, например, bankruptmessage или какой-либо другой, и под это все json и соответственно конечные таблицы становятся разными. Примерное содержание одного из сообщений:

Осталась рассказать про одну неприятную, но вполне ожидаемую вещь: блокировки по ip((((. За одну айпишку можно успеть сделать от 100 запросов, на некоторых проксях дает сделать лишь один и под замену, и ip улетает в блок примерно на час. Для этой части написал класс подстановки проксей.

public static class ProxyClass     {         private static List<WebProxy> Proxys = new List<WebProxy>();// список проксей         private static int NumPr = 0;//используемая сейчас прокси         private static int QuerCnt = 0;//сколько запросов сделано с прокси         private static DateTime lastUseNullProxy=DateTime.Now;//последнее использование без проксли         private static int minutesForNullProxy = 90;// через какое время начинать обход списка с нуля         /// <summary>         /// меняет прокси (в try catch)         /// </summary>         public static void NexProxy()         {             if (NumPr == 0)             {                 lastUseNullProxy = DateTime.Now;// меняет дату              } // если без прокси(0)             if (QuerCnt == 1)             {                 if (NumPr == 0)                  {                 } // если без прокси(0)                 else                 {                     Proxys.Remove(Proxys[NumPr]);                     if (Proxys.Count == 1) { GetFromTxt(); }                     NumPr--;                 }// если с прокси             } //если был всего один запрос             if (NumPr== Proxys.Count-1)              {                  NumPr = 0;             }//             else              {                 NumPr++;             }             if (DateTime.Now.Subtract(lastUseNullProxy).TotalMinutes >= minutesForNullProxy)             {                 NumPr = 0;             }             QuerCnt = 0;         }         /// <summary>         /// возвращает прокси для использования         /// </summary>         /// <returns></returns>         public static WebProxy GetProxy()         {             QuerCnt++;             if (QuerCnt == 2 && NumPr!=0)             {                 Write(append:true);             }             return Proxys[NumPr];         } }

В класс собираются списки проксей, и в коде при запросе идет обращение к данному классу, для получения актуальной прокси, в принципе вся работа этого куска описана в комментах. Основная проблема — найти большое количество нормальных проксей, или чтобы хотя бы половина из них были работающие.

Прикладываю также и ссылку на Git, там можно посмотреть больше кода.


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


Комментарии

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

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