Русский
Русский
English
Статистика
Реклама

Openpyxl

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

09.08.2020 16:21:03 | Автор: admin


Я работаю педагогом в детском технопарке Кванториум. В период самоизоляции мы так же, как и все перешли на дистанционное обучение. И в связи с тем, что дети стали еще больше времени проводить за компьютером, администрация решила сократить академический час и делать перерывы между работой (что бы сохранить зрение). Мы написали приложение, которое подсчитывает время, проведенное за компьютером, ведет статистику в excel (полезно для родителей) и выдает звуковое оповещение о том, что пора сделать перерыв.

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

Ссылка на репозиторий

Под катом подробный разбор.

Для создания программы нужно решить следующие задачи:

  • детекция лица через web камеру (используем mtcnn);
  • подсчёт времени (библиотека time)
  • запись данных в excel документ (библиотека openpyxl);
  • звуковое оповещение;
  • автозагрузка скрипта при включении ПК.

Детекция лица с использованием web камеры


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

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

Изначально использовали метод Виолы-Джонса. Точность намного хуже, чем у mtcnn, процессор загружает также.





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

import cv2import osfrom mtcnn.mtcnn import MTCNNdef show_face_frame():    if faces:        bounding_box = faces[0]['box']        keypoints = faces[0]['keypoints']        cv2.rectangle(img,                      (bounding_box[0], bounding_box[1]),                      (bounding_box[0] + bounding_box[2],                       bounding_box[1] + bounding_box[3]),                      (0, 0, 255),                      2)        cv2.circle(img, (keypoints['left_eye']), 3, (0, 0, 255), 2)        cv2.circle(img, (keypoints['right_eye']), 2, (0, 0, 255), 2)        cv2.circle(img, (keypoints['nose']), 3, (0, 0, 255), 2)        cv2.circle(img, (keypoints['mouth_left']), 3, (0, 0, 255), 2)        cv2.circle(img, (keypoints['mouth_right']), 3, (0, 0, 255), 2)    cv2.imshow('frame', img)cap = cv2.VideoCapture(0)detector = MTCNN()while cap.isOpened():        _, img = cap.read()        img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)        faces = detector.detect_faces(img)        show_face_frame()        cv2.waitKey(300)cap.release()cv2.destroyAllWindows()

Большая задержка cv2.waitKey(300), чтобы не загружать процессор. Обработка 3-4 кадров в секунду загружают i3-8145U в среднем на 15%.

Подсчет времени


Программа не должна делать записи в журнал в следующих случаях:

  • сел за компьютер на 5 сек что-то по бырику сделать;
  • вышел налить кофе или размять ноги.

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

В переменной min_time_here указано минимальное время, проведенное за компьютером, после которого стоит делать запись в журнал. Запись будет произведена после того, как человек отвлечётся от компьютера на время большее чем указано в min_time_not_here.

В коде ниже запись осуществляется, если провел минимум 5 минут за компьютером. Программа не будет учитывать то, что я отвлекаюсь меньше чем на 2 минуты.

