Python в помощь инженеру ПТО

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

Всем привет.
В статье приведу немного скриптов на Python для решения вопросов с которыми иногда пересекается инженер ПТО строительной организации. Склёпал сам по мотивам информации из инета. Профи будет скучно), уровень "без диплома программиста".

На рабочем ноуте используется: Win10, Python 3.11, Office2019. Програмлю в PyScripter (нравится мне он))

Пример 1. Надо архивировать (не в смысле запаковать)

Проводятся испытания отдельных участков трубопровода, штук 50-60. На каждое заводится папка. Так как ни заказчик, ни технадзор, ни еще кто-нибудь не могут определиться, как лучше оформить это дело, то возникает ситуация когда куча документов имеет 2-3-4 варианта оформления. Значит надо скрипт, который текущий вариант закинет в архивную папку. (Ну да, "мой комьютер" или "тотал коммандер" никак с этим не справляются)):

##------------ЗАДАЧА---------------------------
## Создать папку Архив, в ней создать подпапку
## Переместить все файлы ворд/Эксель в подпапку архива

import glob, os, shutil

source_dir = os.getcwd() #Path where your files are at the moment
dst = source_dir+'/Архив/Вар2' #Path you want to move your files to

if not os.path.isdir(dst):           #создаем архив
    os.makedirs(dst)

#либо выбираем типы файлов - типа оффис
format_move_files = ['*.xls*', '*.doc*']
#либо все.
##format_move_files = ['*.*']

for fmf in format_move_files:
    files = glob.iglob(os.path.join(source_dir, fmf))
    for file in files:
        if os.path.isfile(file):
            shutil.move(file, dst)

Пример 2. Создаем папки

Собралось как-то много файлов в одной папке. И тут супостаты опять пристали со своими хотелками - каждый файл в свою папку. Нууу, лааадно. Лучше день потерять....потом за минуту само сделается. Идея такова, тем же тоталом получаю список файлов, его сохраняю в файле "папки.txt". Вот теперь его скрипт должен открыть и наштамповать папок:

import os

codirovk = 'utf-8'

#------------вар2 работает------------------
with open('папки.txt', "r", encoding=codirovk) as file1:
    # итерация по строкам
    for line in file1:
        print(line.strip())
        if not os.path.isdir(line.strip()): ##делаем папки если их нет
            os.makedirs(line.strip())


#------------вар1 работает------------------
##file1 = open('папки.txt', "r")
##
### считываем все строки
##lines = file1.readlines()
##
### итерация по строкам
##for line in lines:
####    print(line.strip())
##    if not os.path.isdir(line.strip()): делаем папки если их нет
##        os.makedirs(line.strip())
##
### закрываем файл
##file1.close

Пример 3. Достаем файлы

И вот присылают как-то папку со сметами, а они каждый файл в отдельной папке, да еще вперемешку с ведомостями всякими, да еще названия файлов пляшут, ну и их 392шт. Шо делать, шо делать - расчехляем питон. Надо достать все файлы смет с попутным переименованием их в одну папку:

# задача - достать из множества папок все файлы в одну папку (где скрипт)
# допзадача - переименовать добавляя имена подпапок

import os, shutil
import glob
import re

dst = os.getcwd()
print(dst)

# допзадача переименовать добавляя имена подпапок
for name in sorted(glob.glob(dst+'/**/*локал*.xls', recursive=True)):
# имеем D:\1 На почту\КС-6\Глава 1\01-02-01Р-01\Л0326174_Локальная смета.xls
# вырезаем эту часть D:\1 На почту\КС-6\   и заменяем косые черты на тире
    newname = name[len(dst)+1:]
    newname = re.sub(r'\\', '-', newname)
    os.rename(name, newname)

# пройтись по всем папкам каталога запуска скрипта и переместить
# файлы *локал*.xls в папку скрипта
for name in sorted(glob.glob(dst+'/**/*локал*.xls', recursive=True)):
    try:
        shutil.move(name, dst)
    except:
        pass

Пример 4. Из ворда в пдф)

Есть пару десятков файлов ворда в формате docx, надо из них pdf. Ну конечно, сча я буду сидеть каждый ручками открывать и делать сохранить как. Хотя есть еще и пдф-принтеры.....Так, ладно, питон погнали:

##*******************работает только docx

#pip install docx2pdf

from docx2pdf import convert  
import os

convert(os.getcwd()) # конвертация текущего каталога

Пример 5 с подпримером 6. Работаем с Excel. Замена текста во множестве файлов.

