Отслеживаем изменения в doc и docx при помощи Python

2db46055b8404bbefcd28f38cca1c047

Здравствуйте, уважаемые коллеги! Прошу не судить строго, так как это моя первая статья.

У нас появилась необходимость отслеживать изменения в doc и docx файлах с фиксацией имени пользователя, который внес эти изменения. Сами файлы находятся в расшаренной папке (да, да, общие папки это зло, но убедить у меня не получилось) и необходимо знать кто внес изменения. Подробнее под катом.

Сами изменения в файлах будем отслеживать при помощи watchdog (pip install watchdog).

Код для отслеживания всех изменений:

# Для отслеживания изменений
import time
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler

# Отслеживаем изменения
class Watcher:
    def __init__(self, path):
        self.observer = Observer()
        self.path = path

    def run(self):
        event_handler = Handler()
        self.observer.schedule(event_handler, self.path, recursive=True)
        self.observer.start()
        try:
            while True:
                time.sleep(1)
        except:
            self.observer.stop()
            print("Error")

        self.observer.join()


class Handler(FileSystemEventHandler):
    @staticmethod
    def on_any_event(event):
        if event.is_directory:
            return None
        print(
            "[{}] noticed: [{}] on: [{}] ".format(
                time.asctime(), event.event_type, event.src_path
            )
        )
        

if __name__ == "__main__":
    w = Watcher('C:\\Users\\user\\Desktop\\')
    w.run()

Такой код позволяет отслеживать изменения во всех файлах (не показывая кто изменил) на рабочем столе пользователя. Естественно, папку «C:\Users\user\Desktop\» эту указал для примера.

Пример вывода:

[Mon Dec 5 14:32:37 2022] noticed: [modified] on: [C:\Users\user\Desktop\Документ Microsoft Word.docx]

Тут нет информации о том, кто изменил файл. Эту информацию можно получить из самого docx файла.

Нам нужно отслеживать изменения именно в doc и docx файлах, поэтому переделаем код:

# -*- coding: utf-8 -*-

# Для атрибутов файла
import docx
# Для отслеживания изменений
import time
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler

# Отслеживаем изменения
class Watcher:
    def __init__(self, path):
        self.observer = Observer()
        self.path = path

    def run(self):
        event_handler = Handler()
        self.observer.schedule(event_handler, self.path, recursive=True)
        self.observer.start()
        try:
            while True:
                time.sleep(1)
        except:
            self.observer.stop()
            print("Error")

        self.observer.join()


class Handler(FileSystemEventHandler):
    @staticmethod
    def on_any_event(event):
        # if event.is_directory:
        #     return None
        # print(
        #     "[{}] noticed: [{}] on: [{}] ".format(
        #         time.asctime(), event.event_type, event.src_path
        #     )
        # )
        
        # Получаем атрибуты файла
        if '.tmp' in event.src_path:
            return None
        try:
            document = docx.Document(docx = event.src_path)
            core_properties = document.core_properties
            print(f'{core_properties.last_modified_by} в {core_properties.modified} модифицировал файл {event.src_path}')
        except:
            pass

if __name__ == "__main__":
    w = Watcher('C:\\Users\\user\\Desktop\\')
    w.run()

В данном примере изменения просто печатаются в консоль при помощи строки:

print (f'{core_properties.last_modified_by} в {core_properties.modified} модифицировал файл {event.src_path}')

Пример вывода:

Иванов Иван Иванович в 2022–12–05 07:35:00 модифицировал файл C:\Users\user\Desktop\Документ Microsoft Word.docx

Для журналирования можно использовать простейшую запись в файл:

f = open('change-doc.log','w')  # открытие в режиме записи
f.write(f'{core_properties.last_modified_by} в {core_properties.modified} модифицировал файл {event.src_path}\n')  # запись в файл
f.close()  # закрытие файла

Или можно отправлять изменения на почту (если это востребовано):

import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
 
fromaddr = "test@mail.ru"
toaddr = "test2@mail.ru"
mypass = "password"
 
msg = MIMEMultipart()
msg['From'] = fromaddr
msg['To'] = toaddr
msg['Subject'] = f'Модифицирован файл {event.src_path}'
 
body = f'{core_properties.last_modified_by} в {core_properties.modified} модифицировал файл {event.src_path}'
msg.attach(MIMEText(body, 'plain'))
 
server = smtplib.SMTP_SSL('smtp.mail.ru', 465)
server.login(fromaddr, mypass)
text = msg.as_string()
server.sendmail(fromaddr, toaddr, text)
server.quit()

Также приведу полный список атрибутов docx файла, которые можно таким же образом получить:

file_name = 'C:\\Users\\user\\Desktop\\123.docx'

document = docx.Document(docx = file_name)
core_properties = document.core_properties
print('author', core_properties.author)
print('created', core_properties.created)
print('last_modified_by', core_properties.last_modified_by)
print('last_printed', core_properties.last_printed)
print('modified', core_properties.modified)
print('revision', core_properties.revision)
print('title', core_properties.title)
print('category', core_properties.category)
print('comments', core_properties.comments)
print('identifier', core_properties.identifier)
print('keywords', core_properties.keywords)
print('language', core_properties.language)
print('subject', core_properties.subject)
print('version', core_properties.version)
print('keywords', core_properties.keywords)
print('content_status', core_properties.content_status)

Спасибо за внимание!!!

© Habrahabr.ru