Не для кого не секрет, что капча является популярным средством, чтобы снизить нагрузку на сайт и предотвратить скачивание информации роботами. Сегодня, когда капча применяется практически на каждом сайте, рассмотрим кейс с ее обходом на сервисе "Прозрачный бизнес".

Что такое "Прозрачный бизнес"?

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

Прежде чем начать, допустим, что у нас уже есть список ИНН, по которым надо опросить Сервис. Если нет, их можно вытащить из открытых данных ФНС или тут.

На старт

Начнем с POST запроса на https://pb.nalog.ru/search-proc.json. Тело запроса будет таким:

payload = {'page': '1', 'pageSize': '10', 'pbCaptchaToken': '', 'token': '', 'mode': 'search-ul', 'queryAll': '',
           'queryUl': 'ИНН ДЛЯ ЗАПРОСА', 'okvedUl': '', 'statusUl': '', 'regionUl': '', 'isMspUl': '', 'queryIp': '', 'okvedIp': '', 'statusIp': '',
           'regionIp': '', 'isMspIp': '', 'mspIp1': '1', 'mspIp2': '2', 'mspIp3': '3', 'queryUpr': '', 'uprType1': '1', 'uprType0': '1',
           'queryRdl': '', 'dateRdl': '', 'queryAddr': '', 'regionAddr': '', 'queryOgr': '', 'ogrFl': '1', 'ogrUl': '1', 'npTypeDoc': '1',
           'ogrnUlDoc': '', 'ogrnIpDoc': '', 'nameUlDoc': '', 'nameIpDoc': '', 'formUlDoc': '', 'formIpDoc': '', 'ifnsDoc': '',
           'dateFromDoc': '', 'dateToDoc': ''}

Однако если слишком часто дергать Сервис получим красивую картинку,

которая будет доступна по ссылке https://pb.nalog.ru/static/captcha.bin?r=1664389287469&a=B19F70E11E1ED39188D369F4F698A07A3EF963834C354814A1500080C8EA265EE3109E11270E79BDD6E154DCB897E1B5&version=2.

Ключевым здесь является параметр version=2. Попробуем заменить на version=3 и получаем:

Уже лучше, верно?

Затем делаем предварительные преобразования: убираем фон, чистим от шума и приводим к монохромному виду. Получается вот так:

Код метода
    def clean_image(self):
        for iy, y in enumerate(self.img_a):
            for ix, x in enumerate(y):
                pass
                if self.img_a[iy][ix][0] > 100 and self.img_a[iy][ix][1] > 100 and self.img_a[iy][ix][2] > 100:
                    self.img_a[iy][ix][0], self.img_a[iy][ix][1], self.img_a[iy][ix][2] = 255, 255, 255
                # Чистим полосы
                if self.img_a[iy][ix][0] >= 27 and self.img_a[iy][ix][0] <= 97 and \
                        self.img_a[iy][ix][1] >= 52 and self.img_a[iy][ix][1] <= 104 and \
                        self.img_a[iy][ix][2] >= 48 and self.img_a[iy][ix][2] <= 117:
                    self.img_a[iy][ix][0], self.img_a[iy][ix][1], self.img_a[iy][ix][2] = 255, 255, 255
                # Все, что осталось, делаем одного цвета
                if not (self.img_a[iy][ix][0] == 255 and self.img_a[iy][ix][1] == 255 and self.img_a[iy][ix][2] == 255):
                    self.img_a[iy][ix][0], self.img_a[iy][ix][1], self.img_a[iy][ix][2] = 0, 0, 0

Теперь надо нарезать картинку на цифры. Идея такая: сканируем картинку слева на право, центр первой встреченной вертикальной полосы из 5 подряд черных пикселей будет точкой входа. Рекурсивно находим все прилежащие черные пиксели. Границы получившегося прямоугольника и есть границы нашей цифры. Повторив процедуру шесть (по количеству цифр) раз, получаем шесть мини-картинок (массивов) с цифрами.

