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

У нас появилась необходимость отслеживать изменения в 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)

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

Для работы с кодом на Python рекомендую использовать дистрибутив Anaconda (включает интерпретатор Python и среду разработки Spyder IDE) или отдельно среду разработки Spyder IDE, которая включает структуру проекта и анализ кода.

Комментарии (7)


  1. alinkagalichina
    00.00.0000 00:00
    +2

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

    1. Скажите, зачем нужно было писать свою vcs? Чем не подошли svn или git?

    2. Не думали ли вы о ведении документации в чём-то отличного от word? Например ascidoc или latex? Git и svn смогут показать не только кто и когда менял, но и что именно изменено.


    1. s-r-grass Автор
      00.00.0000 00:00

      Код с почтой для примера, поэтому у себя просто пишу в текстовый файл.

      1. git вроде не отслеживает изменения в docx? Разве нет? Прочитал об этом тут https://qna.habr.com/q/302959?ysclid=lewco77q2q270712130

      2. Спасибо, подумаю.


      1. garwall
        00.00.0000 00:00
        +3

        для гита всегда можно написать хэндлер, который будет выдергивать, что нам надо.
        git config --global diff.docx.textconv docx2txt, как например.


      1. Johan_Palych
        00.00.0000 00:00

        Может включите аудит доступа к файлам?
        gpedit.msc
        Конфигурация компьютера - Конфигурация Windows - Параметры безопасности - Локальные политики - Политика аудита - Аудит доступа к объектам(Успех и Отказ) - Настраиваем аудит для файлов и папок


        1. s-r-grass Автор
          00.00.0000 00:00
          +1

          Это было первым, что я предложил, но в нашем случае, этот вариант не подходил


  1. Blademoon05
    00.00.0000 00:00

    Почему бы просто не включить отслеживание изменений в самом Word?


    1. s-r-grass Автор
      00.00.0000 00:00

      Это сетевая папка, в которую ходит пара сотен компьютеров