import cv2import timeimport osfrom mtcnn.mtcnn import MTCNNcap = cv2.VideoCapture(0)path = os.path.abspath(__file__)[:-11]  # из абсолютного пути удаляем имя файлаhere, not_here = 0, 0  # секундомерыtime_here, time_not_here = 0, 0  # количество времениswitch = True  # переключатель определяет есть лицо в кадре или нетmin_time_here = 300  # минимально время проведенное за пк, после которого производится запись (в секундах) min_time_not_here = 120  # максимальное время отвлечение от компьютера которое не учитывается программой (в секундах)detector = MTCNN()try:    while cap.isOpened():        _, img = cap.read()        img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)        faces = detector.detect_faces(img)       show_face_frame()       audio_message(path, here)        if faces and switch:            not_here = 0            switch = False            if here == 0:                here = time.time()                print('вы сели за компьютер в ' + time.strftime("%H:%M:%S", time.localtime(here)))        elif not faces and not switch:            not_here = time.time()            switch = True        if not_here != 0:            time_not_here = time.time() - not_here        if here != 0 and not switch:            time_here = time.time() - here        if time_here > min_time_here and time_not_here > min_time_not_here:  # делаем запись если провели за ПК больше min_time_here            write_excel(path, here)            print('вы провели за компьютером ' + time.strftime('%H:%M:%S', time.gmtime(time.time() - here)))            time_here, time_not_here = 0, 0            here, not_here = 0, 0        elif time_not_here > min_time_not_here and  time_here < min_time_here:  # если за ПК провели меньше min_time_here, то ничего не записываем            print('запись не произведена')            time_here, time_not_here = 0, 0            here, not_here = 0, 0        cv2.waitKey(300)except KeyboardInterrupt:    if time_here > min_time_here:  # делаем запись если провели за ПК больше min_time_here        write_excel(path, here)    cap.release()    cv2.destroyAllWindows()

Если пользователь хочет выключить компьютер, для начала нужно прервать работу программы (ctrl+c) и время текущей работы попадет в журнал. Для этого используется обработчик исключений.

Запись данных в excel документ


Для работы с excel поможет замечательная библиотека openpyxl, которая одновременно считывать и записывать данные.

Каждый день программа создает новый лист с текущей датой.


На 1 листе записывается посуточная информация, в какой день сколько времени провели за компьютером.



Функция write_excel открывает документ записывает данные и сразу же закрывает.

Нельзя изменить документ через openpyxl если он уже открыт пользователем. На этот случай добавлено исключение.

def write_excel(path_excel, time_start):    wb = openpyxl.load_workbook(path_excel + r'\dnevnik.xlsx')    today = time.strftime("%d.%m.%Y", time.localtime(time.time()))    if today not in wb.sheetnames:  # если листа с сегодняшней датой еще не существует, то создаем его        wb.create_sheet(title=today)        sheet = wb[today]        sheet.column_dimensions['A'].width = 20        sheet.column_dimensions['B'].width = 20        sheet.column_dimensions['C'].width = 20        sheet.column_dimensions['D'].width = 31        sheet['A1'] = 'Начал работать за ПК'        sheet['B1'] = 'Время работы за ПК'        sheet['C1'] = 'Закончил работать'        sheet['D1'] = 'Сел за компьютер:'        sheet['D2'] = 'Всего провели за ПК времени:'        sheet = wb[today]        row = 2        all_time = 0    else:  # если лист уже создан извлекаем информацию        sheet = wb[today]        row = sheet['E1'].value  # номер строки в excel документе        all_time = sheet['E2'].value  # общее время проведенное за ПК за один день        all_time = all_time.split(':')        all_time = int(all_time[0]) * 3600 + int(all_time[1]) * 60 + int(all_time[2])  # время переводим в секунды        row = row + 2  # плюсуем шапку таблицы и новую строку    sheet['A' + str(row)] = time.strftime("%H:%M:%S", time.localtime(time_start))  # записываем время когда сели за пк    sheet['C' + str(row)] = time.strftime("%H:%M:%S", time.localtime(time.time()))  # когда вышли из за пк    seconds = time.time() - time_start  # время которое мы провели за компьютером    sheet['B' + str(row)] = time.strftime('%H:%M:%S', time.gmtime(seconds))    sheet['E1'] = row - 1  # вычитаем шапку таблицу    all_time = all_time + seconds    all_time = time.strftime('%H:%M:%S', time.gmtime(all_time))    sheet['E2'] = all_time    # заполняем первый лист    sheet_0 = wb.worksheets[0]    sheet_0['A' + str(len(wb.sheetnames))] = today    sheet_0['B' + str(len(wb.sheetnames))] = all_time    while True:  # закрываем файл        try:            wb.save(path_excel + r'\dnevnik.xlsx')        except PermissionError:            input('Сначала закройте excel файл и подтвердите нажав enter')        else:            break