Иногда (скорее редко) получается, что в один массив попадают 2 цифры. Детектируем такие случаи по раздутой ширине прямоугольника (больше 35 пикселей), делим его (прямоугольник) пополам и надеемся, что нам повезет.

Из практики известно, что средний размер картинки с цифрой - 24 на 44 пикселя. По этому средствами библиотеки pillow трансформируем ее до этих значений.

Обучаем нейросеть

Мы научились получать капчу и резать ее на вменяемые цифры. Но как сформировать датасет для обучения нейронки? И здесь Сервис (pb.nalog.ru) идет нам на помощь. Все просто: каждый раз при скачивании капчи мы получаем новое изображение с одинаковыми цифрами. Другими словами, если скачать 10 000 капч, у нас будет 10 000 вариантов, например, цифры 8. Такой оборот избавляет нас от ручной разметки данных, и это хорошо!

В качестве нейронки возьмем простую модель с пятью внутренними слоями. Этого более чем достаточно, чтобы получить точность 99%.

model = keras.Sequential([
    keras.layers.Flatten(input_shape=(44, 24)),
    keras.layers.Dense(528, activation='tanh'),
    keras.layers.Dense(264, activation='tanh'),
    keras.layers.Dense(132, activation='tanh'),
    keras.layers.Dense(66, activation='tanh'),
    keras.layers.Dense(33, activation='tanh'),
    keras.layers.Dense(10,  activation='softmax')
])

model.compile(optimizer = 'adam', loss='categorical_crossentropy', 
              metrics = ['accuracy'])

Обученная модель также доступна на GitHub.

Получаем данные

Итак, когда мы можем преобразовывать картинку в шестизначный код, получаем токен капчи через POST запрос https://pb.nalog.ru/captcha-proc.json

payload = {'captcha': РЕЗУЛЬТАТ РАСПОЗНОВАНИЯ КАПЧИ}

Затем возвращаемся к запросу https://pb.nalog.ru/search-proc.json (с которого все началось) только теперь в поле pbCaptchaToken пробрасываем полученный токен капчи.

В ответ приходит токен организации. Его и передаем в теле запроса по url https://pb.nalog.ru/company-proc.json.

 payload = {'token': ТОКЕН ОРГАНИЗАЦИИ, 'method': 'get-request'}

Здесь Сервис, скорее всего, покажет еще одну капчу. Да, чтобы добраться до данных, капчу придется решить дважды. Но алгоритм действий уже известен! Решаем капчу, токен капчи передаем с полем pbCaptchaToken , и в ответ получаем новый токен и id.

Снова отправляем запрос на https://pb.nalog.ru/company-proc.json только теперь метод будет get-response.

Наконец, если все прошло хорошо, получим json с данными об организации. Что с ними делать - решайте сами.

Ссылка на GitHub

На этом все!

Комментарии (2)


  1. Robastik
    02.10.2022 08:36

    кейс с ее обходом

    Обход капчи - это использование уязвимости для доступа к информации без затрат на решение капчи. Т.е. это кейс решения капчи, а не обхода.

    если слишком часто дергать Сервис

    Слишком часто - с одного IP/отпечатка или это механизм для снижения нагрузки в пиковые периоды, т.е. капчу решают все вне зависимости от злоупотреблений?

    Какова постановка задачи, для решения которой приходится злоупотреблять частым дёрганьем сервиса?

    Если ограничение по IP/отпечатку, то сколько стоит решение капчи в сравнении с ценой прокси/фейкового отпечатка?


    1. hw_store
      02.10.2022 16:32
      +2

      Какова постановка задачи, для решения которой приходится злоупотреблять частым дёрганьем сервиса

      Отпарсить сайт, чтобы выложить его содержимое в альтернативно отформатированном виде, - вперемешку с рекламой, а в идеале - часть общедоступной информации при выдаче предложить за деньги ))