Подача авто-запросов на сайте ФНС в ЕГРЮЛ на python

На сайте ФНС по адресу egrul.nalog.ru/index.html есть замечательный сервис проверки контрагентов или своих собственных обществ.

Суть проверки сводится к подаче запроса в ЕГРЮЛ (единый реестр фактов детальности юридических лиц) и получении тут же, онлайн, выписки из реестра.

Работа с сервисом не вызывает каких-либо затруднений: внес в поле ОГРН, нажал кнопку “Найти” и нажал кнопку “Скачать” ниже. Все, выписка получена.

Как здесь может помочь автоматизация? Очень просто.

Если ваш холдинг состоит из n-количества юридических лиц, то даже такая работа как копипастинг ОГРН в строку поиска сервиса может надоесть.

Избавимся от рутины и автоматизируем процесс подачи-скачивания выписок из ЕГРЮЛ!

В нашем случае программа будет “забирать” по одному ОГРН из заранее подготовленной таблицы excel, вносить значение в строку сервиса, нажимать необходимые кнопки.

В идеале работа программы будет выглядеть так:


Приступим.

Для начала подготовим таблицу excel, куда внесем ОГРН, по которым мы будем работать, в столбик:



Количество ОГРН не имеет значения (можно хоть весь ЕГРЮЛ скачать), главное чтобы они все были в столбце А.

Назовем файл выпискиЕГРЮЛ.xlsx и сохраним в рабочей директории python.

Теперь создадим сам файл с программой – egrul.py.

Первые строки программы, как обычно, начинаются с импорта необходимых модулей, далее мы выбираем браузер (в моем случае Chrome) и “заходим” на сайт:



Далее мы запускаем цикл по всем ОГРН в таблице excel:



Здесь надо обратить внимание на значения x вначале цикла:



2- это начальная ячейка с ОГРН (стартовая), которая соответствует A2 в excel таблице. Конечная ячейка будет A9, хотя в цикле указана цифра 10.

Это надо иметь ввиду, чтобы все ОГРН были обработаны и последнее значение не потерялось.
Между подачами запросов в ЕГРЮЛ программа выдерживает паузу в 30 секунд. Это может показаться недопустимо долго и этот период захочется сократить. Это можно сделать, поменяв значение в строке time.sleep(30) на, например, time.sleep(10). Однако в данном случае можно попасть под санкции сервиса ФНС и получить капчу. Данную капчу можно обойти, но это тема отдельного поста. А в этой программе лучше оставить задержку между подачами запросов в 30 секунд и пойти спокойно пить чай, пока программа за вас работает.

Ссылка на программу – здесь.

Ссылка на тестовую таблицу excel – здесь.
Share post

Similar posts