Звуковое оповещение


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

def audio_message(path, here):    if here == 0:        pass    elif time.strftime('%H:%M:%S', time.gmtime(time.time()-here)) == "01:00:00":        wav = random.choice(os.listdir(path + r'\audio'))        winsound.PlaySound(path + r'\audio\\' + wav, winsound.SND_FILENAME)

Автозагрузка скрипта при включении ПК


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

C:\Users\%username%\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup

C учетом того, что батник и исходный файл хранятся в разных директориях, нельзя использовать функцию os.getcwd() так как она вернет путь до батника. Мы используем os.path.abspath(__file__)[:-11]

В будущем


Хотелось бы, что бы программа следила за моим лицом, а не за всеми, кто садиться за компьютер. Для этого будет использоваться FaceNet которая способна распознавать лица.
Также в планах разработать красивый виджет вместо некрасивой черной консоли, и что бы при выключении компьютера запись производилась автоматически, а не с помощью прерывания.
Спасибо за внимание. Если есть вопросы пишите в комментарии или на https://www.linkedin.com/in/evg-voronov/
Подробнее..

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

09.08.2020 20:18:26 | Автор: admin


Я работаю педагогом в детском технопарке Кванториум. В период самоизоляции мы так же, как и все перешли на дистанционное обучение. И в связи с тем, что дети стали еще больше времени проводить за компьютером, администрация решила сократить академический час и делать перерывы между работой (что бы сохранить зрение). Мы написали приложение, которое подсчитывает время, проведенное за компьютером, ведет статистику в excel (полезно для родителей) и выдает звуковое оповещение о том, что пора сделать перерыв.

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

Ссылка на репозиторий

Под катом подробный разбор.

Для создания программы нужно решить следующие задачи:

  • детекция лица через web камеру (используем mtcnn);
  • подсчёт времени (библиотека time)
  • запись данных в excel документ (библиотека openpyxl);
  • звуковое оповещение;
  • автозагрузка скрипта при включении ПК.

Детекция лица с использованием web камеры


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

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

Изначально использовали метод Виолы-Джонса. Точность намного хуже, чем у mtcnn, процессор загружает также.





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

import cv2import osfrom mtcnn.mtcnn import MTCNNdef show_face_frame():    if faces:        bounding_box = faces[0]['box']        keypoints = faces[0]['keypoints']        cv2.rectangle(img,                      (bounding_box[0], bounding_box[1]),                      (bounding_box[0] + bounding_box[2],                       bounding_box[1] + bounding_box[3]),                      (0, 0, 255),                      2)        cv2.circle(img, (keypoints['left_eye']), 3, (0, 0, 255), 2)        cv2.circle(img, (keypoints['right_eye']), 2, (0, 0, 255), 2)        cv2.circle(img, (keypoints['nose']), 3, (0, 0, 255), 2)        cv2.circle(img, (keypoints['mouth_left']), 3, (0, 0, 255), 2)        cv2.circle(img, (keypoints['mouth_right']), 3, (0, 0, 255), 2)    cv2.imshow('frame', img)cap = cv2.VideoCapture(0)detector = MTCNN()while cap.isOpened():        _, img = cap.read()        img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)        faces = detector.detect_faces(img)        show_face_frame()        cv2.waitKey(300)cap.release()cv2.destroyAllWindows()

Большая задержка cv2.waitKey(300), чтобы не загружать процессор. Обработка 3-4 кадров в секунду загружают i3-8145U в среднем на 15%.

Подсчет времени


Программа не должна делать записи в журнал в следующих случаях:

  • сел за компьютер на 5 сек что-то по бырику сделать;
  • вышел налить кофе или размять ноги.

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

В переменной min_time_here указано минимальное время, проведенное за компьютером, после которого стоит делать запись в журнал. Запись будет произведена после того, как человек отвлечётся от компьютера на время большее чем указано в min_time_not_here.

