Найти в Дзене

[РискТехнологии] Автоматизиция. Нахождение террориста в перечне террористов. Юридические лица.

Статья является продолжением статьи Парсинг (скрапинг) перечня террористов юридических лиц с помощью Python В статье рассматриваться нахождения юридического лица в черном списке, когда название организации трансформируется для более точного поиска в списках. Программа будет принимать на вход 3 параметра: На схеме ниже изображено, как программа будет преобразовывать название компании. Программа сделает 2 варианта названия компании: без изменений и с замененными "Ё" и "Й" на "Е" и "И". И для каждого названия сделает еще по одному преобразованию с кириллицы на латиницу. Итого получится 4 названия компании вместо одного изначального. Не существует одного единственного верного преобразования кириллицы в латиницу, поэтому данную схему можно расширять, но текущая программа носит ознакомительный характер, поэтому остановимся на одном варианте преобразования. Дальше, согласно схеме, каждое из 4х названий будет проходить по 4 проверки: Количество проверок может быть и больше, но мы остановимся
Оглавление

Введение

Статья является продолжением статьи Парсинг (скрапинг) перечня террористов юридических лиц с помощью Python

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

Программа будет принимать на вход 3 параметра:

  • Название компании без организационно-правовой формы (ОПФ)
  • ИНН
  • ОГРН

На схеме ниже изображено, как программа будет преобразовывать название компании.

-2

Программа сделает 2 варианта названия компании: без изменений и с замененными "Ё" и "Й" на "Е" и "И". И для каждого названия сделает еще по одному преобразованию с кириллицы на латиницу. Итого получится 4 названия компании вместо одного изначального.

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

Дальше, согласно схеме, каждое из 4х названий будет проходить по 4 проверки:

  • нахождение одной подстроки в другой (x2)
  • полное совпадение названий
  • нахождение расстояния Левенштейна

Количество проверок может быть и больше, но мы остановимся на 4х

Также программа будет осуществлять поиск по ИНН и ОГРН, но в этом нет ничего сложного.

Результом программы будет имитация REST ответа:

-3

На примере выше видно, что сработало 2 хита:

  • по ИНН
  • по включению одной подстроки в другую

За пределами статьи:

  • заранее были подготовлены файлы для работы с виртуальной средой. О том, как их подготавливать, описываю в отдельной статье: https://dzen.ru/a/aEKVHTM_GULyazKa
  • стартовые исходники для статьи лежат в GitLab. В рамках статьи не объясняется, как устанавливать и настраивать git. Всё это описываю в отдельной статье: https://dzen.ru/a/aGgSbU4TnF-_7wL_
  • должна быть установлена БД PostgreSQL. Установку рассматриваю в статье: https://dzen.ru/a/aEvZ9r7Yj290D80N

В конце статьи есть ссылка в GitLab на финальную версию программы.

Особенность программы

В статье предполагается, что имеется БД с определенными таблицами и данными, которые были созданы в рамках статьи: Парсинг (скрапинг) перечня террористов юридических лиц с помощью Python

Однако, в ниже по тексту будет кратко сказано, как обойтись без реализации предыдущей статьи.

Используемые технологии

ОС: Windows 10

Язык: Python 3.12

Основные библиотеки: re, pyodbc, pydantic, pandas

Прочее: PostgreSQL 17.5

План работы

  • Клонируем репозиторий с GitLab
  • Настраиваем виртуальную среду
  • Планируем архитектуру программы
  • Создаём программу
  • Запускаем программу

Клонируем репозиторий с GitLab

Создадим папку "searcher_ul", куда будем клонировать репозиторий

mkdir searcher_ul

Клонируем репозиторий

git clone https://gitlab.com/pytechnotes1/searcher_ul searcher_ul

Заходим в папку

cd searcher_ul/

Делаем чекаут версии коммита, который я сделал специально для статьи

git checkout b43f3c7e80e7f90532a956fdf85efc14db4ce287

Настраиваем виртуальную среду

Открываем в cmd наш проект searcher_ul и создать виртуальную среду

py -3.12 -m venv venv

Активируем среду

venv\Scripts\activate

Производим установку библиотек из файла, который я подготовил заранее

pip install -r requirements.txt

Выходим из виртуальной среды

deactivate

Изучаем архитектуру программы

Заранее уже готова определенная структура программы.

  • app.py - скрипт, который будет запускать нашу программу.
  • black_list.py - скрипт с нашей программой, которую мы будем реализовывать.
  • settings- папка с конфигами. Её править нет необходимости, если были выполнены все действия из предыдущей статьи: Парсинг (скрапинг) перечня террористов юридических лиц с помощью Python

Ряд конфигов, которые тут представлены в готовом виде, я показываю их реализацию в статье: https://dzen.ru/a/aGYT0uBWUSxWLe9y

Создаём программу

Начнем реализацию файла black_list.py

Реализуем конструктор __init__:

-4

