Excel/PowerQuery/VBA, Python, Программирование

Применяем Python и VBA для автоматизированного сохранения документов MS Office в другом формате

Время прочтения: 5 мин.

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

Однажды нам с коллегами преградила путь к выполнению задачи проблема. Не будем вдаваться в подробности, но суть её заключалась в том, что очень большое количество документов Word, которые предстояло обработать, хранилось в расширении “.xml”, в то время как нам нужно было “.docx”. Такое могло случиться и, например, с таблицами Excel, когда бы потребовалось обновить формат “.xls” до “.xlsx”. Разумеется, сохранение большого количество файлов в нужном формате вручную отняло бы много времени, к тому же, выполняя такую долгую и монотонную работу, можно сбиться и пропустить какой-нибудь важный документ. А если с подобной ситуацией придётся столкнуться в будущем снова, и не раз? Исходя из этого мы приняли решение автоматизировать данный процесс, используя язык программирования Python и VBA (Visual Basic for Applications).

Касаемо MS Word выглядит это следующим образом: программа на Python в цикле открывает файлы документов, находящиеся в нужной папке, а при открытии документа срабатывает макрос VBA, который сохраняет его с расширением “.docx” в папку, созданную ранее также Python. После этого документ закрывается.

Полный код Python представлен далее:

1	import os
2	import subprocess
3	
4	
5	def convert():   
6	    #os.startfile('WINWORD')
7	
8	    input_path = input("Введите путь к файлам: ")
9	    
10	    root, input_folder = os.path.split(input_path)  
11	    output_folder = input_folder + " converted"    
12	    output_path = os.path.join(root, output_folder)
13	    
14	    if not os.path.exists(output_path):       
15	        os.mkdir(output_path)
16	    
17	    for file in os.scandir(input_path):        
18	        if file.name.split('.')[-1] in ["doc", "xml", "rtf"]:            
19	            subprocess.call(os.path.join(input_path, file.name), shell=True)
20	
21	
22	if __name__ == "__main__":    
23	    convert()

Для работы программы нам необходимо импортировать два модуля: os и subprocess. Основной код находится в функции convert(). Строка 8 отвечает за запрос у пользователя пути к папке с документами, которые требуется сохранить в другом формате. В строках 10 – 15 происходит создание папки для сохранения. Далее в строке 17 запускается цикл, перебирающий исходные документы. В цикле мы проверяем, что данный файл имеет именно тот формат, который нас интересует (здесь помимо xml добавлены doc и rtf). Наконец, открываем документ Word (строка 19), и далее очередь VBA.

Но прежде чем писать код, необходимо проделать несколько действий. Сначала запускаем Word и открываем вкладку «Разработчик»: Файл – Параметры – Настроить ленту, в области «Основные вкладки» ставим галочку рядом с «Разработчик» (для Word 2017).

Далее переходим в появившуюся вкладку и в разделе «Код» нажимаем «Безопасность макросов». Здесь во вкладке «Параметры макросов» нужно выбрать «Включить все макросы…». Подготовка завершена.

Теперь также в разделе «Код» нажимаем на «Visual Basic», откроется окно «Microsoft Visual Basic for Applications…».

Далее в окне «Project – Normal» потребуется два раза щёлкнуть по «ThisDocument» во вкладке «Normal – Microsoft Word Objects» и в открывшемся окне ввести код:

1	Private Sub Document_Open()
2	
3	    Dim trigger As Boolean
4	    trigger = True                                                                
5	    If Not trigger Then
6	        Exit Sub
7	    End If
8	
9	    Dim dot_pos&, file$, file_type$, o_path$   
10	                               
11	    file = ActiveDocument.name                                                
12	    dot_pos = InStrRev(file, ".")                                             
13	    file_type = Right$(file, Len(file) - dot_pos)   
14	                          
15	    If file_type = "docx" Then                                                
16	        Exit Sub
17	    End If
18	
19	    file = Left$(file, dot_pos - 1)                                           
20	    o_path = ActiveDocument.path & " converted" & "\" & file & ".docx" 
21	       
22	    Main (o_path)
23	
24	End Sub
25	
26	Private Sub Main(fullPath$)
27	    ActiveDocument.SaveAs fullPath$, wdFormatDOCX                             
28	    Application.Quit
29	End Sub

Функция Document_Open() срабатывает сразу при открытии документа. Первым делом проверяется значение булевой переменной trigger – если переменная установлена в True, макрос продолжит выполняться, иначе выполнение завершится. В строке 9 объявляем несколько переменных (& — целочисленные, $ — строковые). Далее в переменной file сохраняем имя документа, в dot_pos – позицию точки, в file_type – формат файла документа. Делаем небольшую проверку, что если формат документа “.docx”, то выполнение макроса также будет завершено. Это сделано для того, чтобы сразу после обработки всех документов можно было открыть какой-то из сохранённых, и макрос не пытался снова сохранить этот документ, что, кстати, вызовет ошибку.

В переменную o_path записываем полный путь, по которому нужно сохранить документ, и затем вызываем другую функцию main(), которая в качестве параметра принимает сформированный путь и непосредственно сохраняет документ, и закрывает его. Здесь завершается первая итерация, далее Python открывает следующий документ и всё продолжается, пока не будет сохранён последний документ.

Таким образом, использование Python в связке с VBA позволило сократить время, которое нужно потратить на сохранение большого количества документов Word в другом формате, в разы. Более того, данный метод применим не только для перезаписи документов Word, он также работает для файлов других программ MS Office, таких как книг Excel и даже презентаций Power Point, с учётом некоторых отличий в названиях объектов. В «Ворде» объект открытого документа называется ActiveDocument, в «Экселе» — ActiveWorkbook, а в Power Point — ActivePresentation. Также будут отличаться значения параметра FileFormat – в статье для Word мы использовали wdFormatDOCX, для Excel это может быть xlOpenXMLWorkbook.  Список доступных форматов всегда можно посмотреть на сайте docs.microsoft.com. Что касается кода Python – его изменять не требуется вовсе. Надеемся, что наш опыт будет полезен для вас. Спасибо за внимание!

Советуем почитать