В коде ниже запись осуществляется, если провел минимум 5 минут за компьютером. Программа не будет учитывать то, что я отвлекаюсь меньше чем на 2 минуты.

import cv2import timeimport osfrom mtcnn.mtcnn import MTCNNcap = cv2.VideoCapture(0)path = os.path.abspath(__file__)[:-11]  # из абсолютного пути удаляем имя файлаhere, not_here = 0, 0  # секундомерыtime_here, time_not_here = 0, 0  # количество времениswitch = True  # переключатель определяет есть лицо в кадре или нетmin_time_here = 300  # минимально время проведенное за пк, после которого производится запись (в секундах) min_time_not_here = 120  # максимальное время отвлечение от компьютера которое не учитывается программой (в секундах)detector = MTCNN()try:    while cap.isOpened():        _, img = cap.read()        img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)        faces = detector.detect_faces(img)       show_face_frame()       audio_message(path, here)        if faces and switch:            not_here = 0            switch = False            if here == 0:                here = time.time()                print('вы сели за компьютер в ' + time.strftime("%H:%M:%S", time.localtime(here)))        elif not faces and not switch:            not_here = time.time()            switch = True        if not_here != 0:            time_not_here = time.time() - not_here        if here != 0 and not switch:            time_here = time.time() - here        if time_here > min_time_here and time_not_here > min_time_not_here:  # делаем запись если провели за ПК больше min_time_here            write_excel(path, here)            print('вы провели за компьютером ' + time.strftime('%H:%M:%S', time.gmtime(time.time() - here)))            time_here, time_not_here = 0, 0            here, not_here = 0, 0        elif time_not_here > min_time_not_here and  time_here < min_time_here:  # если за ПК провели меньше min_time_here, то ничего не записываем            print('запись не произведена')            time_here, time_not_here = 0, 0            here, not_here = 0, 0        cv2.waitKey(300)except KeyboardInterrupt:    if time_here > min_time_here:  # делаем запись если провели за ПК больше min_time_here        write_excel(path, here)    cap.release()    cv2.destroyAllWindows()

Если пользователь хочет выключить компьютер, для начала нужно прервать работу программы (ctrl+c) и время текущей работы попадет в журнал. Для этого используется обработчик исключений.

Запись данных в excel документ


Для работы с excel поможет замечательная библиотека openpyxl, которая одновременно считывать и записывать данные.

Каждый день программа создает новый лист с текущей датой.


На 1 листе записывается посуточная информация, в какой день сколько времени провели за компьютером.



Функция write_excel открывает документ записывает данные и сразу же закрывает.

Нельзя изменить документ через openpyxl если он уже открыт пользователем. На этот случай добавлено исключение.

