Пишем первого робота для банка

от автора

О чем это

В этой статье мы разберемся, что такое «робот», поймем, как они помогают операционистам, напишем и запустим простого робота на Python.

Исходный код робота и данные для работы можно скачать здесь.

Макросы на стероидах

Робот имитирует действия человека, сидящего за компьютером.

Он может открывать программы, нажимать в них на кнопки, читать и вводить данные.

То, что сейчас называется роботом, впервые стало популярно в 80-х годах прошлого века под названием «макрос»: при нажатии определенной комбинации клавиш макрос вместо оператора вводил и считывал необходимые данные из текстового терминала, что помогало форматировать текст и выполнять другие рутинные операции.

С появлением графических интерфейсов макросы на время остановились в развитии. Прорыв случился только с появлением пакета Microsoft Office ’97 в 1997 году с появлением возможности записывать действия пользователя и превращать их в исполняемый код на Visual Basic for Applications.

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

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

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

Сценарии могут быть и более сложными, причем нередко требуется применение интеллекта операциониста.

Задача нашего первого робота

Наш первый робот будет имитировать работу операциониста CRM в сценарии «обогати клиентские данные в локальной CRM полем ИНН из облачного сервиса».

Процесс AS IS (как работает операционист CRM до появления робота)

  • Операционист открывает локальную CRM-систему. Для нашего учебного примера для простоты мы не будем устанавливать промышленную CRM, а воспользуемся приложением Microsoft Office Excel, в котором будет открыт файл с полями «Фамилия», «Имя», «Отчество», «Дата рождения» и «Номер паспорта».

  • Операционист читает правила сервиса и соглашается с ними нажимая соответствующую галочку.

  • Сайт отображает форму поиска ИНН.

  • Операционист переключается в окно Excel, находит ячейку с фамилией и нажимает клавиши Ctrl + C, копируя данные в буфер обмена.

  • Операционист переключается в браузер и вставляет в него поле данные из буфера обмена.

  • Пункты 4-5 операционист повторяет для полей «Имя», «Отчество», «Дата рождения» и «Номер паспорта».

  • Операционист нажимает на сайте кнопку «Отправить запрос».

  • Сайт какое-то время думает и затем отображает ИНН.

  • Операционист выделяет ИНН, копирует его в буфер обмена и переносит его обратно в Excel.

  • Операционист повторяет шаги выше для остальных записей о пользователе.

Процесс TO BE (как будет работать робот)

  1. Робот находит окно Excel и перемещает курсор в левый верхний угол (в начало клиентских данных). Конечно, робот мог бы прочесть Excel-файл напрямую, но для учебного примера мы предположим, что этой возможности нет, что робот имеет доступ только к пользовательскому интерфейсу CRM и вынужден имитировать действия оператора.

  2. Робот запускает браузер и открывает в нем ссылку https://service.nalog.ru/inn.do. Если появляется окно с приглашением принять условия обслуживания, то робот имитирует нажатие на эту галочку.

  3. Робот переключается в окно Excel и последовательно копирует все клиентские данные из ячеек Excel в буфер обмена, а из буфера обмена — в массив в памяти робота.

  4. Робот переключается в браузер и последовательно получает ИНН для каждой клиентской записи, для этого:

    1. Вставляет данные из памяти в форму на сайте https://service.nalog.ru/inn.do.

    2. Нажимает кнопку «Отправить запрос».

    3. Ждет пока сайт отобразит ИНН во всплывающей подсказке.

    4. Копирует ИНН из всплывающей подсказки в память программы рядом с данными о клиенте.

  5. Робот переключается в окно Excel, находит столбец «ИНН» и вставляет ИНН из памяти программы в соответствующие ячейки.

Выбираем язык программирования

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

Мы будем использовать язык Python, поскольку мы в конечном счете заменяем операциониста и со временем для этого могут потребоваться инструменты для программирования искусственного интеллекта, которые в Python присутствуют в полном объеме.

Помимо этого язык Python является простым в освоении и на нем проходит обучение программированию в Minecraft. Я знаю это потому, что мой семилетний сын программирует на Python в Minecraft и, кстати, одно из его любимых развлечений — роботизировать в Minecraft рутинные задачи, например, рыть тоннели к алмазам и строить место для ночлега.

Язык Python используется многими компаниями и банками, в том числе для задач роботизации он используется и в МКБ.

Подготовка

Для работы потребуется установить:

  • Excel для имитации CRM

  • Google Chrome для доступа к сайту https://service.nalog.ru/inn.do

  • Python 3, его можно скачать с сайта https://www.python.org/downloads/

  • PyWinAuto для имитации работы операциониста в Excel и любом другом не-браузерном приложении