Ниже описание некоторых переменных, которые будут созданы в момент создания экземпляра класса BlackListUL:

  • settings - экземпляр класса Settings. Переменная с конфигурационными данными.
  • self.sql - SQL запрос к таблице со списком террористов. Сам SQL запрос располагается в файле request.sql
  • self.lev_off - переменная, которая будет отключать проверку на расстояние Левенштейна.
  • self.ptrn - шаблоны (Patterns) из файла config.ini
  • self.terrorists - список данных по террористам из БД. Список формируем с помощью метода _set_terrorists. Если в рамках статьи нет желания и/или возможности работать с БД, можно переменной self.terrorists просто присвоить DataFrame вида:
pd.DataFrame([["Название1","ИНН1","ОГРН1"],["Название2","ИНН2","ОГРН2"]], columns=["name","inn","ogrn"])

Сразу подключим необходимые импорты

import re
import pandas as pd
import pyodbc
import unicodedata
from settings import Settings, BLModel, Response as RM, CompanyModel as CM

Реализуем метод _set_terrorists и декоратор connect_db:

-5

В конструкторе в метод _set_terrorists мы передаем строку для соединения с БД.

Метод _set_terrorists мы декорируем методом connect_db.

Декоратор connect_db подменяет "строку для соединения с БД", и в метод _set_terrorists передается уже коннектор от библиотеки pyodbc.

Метод _set_terrorists делает запрос в БД, передает результат в декоратор. Декоратор закрывает соединение с БД и передает результат SQL запроса в переменную self.terrorists.

Декоратором подменять аргументы метода - плохой тон. Не делайте так в реальных проектах.

Приступим к реализации метода search

-6

Метод search вызывает метод _prepare_company_name, который убирает все лишние символы в названии компании, кроме букв и цифр.

Если название получилось коротким (менее 4х символов), то мы не будем проводить проверку на расстояние Левенштейна. Иначе будет очень много ложных срабатываний при поиске в списках.

Вызовем еще ряд методов:

  • _set_objects - формирует list связок: Название+ИНН+ОГРН.
  • _loop_lists - основной метод поиска террориста в списке
  • _print_response - метод формирует ответ в формате JSON (имитация REST ответа)

Начнем с реализации метода _print_response

-7

Для реализации данного метода был заранее создан файл response_model.py со всей структурой ответа.

Именно данный метод формирует ответ следующего вида:

-8

Приступим к реализации метода _set_objects

-9

Данный метод формирует list связок, как на схеме ниже

-10

Для формирования трансформированных названий компании необходимо реализовать метод _get_company_names, который вернет список всех возможных вариаций названия компании.

Перейдем к реализации методов, с помощью которых метод _get_company_names подготавливает трансформированные названия.

-11

Метод _get_ru_company_names подготавливает название компании в двух вариантах: как есть и с заменой Ё на Е и Й на И.

Методы _get_lat_company_names и _transliterate_ru_to_lat подготавливают для каждого кириллического варианта названия компании латинский вариант.

Перейдем к реализации метода _loop_lists

-12

Метод итерируется по каждому террористу в списке террористов и осуществляет проверки на поиск ИНН, ОГРН и названия компании во всех вариациях, которые были подготовлены методом _set_objects.

Методы _search_uid_hists и _search_name_hists группируют ответы проверок.

-13

Проверки выполняются методами _full_eq, _include_eq и _levenshtein_distance.

-14

Через метод _full_eq мы сравниваем ИНН и ОГРН компании клиента и компании из списка террористов.

Методом _remove_accents, который используется в _search_name_hists, мы убираем диакритические знаки из названия компании.

С помощью метода _include_eq мы ищем включения одной подстроки в другую.

Ниже описан вариант реализации поиска расстояния Левенштейна. Одна из причин появления этой статьи - это показать работу данного метода на практике.

-15

Расстояние Левенштейна - это сумма вставок, удалений, замен символов между двух строк. Несколько примеров:

-16

Последний пример - это причина, почему в коротких названиях расстояние Левенштейна может давать ложные срабатывания.

Немного другой вариант реализации расстояния Левенштейна я показываю в статье: https://dzen.ru/a/aGYT0uBWUSxWLe9y

Под конец реализуем методы, которые будут фиксировать хиты:

-17

Касательно проверок на включение в подстроку, нахождение ИНН и ОГРН всё просто: если запись нашлась, то ставим соответствующий хит.

При проверке расстояния Левенштейна, если расстояние = 0, то считаем, что террорист в списке 100% найден, и укажем хит: DIST0. Если расстояние менее 3х, то укажем хит: DIST2.

Почему менее 3х? Из моей практики это самое оптимальное число. Большее число приведет к большому количеству ложных срабатываний, меньшее не будет сильно отличаться от хита DIST0.

На этом реализацию программы заканчиваем.

Запускаем программу

Запускаем скрипт через "py", таким образом запустится интерпретатор из виртуальной среды.

py app.py

Получаем JSON ответ:

{"black_list":{"result":1,"company":{"name":"СВЕТЛАЯ НАДЕЖДА","inn":"1653019714","ogrn":""},"hits":{"INC":["АВТОНОМНАЯ НЕКОММЕРЧЕСКАЯ ОРГАНИЗАЦИЯ БЛАГОТВОРИТЕЛЬНЫЙ ПАНСИОНАТ АК УМУТ СВЕТЛАЯ НАДЕЖДА"],"INN":["1653019714"]}}}

Исходники проекта

PyTechNotes / searcher_ul · GitLab

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