def write_excel(path_excel, time_start):    wb = openpyxl.load_workbook(path_excel + r'\dnevnik.xlsx')    today = time.strftime("%d.%m.%Y", time.localtime(time.time()))    if today not in wb.sheetnames:  # если листа с сегодняшней датой еще не существует, то создаем его        wb.create_sheet(title=today)        sheet = wb[today]        sheet.column_dimensions['A'].width = 20        sheet.column_dimensions['B'].width = 20        sheet.column_dimensions['C'].width = 20        sheet.column_dimensions['D'].width = 31        sheet['A1'] = 'Начал работать за ПК'        sheet['B1'] = 'Время работы за ПК'        sheet['C1'] = 'Закончил работать'        sheet['D1'] = 'Сел за компьютер:'        sheet['D2'] = 'Всего провели за ПК времени:'        sheet = wb[today]        row = 2        all_time = 0    else:  # если лист уже создан извлекаем информацию        sheet = wb[today]        row = sheet['E1'].value  # номер строки в excel документе        all_time = sheet['E2'].value  # общее время проведенное за ПК за один день        all_time = all_time.split(':')        all_time = int(all_time[0]) * 3600 + int(all_time[1]) * 60 + int(all_time[2])  # время переводим в секунды        row = row + 2  # плюсуем шапку таблицы и новую строку    sheet['A' + str(row)] = time.strftime("%H:%M:%S", time.localtime(time_start))  # записываем время когда сели за пк    sheet['C' + str(row)] = time.strftime("%H:%M:%S", time.localtime(time.time()))  # когда вышли из за пк    seconds = time.time() - time_start  # время которое мы провели за компьютером    sheet['B' + str(row)] = time.strftime('%H:%M:%S', time.gmtime(seconds))    sheet['E1'] = row - 1  # вычитаем шапку таблицу    all_time = all_time + seconds    all_time = time.strftime('%H:%M:%S', time.gmtime(all_time))    sheet['E2'] = all_time    # заполняем первый лист    sheet_0 = wb.worksheets[0]    sheet_0['A' + str(len(wb.sheetnames))] = today    sheet_0['B' + str(len(wb.sheetnames))] = all_time    while True:  # закрываем файл        try:            wb.save(path_excel + r'\dnevnik.xlsx')        except PermissionError:            input('Сначала закройте excel файл и подтвердите нажав enter')        else:            break

Звуковое оповещение


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

def audio_message(path, here):    if here == 0:        pass    elif time.strftime('%H:%M:%S', time.gmtime(time.time()-here)) == "01:00:00":        wav = random.choice(os.listdir(path + r'\audio'))        winsound.PlaySound(path + r'\audio\\' + wav, winsound.SND_FILENAME)

Автозагрузка скрипта при включении ПК


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

C:\Users\%username%\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup

C учетом того, что батник и исходный файл хранятся в разных директориях, нельзя использовать функцию os.getcwd() так как она вернет путь до батника. Мы используем os.path.abspath(__file__)[:-11]

В будущем


Хотелось бы, что бы программа следила за моим лицом, а не за всеми, кто садиться за компьютер. Для этого будет использоваться FaceNet которая способна распознавать лица.
Также в планах разработать красивый виджет вместо некрасивой черной консоли, и что бы при выключении компьютера запись производилась автоматически, а не с помощью прерывания.
Спасибо за внимание. Если есть вопросы пишите в комментарии или на https://www.linkedin.com/in/evg-voronov/
Подробнее..

Перевод Бесшовная интеграция Microsoft Excel и Word с помощью Python

22.04.2021 16:18:43 | Автор: admin

Хотя в среднем для каждодневных задач автоматизация не требуется, бывают случаи, когда она может быть необходима.Создание множества диаграмм, рисунков, таблиц и отчётов может утомить, если вы работаете вручную. Так быть не должно.Можно построить конвейер на Python, с помощью которого Excel и Word легко интегрировать: нужно создать таблицы в Excel, а затем перенести результаты в Word, чтобы практически мгновенно получить отчёт.


Openpyxl

Встречайте Openpyxl возможно, одну из самых универсальных связок [биндингов] с Python, которая сделает взаимодействие с Excel очень простым. Вооружившись этой библиотекой, вы сможете читать и записывать все нынешние и устаревшие форматы Excel, то есть xlsx и xls.

Openpyxl позволяет заполнять строки и столбцы, выполнять формулы, создавать 2D и 3D диаграммы, маркировать оси и заголовки, а также предоставляет множество других возможностей, которые могут пригодиться.

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

Python-docx

Затем идёт Python-docx, этот пакет для Word то же самое, что Openpyxl для Excel. Если вы ещё не изучили его документацию, вам, вероятно, стоит взглянуть на неё. Python-docx без преувеличения один из самых простых и понятных мне наборов инструментов, с которыми я работал с тех пор, как начал работать с самим Python.