pip3 install pywinauto

  • selenium web driver для имитации работы операциониста в Google Chrome. Для установки этого пакета необходимо выполнить два шага:

    • Скачать исполняемое приложение ChromeWebDriver отсюда https://chromedriver.chromium.org/downloads , при этом обратите внимание на версию — она должна совпадать с версией Google Chrome

    • Установить пакет для Python3

pip3 install selenium

Переходим к программированию

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

В обычной жизни это делает операционист.

При программировании робота эти действия имитируют библиотеки pywinauto для классических приложений и selenium — для браузерных.

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

Из плохих новостей — компьютером в этот момент нельзя будет пользоваться: за ним «сидит» робот.

Код CrmAppAgent

Вся логика работы с CRM упакована в класс CrmAppAgent.

В нем реализованы как методы перемещения курсора, копирования и вставки данных, так и более высокоуровневые методы для получения списка записей и вставки ИНН напротив записей о клиенте.

from pywinauto import Application from pywinauto import clipboard import time  class CrmAppAgent:     def __init__(self):         window_title_regular_expression = ".*data.*"         excel_app = Application(backend="uia").connect(title_re=window_title_regular_expression)         excel_window = excel_app.window(title_re=window_title_regular_expression)         self.excel_app = excel_app         self.excel_window = excel_window      def deselect(self):         excel_window = self.excel_window         excel_window.type_keys('{ESC}')      def move_cursor_to_top_left_corner(self):         excel_window = self.excel_window         excel_window.type_keys('^{HOME}')      def move_cursor_down(self):         excel_window = self.excel_window         excel_window.type_keys('{DOWN}')      def move_cursor_to_first_person_cell(self):         excel_window = self.excel_window         self.move_cursor_to_top_left_corner()         self.move_cursor_down()      def read_cell_contents(self):         excel_window = self.excel_window         excel_window.type_keys('^c')         time.sleep(0.1)         cell_data = clipboard.GetData()         result = cell_data.rstrip()         return result      def move_cursor_right(self):         excel_window = self.excel_window         excel_window.type_keys('{RIGHT}')      def move_cursor_to_first_left_cell(self):         excel_window = self.excel_window         excel_window.type_keys('{HOME}')      def read_person(self):         excel_window = self.excel_window         last_name = self.read_cell_contents()          if not last_name:             return None          self.move_cursor_right()         first_name = self.read_cell_contents()          self.move_cursor_right()         middle_name = self.read_cell_contents()          self.move_cursor_right()         birthday = self.read_cell_contents()          self.move_cursor_right()         passport = self.read_cell_contents()          self.move_cursor_down()         self.move_cursor_to_first_left_cell()          return {             "last_name": last_name,             "first_name": first_name,             "middle_name": middle_name,             "birthday": birthday,             "passport": passport         }      def read_persons(self):         excel_window = self.excel_window         result = []         self.deselect()         self.move_cursor_to_first_person_cell()         while True:             person = self.read_person()             if person:                 result.append(person)             else:                 break          return result          def move_cursor_to_first_inn(self):         excel_window = self.excel_window         self.move_cursor_to_top_left_corner()         self.move_cursor_down()          for i in range(5):             self.move_cursor_right()              def fill_inns(self, inns):         excel_window = self.excel_window         self.move_cursor_to_first_inn()         for inn in inns:             excel_window.type_keys(inn)             self.move_cursor_down()

Код InnAppAgent

Логика работы с приложением https://service.nalog.ru/inn.do упакована в класс InnAppAgent.

Работа с этим приложением ведется через selenium web driver, что позволяет находить элементы на HMTL-странице веб-приложения по идентификаторам и код получается чище и короче, нежели код роботизации классического приложения.

from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.keys import Keys import os  class InnAppAgent:     def __init__(self):                 browser = self.get_browser()         self.browser = browser                  browser.implicitly_wait(10)          SERVICE_URL = 'https://service.nalog.ru/inn.do'         browser.get(SERVICE_URL)          accept_terms_and_conditions_page_shown = browser.current_url != SERVICE_URL          if accept_terms_and_conditions_page_shown:             self.accept_terms_and_conditions()                  def get_browser(self):         options = webdriver.ChromeOptions()         options.add_argument("--start-maximized")          current_folder = os.getcwd()         web_driver_executable_name = "chromedriver.exe"         web_driver_executable_path = "{}\\{}".format(current_folder, web_driver_executable_name)         result = webdriver.Chrome(executable_path=web_driver_executable_path, chrome_options=options)         return result      def accept_terms_and_conditions(self):         browser = self.browser         browser.find_element(By.XPATH, '//a[@class="checkbox checkbox-off"]').click()         browser.find_element(By.XPATH, '//button[@id="btnContinue"]').click()      def fill_person_data(self, person):         browser = self.browser         input_data = {             "fam": person["last_name"],             "nam": person["first_name"],             "otch": person["middle_name"],             "bdate": person["birthday"],             "docno": person["passport"]         }          for element_id, input_value in input_data.items():             element = browser.find_element(By.ID, element_id)             element.clear()             for symbol in input_value:                 element.send_keys(symbol)                 time.sleep(0.1)      def submit_data(self):         browser = self.browser         browser.find_element(By.ID, 'btn_send').click()      def read_inn(self):         browser = self.browser         previous_inn_element = browser.find_element(By.ID, "resultInn")         previous_inn = previous_inn_element.text         WebDriverWait(driver=browser, timeout=10, poll_frequency=1).until(lambda drv: drv.find_element(By.ID, "resultInn").text != previous_inn)          inn_element = browser.find_element(By.ID, "resultInn")         result = inn_element.text          return result      def submit_data_and_read_inn(self):         browser = self.browser         self.submit_data()          return self.read_inn()      def find_inn(self, person):         browser = self.browser         self.fill_person_data(person=person)          result = self.submit_data_and_read_inn()          return result      def find_inns(self, persons):             browser = self.browser          return [self.find_inn(person=person) for person in persons]