Comments 23

    +3
    ох, реализация «с лазерной пушки, которая вращается на орбите планеты Земля, по воробьям»

    В ответе приходит хеш-строка URI, по которому есть результаты поиска в виде JSON.
    Заголовок спойлера
    В редакторе есть тег code, для выкладок кода.
    Вместо Excel, куда удобнее и проще использовать csv, который нативными модулями парсится
      +1
      Не оставляйте, пожалуйста пробелов перед скобками (при вызове функций).
      Всегда оставляйте, пожалуйста пробелы вокруг знака равно.
      Pep8 вам в помощь — habr.com/ru/post/251531
      если бы код был на github то нашлись бы люди, которые это поправили. А как исправить код на картинке или выложенный в частное облако?
        0
        Воот матёрые програмисты подтянулись. PEP8 и прочее. Ребят, просто порадуйтесь за человека. Хочу сказать что иногда не обязательно быть прям хардкор-программистом чтобы просто радоваться плюсам автоматизации.
        У меня случилась недавно такая история на работе — мы собираем досье на медизделие и в нём соответствующая нормативная документация на сырьё. На всё на это порядка 10 однотипных докуметов. Я за полчаса написал скрипт и сгенерировал более 2500 файлов съэкономив тем самым кучу времени и нервных клеток, себе и коллегам.
        Я не программист (я химик), но иногда мне нравиться поступать разумно (пусть даже и с пушкой по пернатым).
        Автору удачи!!!
          0
          согласен, как раз искал подобное решение, а про webdriver впервые слышу, т.ч. автору спасибо!
            0
            WebDriver — это наиболее очевидное решение. Я как раз подумал о том, что можно было решить все это через отправку запросов, без всякого UI, но в первом комменте про это уже написали. :)
          0
          Хорошо бы втянуть excel в pandas через df = pandas.read_xls(“ЕГРЮЛ.xlsx”) и там уже при помощи len(df.index) определить длину столбца, а не вписывать руками 30 в начало скрипта.

          Впрочем, если скрипт для разового применения — сойдёт и так. А если для регулярного — лучше от «ручника» уйти.
            0
            да, у меня есть такая реализация. без pandas, все проще. но ручник нужен для ситуации, если полезли капчи либо отошел, либо интернет отвалился. напишу как-нибудь попозже пост как кидаться запросами, в том числе игнорируя капчи.
            0

            А почему код картинкой? В Хабр можно легко вставить код с подсветкой.

              0
              спасибо за комменты. первый пост, он такой ) тем более, что я юрист, а не программер. порой проще написать «лазерную пушку по воробьям» самому, чем идти в ИТ и объяснять, что это и зачем надо.
                0
                Лучше идите к начальству холдинга и выбивайте денег на какую нибудь платную систему, где будет вся свежая информация и из налоговой и из судов и еще откуда нибудь. Думаю, юрист не пропускающий важные события более ценен чем юрист умеющий программировать.
                  0
                  Вот именно, и «еще откуда-нибудь». Все существующие системы Спарк, Правобот и т.п. предоставляют какую-то информацию. Эта информация не особо-то и нужна, иногда не релевантна, а иногда вообще вводит в заблуждение. Кроме того, разрабатывать мелкие сервисы такие программные монстры не будут. Здесь и рождается ниша для IT-юристов.
                0
                import requests, json, os, datetime, traceback; from time import sleep
                inn = 6724005460 #инн из воздуха
                s = requests.Session()
                
                r = s.get("https://egrul.nalog.ru/index.html",
                    headers={
                        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:66.0) Gecko/20100101 Firefox/66.0",
                        "Accept-Language": "ru-RU,ru;q=0.8,en-US;q=0.5,en;q=0.3",
                        }
                    )
                
                req = requests.Request(
                    'POST',
                    'https://egrul.nalog.ru/',
                    data=b'vyp3CaptchaToken=&page=&query='+bytes(inn)+'&region=&PreventChromeAutocomplete=', # хабр почему то заменяет rеg в слове rеgion (буква е заменена на русскую) на знак ®, магия 
                    headers = {
                    "Host": "egrul.nalog.ru",
                    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:66.0) Gecko/20100101 Firefox/66.0",
                    "Accept": "application/json, text/javascript, */*; q=0.01",
                    "Accept-Language": "ru-RU,ru;q=0.8,en-US;q=0.5,en;q=0.3",
                    "Accept-Encoding": "gzip, deflate, br",
                    "Referer": "https://egrul.nalog.ru/index.html",
                    "Content-Type": "application/x-www-form-urlencoded",
                    "X-Requested-With": "XMLHttpRequest"
                    }
                    )
                
                r = s.prepare_request(req)
                r = s.send(r)
                #print(r.text)
                t = json.loads(r.text)['t']
                
                sleep(0.5)
                
                r = s.get("https://egrul.nalog.ru/search-result/"+str(t),
                    headers={
                        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:66.0) Gecko/20100101 Firefox/66.0",
                        "Accept-Language": "ru-RU,ru;q=0.8,en-US;q=0.5,en;q=0.3",
                        "Referer": "https://egrul.nalog.ru/index.html"
                        }
                    )
                
                #print(r.text)
                jsn = json.loads(r.text)
                
                try:
                    while True:
                        if jsn['status'] != 'wait': break
                        sleep(0.2)
                except Exception:
                    pass
                
                try:
                    item = (jsn["rows"])[0]
                    if str(item['tot']) != '0':
                        if len(item['n']) < 50: name = str(item['n'])
                        else: name = str(item['i'])
                
                        name = name.replace('"',"'").replace('\\','⧵').replace('/','⁄').replace('|','¦').replace(':',';').replace('*','✱').replace('?','').replace('<','«').replace('>','»')
                
                        try:
                            os.mkdir(name)
                        except Exception:
                            pass
                            name = name + ' '+str(datetime.datetime.strftime(datetime.datetime.now(datetime.timezone(datetime.timedelta(hours=3))),'%x %X %Z')).replace('/','.').replace(':','-')
                            os.mkdir(name)
                
                        f = open(name+'\\'+name+'.txt','w+',encoding='utf-8')
                        f.write('по состоянию на ' + str(datetime.datetime.strftime(datetime.datetime.now(datetime.timezone(datetime.timedelta(hours=3))),'%x %X %Z')).replace('/','.')+'\n'+str(item))
                        f.close()
                
                        t = item['t']
                
                        r = s.get("https://egrul.nalog.ru/vyp-request/"+str(t),
                            headers={
                                "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:66.0) Gecko/20100101 Firefox/66.0",
                                "Accept-Language": "ru-RU,ru;q=0.8,en-US;q=0.5,en;q=0.3",
                                "Referer": "https://egrul.nalog.ru/index.html"
                                }
                            )
                        sleep(0.5)
                        while True:
                            r = s.get("https://egrul.nalog.ru/vyp-status/"+str(t),
                                headers={
                                    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:66.0) Gecko/20100101 Firefox/66.0",
                                    "Accept-Language": "ru-RU,ru;q=0.8,en-US;q=0.5,en;q=0.3",
                                    "Referer": "https://egrul.nalog.ru/index.html"
                                    }
                                )
                            st = json.loads(r.text)['status']
                            if st == 'ready': break
                            sleep(0.5)
                
                        r = s.get("https://egrul.nalog.ru/vyp-download/"+str(t),
                                headers={
                                    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:66.0) Gecko/20100101 Firefox/66.0",
                                    "Accept-Language": "ru-RU,ru;q=0.8,en-US;q=0.5,en;q=0.3",
                                    "Referer": "https://egrul.nalog.ru/index.html"
                                    }
                                )
                
                        #print(r.text)
                
                        f = open(name+'\\'+name+' выписка.pdf','wb+')
                        f.write(r.content)
                        f.close()
                
                except Exception as e:
                    print(e)
                    traceback.print_exc()
                    pass

                Капча, обработка jsona с ответом и всякое такое в сделку не входит, но дописывается просто
                  0
                  отлично! большой труд.
                  вставлю свои 5 копеек:
                  — сравните теперь длину кода;
                  — requests, которые здесь использованы, к сожалению отваливаются из-за капч в дальнейшем;
                  — только один ИНН?
                    0
                    сравните теперь длину кода;

                    Де-факто большинство кода распсывание HTTP заглоловков
                    requests, которые здесь использованы, к сожалению отваливаются из-за капч в дальнейшем;

                    С чего это вдруг? Попробую сегодня обработать и отпишусь
                    только один ИНН?

                    Не-а любой запрос для поиска ФНС т.е. ОГРН, ИНН или название
                      0
                      по поводу ИНН — только одну компанию можно проверить?
                        0
                        Да, но ничто не мешает сделать цикл и небольшую задержку во избежание капч
                          0
                          Так в тексте программы уже этот цикл есть )
                          Небольшая задержка, к сожалению, не всегда спасает. Ранее писал под старый сервис, там задержку надо было ставить до 15 мин.
                            0
                            Добавил обработку капч, с задержкой в 5 секунд они достаточно редко появляются + бонусом парсинг jsona от фнс

                            Заголовок спойлера
                            import requests, json, os, datetime, traceback, bs4, webbrowser; from time import sleep;
                            querys = ['7707510023', 'ООО Яндекс', '1057749528100']
                            s = requests.Session()
                            n = 0
                            
                            for item in querys:
                                query = querys[n]
                                r = s.get("https://egrul.nalog.ru/index.html",
                                    headers={
                                        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:66.0) Gecko/20100101 Firefox/66.0",
                                        "Accept-Language": "ru-RU,ru;q=0.8,en-US;q=0.5,en;q=0.3",
                                        }
                                    )
                            
                                req = requests.Request(
                                    'POST',
                                    'https://egrul.nalog.ru/',
                                    data=b'vyp3CaptchaToken=&page=&query='+query.encode()+b'&region=&PreventChromeAutocomplete=', 
                                    headers = {
                                    "Host": "egrul.nalog.ru",
                                    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:66.0) Gecko/20100101 Firefox/66.0",
                                    "Accept": "application/json, text/javascript, */*; q=0.01",
                                    "Accept-Language": "ru-RU,ru;q=0.8,en-US;q=0.5,en;q=0.3",
                                    "Accept-Encoding": "gzip, deflate, br",
                                    "Referer": "https://egrul.nalog.ru/index.html",
                                    "Content-Type": "application/x-www-form-urlencoded",
                                    "X-Requested-With": "XMLHttpRequest"
                                    }
                                    )
                            
                                r = s.prepare_request(req)
                                r = s.send(r)
                                #print('31',r.text)
                                item = json.loads(r.text)
                                try:
                                    if item["ERRORS"] != '' and (item["ERRORS"])["captchaSearch"] != '':
                                        while True:
                                            r = s.get('https://egrul.nalog.ru/captcha-dialog.html',
                                            headers = {
                                                "Host": "egrul.nalog.ru",
                                                "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:66.0) Gecko/20100101 Firefox/66.0",
                                                "Accept-Language": "ru-RU,ru;q=0.8,en-US;q=0.5,en;q=0.3",
                                                "Referer": "https://egrul.nalog.ru/index.html",
                                                "Pragma": "no-cache",
                                                "Cache-Control": "no-cache"
                                            })
                                            b = bs4.BeautifulSoup(r.content.decode(),features="lxml").find('div',class_='field-data').find('img').get('src')
                                            #print('\r\n\r\nb =',b,'\r\n\r\n')
                                            webbrowser.open('https://egrul.nalog.ru' + b)
                                            ct = b.split('?a=')[1].split('&')[0]
                                            captcha = input('Введите капчу: ')
                                            #print('ct=',ct)
                            
                                            r = requests.Request(
                                            'POST',
                                            'https://egrul.nalog.ru/captcha-proc.json',
                                            data=b'captcha='+captcha.encode()+b'&captchaToken='+ct.encode(), 
                                            headers = {
                                                "Host": "egrul.nalog.ru",
                                                "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:66.0) Gecko/20100101 Firefox/66.0",
                                                "Accept": "application/json, text/javascript, */*; q=0.01",
                                                "Accept-Language": "ru-RU,ru;q=0.8,en-US;q=0.5,en;q=0.3",
                                                "Accept-Encoding": "gzip, deflate",
                                                "Referer": "https://egrul.nalog.ru/index.html"
                                                }
                                            )
                            
                                            r = s.prepare_request(req)
                                            r = s.send(r)
                                            #print('captcha r', r.text)
                                            item = json.loads(r.text)
                            
                                            try:
                                                tr = False
                                                if item["ERRORS"] != '':
                                                    tr = True
                                            except Exception as e:
                                                print(e)
                                                pass
                                            if tr == False: break
                                            
                            
                                except Exception as e:
                                    #print(e)
                                    pass
                                t = json.loads(r.text)['t']
                            
                                sleep(0.5)
                            
                                r = s.get("https://egrul.nalog.ru/search-result/"+str(t),
                                    headers={
                                        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:66.0) Gecko/20100101 Firefox/66.0",
                                        "Accept-Language": "ru-RU,ru;q=0.8,en-US;q=0.5,en;q=0.3",
                                        "Referer": "https://egrul.nalog.ru/index.html"
                                        }
                                    )
                            
                                #print('95', r.text)
                                jsn = json.loads(r.text)
                            
                                try:
                                    while True:
                                        if jsn['status'] != 'wait': break
                                        sleep(0.2)
                                except Exception:
                                    pass
                            
                                try:
                                    item = (jsn["rows"])[0]
                                    itemParse = ''
                            
                                    itemParse += item['n'] + '\n'
                                    itemParse += item['g'] + '\n'
                                    itemParse += 'Адрес: ' + item['a']+'\n'
                                    itemParse += 'ИНН: ' + item['i']+'\n'
                                    itemParse += 'ОГРН: ' + item['o']+'\n'
                                    itemParse += 'КПП: ' + item['p']+'\n'
                                    itemParse += 'Дата регистрации: ' + item['r']+'\n'
                            
                                    try:
                                        itemParse += 'ДАТА ПРЕКРАЩЕНИЯ ДЕЯТЕЛЬНОСТИ: ' + item['e']+'\n'
                                    except Exception:
                                        pass
                            
                                    if str(item['tot']) != '0':
                                        if len(item['n']) < 50: name = str(item['n'])
                                        else: name = str(item['i'])
                            
                                        name = name.replace('"',"'").replace('\\','⧵').replace('/','⁄').replace('|','¦').replace(':',';').replace('*','✱').replace('?','').replace('<','«').replace('>','»')
                            
                                        try:
                                            os.mkdir(name)
                                        except Exception:
                                            pass
                                            name = name + ' '+str(datetime.datetime.strftime(datetime.datetime.now(datetime.timezone(datetime.timedelta(hours=3))),'%x %X %Z')).replace('/','.').replace(':','-')
                                            os.mkdir(name)
                            
                                        f = open(name+'\\'+name+'.txt','w+',encoding='utf-8')
                                        f.write('по состоянию на ' + str(datetime.datetime.strftime(datetime.datetime.now(datetime.timezone(datetime.timedelta(hours=3))),'%x %X %Z')).replace('/','.')+'\n'+str(itemParse))
                                        f.close()
                            
                                        t = item['t']
                            
                                        r = s.get("https://egrul.nalog.ru/vyp-request/"+str(t),
                                            headers={
                                                "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:66.0) Gecko/20100101 Firefox/66.0",
                                                "Accept-Language": "ru-RU,ru;q=0.8,en-US;q=0.5,en;q=0.3",
                                                "Referer": "https://egrul.nalog.ru/index.html"
                                                }
                                            )
                                        sleep(0.5)
                                        while True:
                                            r = s.get("https://egrul.nalog.ru/vyp-status/"+str(t),
                                                headers={
                                                    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:66.0) Gecko/20100101 Firefox/66.0",
                                                    "Accept-Language": "ru-RU,ru;q=0.8,en-US;q=0.5,en;q=0.3",
                                                    "Referer": "https://egrul.nalog.ru/index.html"
                                                    }
                                                )
                                            st = json.loads(r.text)['status']
                                            if st == 'ready': break
                                            sleep(0.5)
                            
                                        r = s.get("https://egrul.nalog.ru/vyp-download/"+str(t),
                                                headers={
                                                    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:66.0) Gecko/20100101 Firefox/66.0",
                                                    "Accept-Language": "ru-RU,ru;q=0.8,en-US;q=0.5,en;q=0.3",
                                                    "Referer": "https://egrul.nalog.ru/index.html"
                                                    }
                                                )
                            
                                        #print(r.text)
                            
                                        f = open(name+'\\'+name+' выписка.pdf','wb+')
                                        f.write(r.content)
                                        f.close()
                                        n += 1
                                        sleep(5)
                            
                                except Exception as e:
                                    #print(e)
                                    traceback.print_exc()
                                    pass

                              0
                              и ещё, в 129 строке в replace('?') должен вот этот символ стоять unicode-table.com/ru/2753 но хабр его заменяет
                                0
                                upd. закрвл try для ИП шников
                                itemParse += item['n'] + '\n'
                                try:
                                    itemParse += item['g'] + '\n'
                                except Exception:
                                    pass
                                try:
                                    itemParse += 'Адрес: ' + item['a']+'\n'
                                except Exception:
                                    pass
                                itemParse += 'ИНН: ' + item['i']+'\n'
                                itemParse += 'ОГРН: ' + item['o']+'\n'
                                try:
                                    itemParse += 'КПП: ' + item['p']+'\n'
                                except Exception:
                                    pass
                                itemParse += 'Дата регистрации: ' + item['r']+'\n'
                    0
                    А почему проект сделан на питоне а не на VBA EXCEL? Данные же изначально в excel хранятся.
                      0
                      Потому что использовался python. Вы можете изложить свое решение
                        0
                        Мое решение для mac и windows отличается, если надо для всех систем — в макросе файла Excel можно установить проверку наличия библиотек или использовать VBA-tools/VBA-Web

                        Для Excel Windows можно использовать объект «MSXML2.XMLHTTP», причем не надо заниматься парсингом страницы, отправляйте POST на egrul.nalog.ru с query=inn, получите Json. Я ни разу не получил требование по вводу капчи, потому не понял, в чем прикол 30 секунд.

                        В Excel Mac Os есть Workbook.Querytable, увы она не работает так хорошо, хотя и выполняет вашу задачу. Я все равно рекомендую использовать либо vba-tools, либо выполнение запросов через обертку командной строки на StackOwerflow можно найти скрипт executeInShell, кстати там же решение с переключением mac-windows

                        Я дошел только до этого момента, но подозреваю, что получение файла через второй запрос выполняется аналогично.

                        Объем — 6 строк для получения ссылки на один файл, + цикл + объявление переменных.
                        Никаких питонов и зависимостей, кроме Excel, который ТОЖЕ участвует в вашем процессе.

                        Использование Python и Selenium в данном примере оправдывается только незнанием автора возможностей VBA excel.

                    Only users with full accounts can post comments. Log in, please.