Python-docx позволяет автоматизировать создание документов путём автоматической вставки текста, заполнения таблиц и рендеринга изображений в отчёт без каких-либо накладных расходов. Без лишних слов давайте создадим наш собственный автоматизированный конвейер. Запустите Anaconda (или любую другую IDE по вашему выбору) и установите эти пакеты:

pip install openpyxlpip install python-docx

Автоматизация Microsoft Excel

Сначала загрузим уже созданный лист Excel, вот так:

workbook = xl.load_workbook('Book1.xlsx')sheet_1 = workbook['Sheet1']

Теперь переберём все строки в нашей таблице, чтобы вычислить и вставить значения мощности, умножив ток на напряжение:

for row in range(2, sheet_1.max_row + 1):    current = sheet_1.cell(row, 2)    voltage = sheet_1.cell(row, 3)    power = float(current.value) * float(voltage.value)    power_cell = sheet_1.cell(row, 1)    power_cell.value = power

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

values = Reference(sheet_1, min_row = 2, max_row = sheet_1.max_row, min_col = 1, max_col = 1)chart = LineChart()chart.y_axis.title = 'Power'chart.x_axis.title = 'Index'chart.add_data(values)sheet_1.add_chart(chart, 'e2') workbook.save('Book1.xlsx')
Автоматически созданная таблица ExcelАвтоматически созданная таблица Excel

Извлечение диаграммы

Теперь, когда мы сгенерировали нашу диаграмму, нам нужно извлечь её как изображение, чтобы мы могли использовать её в нашем отчёте Word. Сначала укажем точное местоположение файла Excel, а также место, где должно быть сохранено изображение диаграммы:

input_file = "C:/Users/.../Book1.xlsx"output_image = "C:/Users/.../chart.png"

Затем откройте электронную таблицу, используя следующий метод:

operation = win32com.client.Dispatch("Excel.Application")operation.Visible = 0operation.DisplayAlerts = 0workbook_2 = operation.Workbooks.Open(input_file)sheet_2 = operation.Sheets(1)

Позднее вы сможете перебирать все объекты диаграммы в электронной таблице (если их несколько) и сохранять их в указанном месте:

for x, chart in enumerate(sheet_2.Shapes):    chart.Copy()    image = ImageGrab.grabclipboard()    image.save(output_image, 'png')    passworkbook_2.Close(True)operation.Quit()

Автоматизация Microsoft Word

Теперь, когда у нас есть сгенерированное изображение диаграммы, мы должны создать шаблон документа, который в принципе является обычным документом Microsoft Word (.docx), сформированным именно так, как мы хотим: отчёт содержит шрифты, размеры шрифтов, структуру и форматирование страниц.

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

Шаблон документа Microsoft WordШаблон документа Microsoft Word

Любой сгенерированный контент, включая текст и изображения, может быть объявлен в двойных фигурных скобках {{ variable_name }}. В случае таблиц вам нужно создать таблицу со строкой шаблона со всеми включёнными столбцами, затем нужно добавить одну строку вверху и одну строку ниже со следующей нотацией:

Первая строка:

{%tr for item in variable_name %}

Последняя строка:

{%tr for item in variable_name %}

На рисунке выше имена переменных:

  • table_contents для словаря Python, в котором будут храниться наши табличные данные;

  • Index для ключей словаря (первый столбец);

  • Power, Current и Voltage для значений словаря (второй, третий и четвёртый столбцы).

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

template = DocxTemplate('template.docx')table_contents = []for i in range(2, sheet_1.max_row + 1):    table_contents.append({        'Index': i-1,        'Power': sheet_1.cell(i, 1).value,        'Current': sheet_1.cell(i, 2).value,        'Voltage': sheet_1.cell(i, 3).value        })

Далее импортируем ранее созданное в Excel изображение диаграммы и создадим другой словарь для создания экземпляров всех объявленных в документе шаблона переменных-заполнителей:

image = InlineImage(template,'chart.png',Cm(10))context = {    'title': 'Automated Report',    'day': datetime.datetime.now().strftime('%d'),    'month': datetime.datetime.now().strftime('%b'),    'year': datetime.datetime.now().strftime('%Y'),    'table_contents': table_contents,    'image': image    }

И, наконец, визуализируем отчёт с нашей таблицей значений и изображением диаграммы:

template.render(context)template.save('Automated_report.docx')

Результаты

И вот автоматически сгенерированный отчёт Microsoft Word с числами и созданной в Microsoft Excel диаграммой. Мы получили полностью автоматизированный конвейер, его можно использовать, чтобы создать столько таблиц, диаграмм и документов, сколько вам потребуется.

Автоматически сгенерированный отчётАвтоматически сгенерированный отчёт

Исходный код

import openpyxl as xlfrom openpyxl.chart import LineChart, Referenceimport win32com.clientimport PILfrom PIL import ImageGrab, Imageimport osimport sysfrom docx.shared import Cmfrom docxtpl import DocxTemplate, InlineImagefrom docx.shared import Cm, Inches, Mm, Emuimport randomimport datetimeimport matplotlib.pyplot as plt######## Generate automated excel workbook ########workbook = xl.load_workbook('Book1.xlsx')sheet_1 = workbook['Sheet1']  for row in range(2, sheet_1.max_row + 1):    current = sheet_1.cell(row, 2)    voltage = sheet_1.cell(row, 3)    power = float(current.value) * float(voltage.value)    power_cell = sheet_1.cell(row, 1)    power_cell.value = power  values = Reference(sheet_1, min_row = 2, max_row = sheet_1.max_row, min_col = 1, max_col = 1)chart = LineChart()chart.y_axis.title = 'Power'chart.x_axis.title = 'Index'chart.add_data(values)sheet_1.add_chart(chart, 'e2')  workbook.save('Book1.xlsx')######## Extract chart image from Excel workbook ########input_file = "C:/Users/.../Book1.xlsx"output_image = "C:/Users/.../chart.png"operation = win32com.client.Dispatch("Excel.Application")operation.Visible = 0operation.DisplayAlerts = 0    workbook_2 = operation.Workbooks.Open(input_file)sheet_2 = operation.Sheets(1)    for x, chart in enumerate(sheet_2.Shapes):    chart.Copy()    image = ImageGrab.grabclipboard()    image.save(output_image, 'png')    passworkbook_2.Close(True)operation.Quit()######## Generating automated word document ########template = DocxTemplate('template.docx')#Generate list of random valuestable_contents = []for i in range(2, sheet_1.max_row + 1):        table_contents.append({        'Index': i-1,        'Power': sheet_1.cell(i, 1).value,        'Current': sheet_1.cell(i, 2).value,        'Voltage': sheet_1.cell(i, 3).value        })#Import saved figureimage = InlineImage(template,'chart.png',Cm(10))#Declare template variablescontext = {    'title': 'Automated Report',    'day': datetime.datetime.now().strftime('%d'),    'month': datetime.datetime.now().strftime('%b'),    'year': datetime.datetime.now().strftime('%Y'),    'table_contents': table_contents,    'image': image    }#Render automated reporttemplate.render(context)template.save('Automated_report.docx')

Вот мой репозиторий на GitHub с шаблоном документа и исходным кодом для этого туториала. А вот ссылка на курс Fullstack-разработчик на Python, который сделает из вас настоящего универсального солдата от кодинга.

Узнайте, как прокачаться и в других специальностях или освоить их с нуля:

Другие профессии и курсы
Подробнее..

Анализ банковских выписок в формате .xlsx с помощью Python и openpyxl

12.05.2021 20:07:31 | Автор: admin
Дисклеймер