Код сценария робота

Бизнес-логика по взаимодействию роботов вынесена в класс EnrichPersonsWithInnsScenario.

Сценарий очень короткий, поскольку все нюансы взаимодействия с приложением CRM и приложением https://service.nalog.ru/inn.do вынесена в классы-агенты.

class EnrichPersonsWithInnsScenario:     def __init__(self, crm_app_agent, inn_app_agent):         self.crm_app_agent = crm_app_agent         self.inn_app_agent = inn_app_agent              def run(self):         crm_app_agent = self.crm_app_agent          persons = crm_app_agent.read_persons()          inn_app_agent = self.inn_app_agent         inns = inn_app_agent.find_inns(persons=persons)          crm_app_agent.fill_inns(inns=inns)  crm_app_agent = CrmAppAgent() inn_app_agent = InnAppAgent() enrich_persons_with_inns_scenario = EnrichPersonsWithInnsScenario(crm_app_agent=crm_app_agent, inn_app_agent=inn_app_agent) enrich_persons_with_inns_scenario.run()

Финальный листинг

Исходный код робота и данные для работы можно скачать здесь: https://github.com/vasiliy-mikhailov/robot_tutorial

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

  • Откройте файл data.xlsx при помощи Excel. Робот будет искать окно с названием «data», поэтому переименовывать файл нельзя.

  • Опционально: поменяйте в Excel тестовые данные клиента на свои. Если этого не сделать, то сайт https://service.nalog.ru/inn.do не сможет найти ИНН и сценарий не дойдет до конца. Реальные данные не включены в учебный пример по соображениям соблюдения закона о персональных данных.

  • Сохраните скрипт robot.py в любую папку.

  • Положите в эту же папку файл chromedriver.exe.

  • Перейдите в эту папку и выполните в ней команду.

python3.exe robot.py

  • Вы увидите как запустится браузер и робот примет в нем условия обслуживания.

  • Затем откроется окно Excel и робот начнет перемещаться по ячейкам и копировать их содержимое.

  • После того как робот скопирует все ячейки, переключитесь в окно браузера и посмотрите как робот вводит эти данные в форму и получает ИНН.

  • Если робот сможет вычислить все ИНН, то он перейдет обратно в Excel и заполнит ячейку с ИНН.

  • Обратите внимание на то, что робот может не выполнить работу до конца. Наиболее частые ошибки: невозможность скопировать данные в буфер обмена с ошибкой «Доступ запрещен» и зависание сервиса https://service.nalog.ru/inn.do на стадии поиска ИНН.

Поздравляю, что дальше?

Вы только что написали своего первого робота на языке программирования Python.

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

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

Поиск задач под роботизацию

Если вы выходите домой в 21:00, а операционисты все еще сидят, подойдите к ним и посмотрите, что они делают. Вполне может быть, что они выполняют рутинные операции по вводу данных, тогда весьма вероятно, что это ваши будущие клиенты. Присмотритесь и к другим шаблонным процессам в компании. Подумайте, как можно улучшить работу.

Экономика вопроса

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

Простые роботы могут быть написаны Junior-разработчиком, однако, когда количество роботов растет, возникает потребность в размещении их на серверах, организации автоматического процесса поставки и мониторинга исполнения. Для организации этого процесса и формирования правильной архитектуры обычно требуется Senior-разработчик.

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

Развиваем технические навыки

Для более глубокого изучения рекомендую прочесть и перенабрать своими руками примеры кода из книга «Автоматизация рутинных задач с помощью Python».

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

Удачи в изучении Python!

Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.

Какие у вас отношения с роботами?

19.44% Сторонюсь7
25% Читал про них9
19.44% Сделал учебного робота7
5.56% Ищу работу программистом по роботизации2
30.56% Уже давно и плотно профессионально их программирую11

Проголосовали 36 пользователей. Воздержались 3 пользователя.

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


Комментарии

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

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