Используйте python для автоматизации офисной рутины
В повседневной офисной работе вам часто приходится что-то делать с кучей файлов. Разархивируйте, переместите, переименуйте, обновите, снова заархивируйте и отправьте или загрузите на FTP. Все это просто сделать, но вам потребуется очень много времени, чтобы повторить их вручную с десятками или сотнями файлов.
К счастью, вы можете использовать языки программирования для автоматизации этих повторяющихся задач. Python - идеальный выбор, потому что его легко установить на компьютере, и даже новичок в вычислениях может создать программу с помощью небольших проб и ошибок. Python - это универсальный язык программирования, с которым вы можете решить практически любую проблему.
Давайте рассмотрим довольно распространенную задачу во многих отраслях. Мы будем:
- Разархивируйте группу файлов
- Обновите их содержимое - в нашем примере мы изменим содержимое узла XML.
- Снова заархивируйте результат - используя
zipfile
иshutil
libraries
Вы можете выполнить это упражнение в блокноте github - Unzip_Update_Zip_full.ipynb.
Установка Python
Есть несколько способов настроить python на свой компьютер. Мне лично нравится пользоваться Anaconda и Jupyter notebook. Вы загружаете и устанавливаете пакет conda, призванный упростить управление средой Python со всеми возможными улучшениями, и запускаете ноутбук, который является важной частью пакета.
В записной книжке вы можете запустить отдельную ячейку, содержащую одну или несколько строк кода, и сразу увидеть результаты. Такой подход идеально подходит для прототипирования. С помощью Google, stackoverflow и руководств, например здесь, на medium, вы можете быстро комбинировать фрагменты кода, необходимые для того, что вам нужно сделать.
Распаковка
Давайте посмотрим, как вы подойдете к задаче по распаковке файла в Python. Просто зайдите в Google и введите unzip python. Он быстро выводит список результатов, и вы выбираете, скажем, один из крупнейших сайтов вопросов и ответов - Распаковка файлов stackoverflow в Python. Вы узнаете, как это сделать, в трех строчках кода:
import zipfile
with zipfile.ZipFile(path_to_zip_file, 'r') as zip_ref:
zip_ref.extractall(directory_to_extract_to)
Вам import
библиотека, необходимая для работы с .zip
файлами - zipfile
. Это позволяет вам использовать его функции и методы для распаковки архивов и их повторного заархивирования.
Сначала вы открываете архив для чтения с помощью zipfile.ZipFile(path_to_zip_file, 'r')
, а затем извлекаете содержимое пакета в каталог zip_ref.extractall(directory_to_extract_to)
.
Я использовал обозначение with
, чтобы убедиться, что архив открыт, выполняется действие, а затем архив закрывается, чтобы его содержимое было освобождено из памяти. Это предотвращает утечку памяти в случае обработки сотен или тысяч файлов.
Распаковка папки с большим количеством файлов
Чтобы распаковать файл на Python, вы используете три строки кода. Чтобы распаковать кучу файлов, нужно добавить еще несколько строк. Вы должны идентифицировать zip-файлы в папке и передать их описанной выше процедуре.
Библиотека os
позволяет одновременно получать содержимое папки os.listdir()
и комбинировать имена папок и файлов с помощью os.path.join(folder,file)
. Listdir возвращает как файлы, так и подпапки. Вы можете добавить file.endswith(".zip")
, чтобы идентифицировать только архивы.
В качестве альтернативы вы можете использовать
os.path.splitext()
. Второй вывод - это расширение файла.
Зная все файлы в папке, вы можете применить предыдущий код, чтобы распаковать их. Опять же, вы можете перебирать файлы и разархивировать каждый из них или обернуть разархивирование в функцию, которая вызывается в однострочном исчерпывающем обозначении.
def unzip(folder: str, file: str, folder_to_extract: str) -> list: """unzips a file in a folder into folder_to_extract returns a list of files in the zip archive""" with zipfile.ZipFile(os.path.join(folder,file), 'r') as zip_ref: zip_ref.extractall(folder_to_extract) return zip_ref.namelist() # applying a function to the output can be squeezed into the list comprehension [unzip(folder, f, "temp") for f in os.listdir(folder) if f.endswith(".zip")]
Обновите извлеченный XML
После того, как мы извлекли XML-файл в папку temp
, мы можем работать с ним. Python содержит библиотеку xml.etree для обработки файлов XML. В нашем случае мы знаем, что zip-архив содержал один XML-файл a.xml
, хотя вы всегда можете перечислить все файлы в архиве, используя - zip_ref.namelist()
.
Чтобы обновить XML-файл, вам необходимо импортировать древовидную библиотеку и загрузить XML-документ.
from xml.etree import ElementTree as ET # parse the XML document into a variable tree = ET.parse(path) # get the root emelement containing all the XML nodes root = tree.getroot()
Помните, что любая переменная, производная от
tree
, является ссылкой. Когда вы обновляете содержимое этих переменных, вы также обновляетеtree
.
Допустим, мы хотим обновить узел <id>...</id>
в нашем XML. Сначала мы должны его найти. В библиотеке etree есть несколько методов поиска узлов XML.
.find()
обнаружил первое появление элемента XML.findall()
перечислить все появления подэлемента
Оба метода принимают имя элемента или его можно найти с помощью xpath
. Xpath - это своего рода адрес внутри XML для поиска нужного элемента. Когда узел обнаружен, используется .text
аргумент для получения значения, записанного между тегами.
# in the <data> find the <id>...</id> node and show its content (.text) id = root.find("id").text
Наш идентификатор состоит из трех частей, разделенных подчеркиванием «_»:
- Префикс
- Версия
- Дата
Один из XML имеет идентификатор - test_001_20201026
. .text
возвращает значения в виде строки, и вы можете применить .split("_")
функцию, чтобы разбить текст на детали.
[In]: split_id = id.split("_") print(split_id) [Out]: ["test","001","20201026"]
Результатом является список Python, который можно легко обновлять поэлементно. Сначала меняем префикс split_id[0] = new_prefix
. Потом обновляем версию.
split_id[0] = new_prefix split_id[1] = "{:03d}".format(new_version)
Мы использовали "{:03d}".format(new_version)
, чтобы добавить ведущие нули до 3 символов, если необходимо, чтобы превратить 1
в 001
.
Обновленные значения могут быть объединены в одну строку с помощью .join("_")
, и исходный компонент XML может быть обновлен с его помощью:
root.find("id").text = "_".join(split_id)
Как я уже упоминал, любое обновление переменной, полученной из tree
, также обновляет tree
. Мы достигли желаемого обновления XML, и нам нужно только экспортировать его, используя tree.write(output_path)
.
Давайте посмотрим на полный код обновления XML:
Заархивируйте обновленный XML
Теперь обновленный a.xml
лежит в папке temp
. Нам нужно только заархивировать его и поместить этот архив в processed
folder. Давайте сначала создадим папку вывода, если она не существует. Мы будем использовать Path
из pathlib
библиотеки.
# create the output folder if it doesn't exists Path(output_folder).mkdir(parents=True, exist_ok=True)
Затем мы упаковываем XML в zip-архив, используя zipfile
lib. Теперь надо открыть архив для записи 'w'
. Тогда воспользуемся ссылкой на этот архив и .write(path_to_file, name_of_this_file)
.
Если вы не укажете второй параметр
name_of_the_zipped_file
, будет заархивирован весь путь, включая папки и подпапки.
Если вы не знаете имя файла, os
библиотека может помочь вам с ее os.path.basename()
функцией.
with zipfile.ZipFile(output_path, 'w') as myzip: myzip.write(path_to_processed_xml, os.path.basename(path_to_processed_xml))
Иногда вам нужно также упаковать папки и файлы. В нашем примере Folder_001_20201101.zip
содержит файл и другие файлы в папке.
- folder_A / a.xml
- efg.txt
В таком случае было бы слишком полно использовать zip-файл, но у вас есть альтернатива в shutil.make_archive(output_folder, format, folder_to_pack)
. Этот метод только архивирует содержимое folder_to_pack
и помещает результат в output_folder
. Вы можете выбирать из форматов zip
, tar
, gztar
, bztar
, xztar
.
Положил все это вместе
Теперь мы знаем все составляющие процесса:
- разархивировать несколько архивов из папки во временную папку
- обновил каждый из распакованных файлов
- и снова заархивировал этот обновленный файл в архив
В этом последнем упражнении мы должны сделать несколько небольших настроек. Мы будем использовать имя исходного архива, обновлять его, а также обновлять содержимое всех содержащихся XML-файлов. Причина в том, что в архиве может быть два или более XML-файла, каждый с разными идентификаторами, и мы заархивируем их все обратно в обновленный zip-архив (который не может иметь двух разных имен).
Полный код можно найти в этой записной книжке - Unzip_Update_Zip_full.ipynb
Вывод
В этом простом руководстве вы увидели мощь Python (или любого другого языка программирования). С помощью нескольких строк кода вы можете автоматизировать задачи, выполнение которых вручную заняло бы много времени. Я использую этот принцип, когда решаю, стоит ли тратить время на кодирование:
Если однажды вы сделаете что-то маленькое, сделайте это вручную. Если он большой, вы повторяете одну и ту же операцию со многими элементами или думаете, что вам придется сделать это в будущем - автоматизировать с помощью языка программирования.
Операция в этом примере может иметь множество вариаций. Возможно, вы захотите обновить другой узел XML. ZIP, возможно, содержит файлы CSV. Вы скорее обновите дату, а не префикс и версию. Возможно, вам потребуется изменить ввод - например, увеличьте версию на 1 или добавьте неделю к дате.
Все это возможно с небольшими изменениями кода. Вы также можете просмотреть полный пример в блокноте jupyter на Github.
Я надеюсь, что вам понравился этот учебник по архивированию и обработке XML, и что вам нравится то, чего вы можете достичь с помощью python. Возможности безграничны.
Other articles: * Plotly Express complete tutorial * Very illustrative highlighted line chart * Plotly Histogram - Complete Guide * Everything you wanted to know about Kfold train-test split * How to turn a list of addreses into a map