Мы строили, строили и наконец - построили. Но....да твою ж дивизию: ну почему когда 85% исполнительной документации уже сделано и подписано (а это примерно 1200-1500 актов скрытых работ, сделанных в эксель) вдруг какой-то заразе приходит в голову поменять подписанта из-за игр генподрядчик-субподрядчик-субсубподрядчик. И, шо, эти люди думают, радостно потирая ручки, шо я буду мучиться. Ну держитесь - где там мой удав, пора придушить воооон того....А ладно, смотрим шо есть в интернете для питона. А там много чего есть, те что приглянулись вот:

  • openpyxl - работает только с xlsx Для его использования возникла подзадача сконвертировать из xls в xlsx. Смотрим вопрос в инете. Находим pyexcel, xls2xlsx - но рушат форматирование. Находим pywin32. Делаем:

# Задача: конвертация эксель из xls в xlsx
# Все остальные библиотеки работают вкось
# Эксель должен быть установлен на компе!!!

# pip bloks
##     python -m pip install --upgrade pywin32

# import bloks
import os

import win32com.client as win32

# config bloks
path =os.getcwd()
format_files = ('.xls')

pred_prefiks_file_name = ''

# relise bloks
for root, dirs, files in os.walk(path):
    for file in files:
        if(file.endswith(format_files, 0, len(file))):
##            print(os.path.join(file))## - этот вариант выводит только имя файла
            print(file)
##        print(os.path.join(root, file))## - этот вариант выводит полный путь и имя файла
            # -------делаем через COM объект -----------------------------
            excel = win32.gencache.EnsureDispatch('Excel.Application')
            wb = excel.Workbooks.Open(os.path.join(root, file))
            wb.SaveAs(pred_prefiks_file_name+os.path.join(root, file)+'x', FileFormat = 51)    #FileFormat = 51 is for .xlsx extension
            wb.Close()                               #FileFormat = 56 is for .xls extension
            excel.Application.Quit()

input("Работа завершена. Тисни ентер.")

Далее обрабатываем openpyxl, но он тоже нарушает форматирование. Ищем дальше и находим:

  • aspose-cells -добавляет лист 'Evaluation Warning' и может еще какое ограничение содержит, так как он платный.

Практически он работает как надо. Делаю через него скрипт, а лишний лист удаляю с помощью pywin32.

## худо бедно работает как надо мне, но компонент платный

##pip install aspose-cells
##pip install aspose-cells-python
##python -m pip install --upgrade pywin32

import os
from aspose.cells import Workbook, ReplaceOptions
import win32com.client as win32

path =os.getcwd()
format_files = ('.xlsx')##'.pdf','.doc', '.docx', '.dwg', '.py' ## - закомментировать если нужны все файлы

find_str = 'Руководитель проекта ООО "Капуста" '
removent_str = 'Заместитель генерального директора по объектам ООО "Рога и копыта"'

# ВНИМАНИЕ - замена осуществляет по полным данным в ячейке. Т.е. меняется ячейка на ячейку

pred_prefiks_file_name = ''

for root, dirs, files in os.walk(path):
    for file in files:
        if(file.endswith(format_files, 0, len(file))):## - закомментировать если нужны все файлы
            print(file)
            # Load Excel file
            workbook = Workbook(file)   ##Workbook("Workbook.xlsx")
            # Create replace options
            replace = ReplaceOptions()
            # Set case sensitivity and text matching options - раздел выдает ошибку
##            replace.setCaseSensitive(False)
##            replace.setMatchEntireCellContents(False)
            # Replace text
            workbook.replace(find_str, removent_str, replace)
            # Save as Excel XLSX file
            workbook.save(pred_prefiks_file_name+file);

## этот блок удаляет последний добавляемый лист 'Evaluation Warning' - по факту просто последний
            excel = win32.gencache.EnsureDispatch('Excel.Application')
            wb = excel.Workbooks.Open(os.path.join(root, pred_prefiks_file_name+file))
            ws = wb.ActiveSheet
            try:
                excel.DisplayAlerts=False
                wb.Worksheets(wb.Sheets.Count).Delete()
            finally:
                pass
            wb.Save()
            wb.Close()
            excel.Application.Quit()

input("Работа завершена. Тисни ентер.")

Да шо ж я упускаю что-то. Как то все топорно. Стоп, эту работу лучше экселя никто не сделает, а это значит вот же решение - pywin32. И конвертировать ничего не надо было. Ищем материалы в инете, просматриваем, пробуем раз 50 с попутным улучшением, готово:

##python -m pip install --upgrade pywin32

import os
import win32com.client as win32
import re

path = os.getcwd()
format_files = ('.xlsx', '.xls')##'.pdf','.doc', '.docx', '.dwg', '.py' ## - закомментировать если что-то не надо

# ищем строку
find_str = 'Сидоров Ю.М.'
# строка для замены найденной строки
removent_str = 'Сидоров Ю.А.'

# делаем 4 замены по порядку, а можно было и через список сделать

#Сидоров Ю.М.                                     Сидоров Ю.А.
#Руководитель проекта ООО "Капуста"               Заместитель генерального директора по объектам ООО "Рога и копыта"
#Сидоров Ю.М. Приказ №15 29.03.2023               Сидоров Ю.А. Приказ № П100  от  31.09.2022
#Иванов А.А.                                      Сидоров Ю.А.

#количество строк в которых надо делать поиск
row_find = 125
#количество столбцов в которых надо делать поиск
col_find = 40

#если надо спереди имени файла добавить префикс
pred_prefiks_file_name = ''

excel = win32.gencache.EnsureDispatch('Excel.Application')

for root, dirs, files in os.walk(path):
    for file in files:
        if ((file.endswith(format_files, 0, len(file))) and (not file.endswith('~$', 0, 2))):
            # not file.endswith('~$', 0, 2) - защита от временных файлов эксель которые имена начинаются на ~$
            print('файл: ',file)
            #print(os.path.join(file))## - этот вариант выводит только имя файла
            #print(os.path.join(root, file))## - этот вариант выводит полный путь и имя файла
##            excel = win32.gencache.EnsureDispatch('Excel.Application')
            wb = excel.Workbooks.Open(os.path.join(root, file))
            print('листов: ', wb.Worksheets.Count)
            for sh_i in range(1, wb.Worksheets.Count+1):  #перебираем листы книги
                ws = wb.Worksheets(sh_i)    # идем на лист и активируем его
                ws.Activate()
                print('лист: ', sh_i)
                fp = 0
                cii2 = 0
                for row_i in range(1, row_find): #ws.Columns.Count - это вообще все строки
                    for col_i in range(1, col_find): #ws.Rows.Count - это вообще все колонки
                        if ws.Cells(row_i,col_i).Value:
                            cii2 = cii2 + 1
                            #вариант с re - заменяет внутри
                            data_from_cell = str(ws.Cells(row_i,col_i).Value) #получаем строку из данных
                            result = re.findall(find_str, data_from_cell)
                            if len(result) > 0:
                                print('в ячейке: ',row_i,',',col_i)
                                print('данные в ячейке: '+data_from_cell)
                                fp = 1
                                data_from_cell2 = re.sub(find_str, removent_str, data_from_cell, count=0)
                                print('измененные данные: '+data_from_cell2)
                                ws.Cells(row_i,col_i).Value = data_from_cell2
                                print('замена выполнена')

                            #вариант через данные эксель - совпадение по ячейке полностью - плохой вариант
    ##                        if ws.Cells(row_i,col_i).Value == find_str:
    ##                            print('найдено на листе: ', sh_i)
    ##                            print('в ячейке: ',row_i,', ',col_i)
    ##                            fp = 1
    ##                            ws.Cells(109,1).Value = removent_str
    ##                            print('замена выполнена')

                if fp == 0:
                    print('не найдено на листе: ', sh_i)
                print('пройдено ячеек: ', cii2)
            wb.Save(os.path.join(root, pred_prefiks_file_name+file))
            wb.Close()
##            excel.Application.Quit()

excel.Application.Quit()

print('')
print('----------------------------------------------')
input("Работа завершена. Тисни ентер.")

В общем как поиск/замену сделать через pywin32 не нашел. Перебираю заданную область по ячейково. Сначала всю ячейку заменял - но это отдельный текст внутри ячейки не заменишь, а только целиком. Потом через модуль re уже стало работать, как я и хотел. Работает медленнее, чем aspose, но мне как-то спокойнее)).

п.с. Так и живём в ПТО))

Источник: https://habr.com/ru/articles/761484/


Интересные статьи

Интересные статьи

Пару лет назад, как и многие другие владельцы сайтов в рунете, я столкнулся с резким ростом посетителей из социальных сетей. Поначалу это радовало, пока дело не дошло до детального изучения поведения ...
Давайте представим ситуацию, когда вам нужно установить на все виртуальные машины (агенты сервера сборки) определенный пакет Python. Но вы не можете изменить образ агента, а загрузка, к примеру из pyp...
GraphQL это современный язык запросов для получения данных с сервера. Существует большое количество документации по построению API для целого вороха платформ, но к сожале...
В прошлой статье мы рассказывали о том, как подключать к серверу отдельный накопитель для того, чтобы в случае отказа сервера или накопителя в нем, резервную копию сервера можно было пере...
Я живу в хорошем городе. Но, как и во многих других, поиск парковочного места всегда превращается в испытание. Свободные места быстро занимают, и даже если у вас есть своё собственное, друзья...