Aхтунг! Данный кейс написан новичком: приведенные решения могут быть чрезмерно грубыми, а синтаксические решения лишены изящности.

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

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

  1. Открыть нужную excel-таблицу и провести построковый и полистовой поиск значения по 1-3 ключевым словам, не заморачиваясь с инструментами самого MO Excel по сортировке и фильтру. Построковый поиск предпочтительный, чтобы позволить выводить всю интересующую транзакцию и проводить поиск по всем колонкам.

  2. Обнаружив строки с ключевыми словами - перенести их значения в новую таблицу вместе с номером соответствующей строки.

В качестве инструмента для таких операций был выбран пайтоновский модуль openpyxl.

import openpyxl from openpyxl import Workbookbankstatetment = input('Введите название файла для анализа ') #просим указать имя файла в рабочей директории#просим ввести ключевые для поиска словаobj1= input('Введите ключевое слово ') obj2= input('Введите ключевое слово ')obj3= input('Введите ключевое слово ')wb = openpyxl.load_workbook(bankstatetment) # загружаем выбранную выписку/файлresults_string_list = list() #создаем список, куда будет помещаться значение строк с ключевыми словамиresults_stringrow_list = list() #создаем список, куда будет помещаться номер строки с ключевыми словами

Как я понял, посредством openpyxl нельзя перебирать листы таблицы - в каждом случае приходится прописывать, какой лист таблицы должен стать активным и точно указать его наименование. Конечный пользователь, в результате, будет вынужден удостовериться, что в проверяемом файле все листы названы как в программе "Лист 1", "Лист 2", "Лист 3".

Поиск ключевых слов в строках реализован через перебор значений ячеек в строках с помещением обнаруженных значений в два списка. В итоге у нас получаются два списка: results_string_list для значений строк и results_stringrow_list для номеров соответствующих строк. Так как добавление содержания и номера строки идет одновременно, их индексы в каждом списке будут совпадать, т.е. не нужно будет создавать словарь.

sheet = wb['Лист1'] #делаем активным первый лист таблицы.for row in sheet: #перебор строк в листе    string = ''    for cell in row:        string = string + str(cell.value) + ' ' #определить значение в ячейках строки        string_row = str(cell.row)+ ' '#определить номер строки    if obj1 in string:         results_string_list.append (string) #добавляем значение строки в отдельный список        results_stringrow_list.append (string_row) #добавляем номер строки в отдельный список    if obj2 in string:        results_string_list.append (string)        results_stringrow_list.append (string_row)    if obj3 in string:        results_string_list.append (string)        results_stringrow_list.append (string_row)

Аналогичный код идет после установки в качестве активного второго листа страницы и далее. После приступаем к передаче найденных данных в новую таблицу:

wb = Workbook() #создаем новую таблицуws = wb.active #делаем новую таблицу активнойa1 = ws['A1']a1.value = 'Содержание транзакции' #задаем значение подзаголовка колонки "А"b1 = ws['B1']b1.value = 'Номер строки с транзакцией' #задаем значение подзаголовка колонки "B"

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

a2 = ws['A2']a3 = ws['A3']a4 = ws['A4']a5 = ws['A5']...b2 = ws['B2']b3 = ws['B3']b4 = ws['B4']b5 = ws['B5']

Далее выдергиваем каждый результат из списков посредством срезов и цикла for и "вписывая" каждое найденное значение сроки в новую ячейку колонки.

for i in results_string_list[0:1]:    a2.value = ifor i in results_string_list[1:2]:    a3.value = ifor i in results_string_list[2:3]:    a4.value = ifor i in results_string_list[3:4]:    a5.value = i...for i in results_stringrow_list[0:1]:    b2.value = ifor i in results_stringrow_list[1:2]:    b3.value = ifor i in results_stringrow_list[2:3]:    b4.value = ifor i in results_stringrow_list[3:4]:    b5.value = i...wb.save('результаты анализа.xlsx') 

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

P.S. При применении openpyxl поиск ключевых слов не был чувствителен к регистру, так что эту проблему решать не пришлось.

Подробнее..
Категории: Python , Excel , Openpyxl

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru