Действия вынесены в параметры запуска
This commit is contained in:
243
main.py
243
main.py
@ -1,4 +1,5 @@
|
||||
import os
|
||||
import argparse
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import time
|
||||
@ -132,10 +133,24 @@ class BackupManager:
|
||||
self.page.goto(self.backup_url, wait_until="networkidle")
|
||||
self.page.wait_for_timeout(10000)
|
||||
|
||||
def _refresh_backup_list(self):
|
||||
"""Обновить список бэкапов кликом по ссылке 'обновить список / статусы'"""
|
||||
self.page.click("a:has-text('обновить список / статусы')")
|
||||
self.page.wait_for_timeout(10000)
|
||||
|
||||
def _extract_timestamp(self, name: str) -> str:
|
||||
match = re.search(r"(\d{4}_\d{2}_\d{2}_\d{2}_\d{2}_\d{2})", name)
|
||||
return match.group(1) if match else ""
|
||||
|
||||
def _is_file_ready(self, backup_file: BackupFile) -> bool:
|
||||
"""Проверяет что файл готов (не в процессе создания)"""
|
||||
size = backup_file.size.lower()
|
||||
# Готовый файл: "1033513 KB"
|
||||
# В процессе: "файл формируется, 50048 KB"
|
||||
if "формируется" in size or "создаётся" in size or "progress" in size:
|
||||
return False
|
||||
return True
|
||||
|
||||
def parse_backup_table(self) -> list[BackupFile]:
|
||||
rows_data = self.page.evaluate("""() => {
|
||||
const table = document.querySelector('table.gb-ttc-2');
|
||||
@ -261,6 +276,15 @@ class BackupManager:
|
||||
# СОЗДАНИЕ БЭКАПОВ
|
||||
# =====================================================
|
||||
|
||||
def _expected_new_files(self, backup_data: bool, backup_mysql: bool) -> int:
|
||||
"""Сколько новых файлов ожидаем"""
|
||||
count = 0
|
||||
if backup_data:
|
||||
count += 1 # ftp_...
|
||||
if backup_mysql:
|
||||
count += 2 # sqldump_... (raw + zip)
|
||||
return count
|
||||
|
||||
def create_backup(
|
||||
self,
|
||||
backup_data: bool = False,
|
||||
@ -286,9 +310,11 @@ class BackupManager:
|
||||
self._go_to_backups()
|
||||
|
||||
# Запоминаем количество бэкапов до создания
|
||||
files_before = self.parse_backup_table()
|
||||
count_before = len(files_before)
|
||||
print(f"[*] Бэкапов до создания: {count_before}")
|
||||
ready_files_before = [
|
||||
f for f in self.parse_backup_table() if self._is_file_ready(f)
|
||||
]
|
||||
count_before = len(ready_files_before)
|
||||
print(f"[*] Готовых бэкапов до создания: {count_before}")
|
||||
|
||||
types = []
|
||||
if backup_data:
|
||||
@ -336,20 +362,6 @@ class BackupManager:
|
||||
max_wait=max_wait,
|
||||
)
|
||||
|
||||
def _expected_new_files(self, backup_data: bool, backup_mysql: bool) -> int:
|
||||
"""Сколько новых файлов ожидаем"""
|
||||
count = 0
|
||||
if backup_data:
|
||||
count += 1 # ftp_...
|
||||
if backup_mysql:
|
||||
count += 2 # sqldump_... (raw + zip)
|
||||
return count
|
||||
|
||||
def _refresh_backup_list(self):
|
||||
"""Обновить список бэкапов кликом по ссылке 'обновить список / статусы'"""
|
||||
self.page.click("a:has-text('обновить список / статусы')")
|
||||
self.page.wait_for_timeout(10000)
|
||||
|
||||
def _wait_for_backup_completion(
|
||||
self, count_before: int, expected_new: int, poll_interval: int, max_wait: int
|
||||
) -> bool:
|
||||
@ -402,44 +414,6 @@ class BackupManager:
|
||||
print(f" Следующая проверка через {poll_interval} сек...")
|
||||
time.sleep(poll_interval)
|
||||
|
||||
def _is_file_ready(self, backup_file: BackupFile) -> bool:
|
||||
"""Проверяет что файл готов (не в процессе создания)"""
|
||||
size = backup_file.size.lower()
|
||||
# Готовый файл: "1033513 KB"
|
||||
# В процессе: "файл формируется, 50048 KB"
|
||||
if "формируется" in size or "создаётся" in size or "progress" in size:
|
||||
return False
|
||||
return True
|
||||
|
||||
# def _check_task_status(self) -> list[str]:
|
||||
# """Проверяет статус заданий в таблице Schedule/Operation"""
|
||||
# statuses = self.page.evaluate("""() => {
|
||||
# const tables = document.querySelectorAll('table');
|
||||
# const results = [];
|
||||
|
||||
# for (const table of tables) {
|
||||
# const headers = table.querySelectorAll('th');
|
||||
# const headerTexts = Array.from(headers).map(h => h.innerText.trim());
|
||||
|
||||
# if (headerTexts.some(h => h.includes('Schedule') || h.includes('Operation'))) {
|
||||
# const rows = table.querySelectorAll('tr');
|
||||
# for (const row of rows) {
|
||||
# const cells = row.querySelectorAll('td');
|
||||
# if (cells.length >= 3) {
|
||||
# const schedule = cells[0]?.innerText?.trim() || '';
|
||||
# const server = cells[1]?.innerText?.trim() || '';
|
||||
# const operation = cells[2]?.innerText?.trim() || '';
|
||||
# if (schedule || operation) {
|
||||
# results.push(`${schedule} | ${server} | ${operation}`);
|
||||
# }
|
||||
# }
|
||||
# }
|
||||
# }
|
||||
# }
|
||||
# return results;
|
||||
# }""")
|
||||
# return statuses
|
||||
|
||||
def create_backup_mysql_only(self, wait: bool = True):
|
||||
"""Создать только бэкап базы данных"""
|
||||
return self.create_backup(
|
||||
@ -701,36 +675,144 @@ class BackupManager:
|
||||
print("\n[OK] Готово")
|
||||
|
||||
|
||||
def parse_args():
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Менеджер резервных копий 1gb.ru",
|
||||
formatter_class=argparse.RawTextHelpFormatter,
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"--action",
|
||||
choices=["create", "list", "download", "delete", "create-download"],
|
||||
default="list",
|
||||
help="""Действие:
|
||||
list — показать список бэкапов (по умолчанию)
|
||||
create — создать бэкап
|
||||
download — скачать последний бэкап
|
||||
create-download — создать и скачать
|
||||
delete — удалить старые бэкапы""",
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"--type",
|
||||
choices=["all", "data", "db"],
|
||||
default="all",
|
||||
help="""Тип бэкапа (для create/create-download/download):
|
||||
db — только база данных MySQL (по умолчанию)
|
||||
data — только данные сайта FTP
|
||||
all — данные + база""",
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"--keep",
|
||||
type=int,
|
||||
default=3,
|
||||
help="Сколько бэкапов ОСТАВИТЬ при удалении (по умолчанию: 3)",
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"--year",
|
||||
type=int,
|
||||
default=2026,
|
||||
help="За какой год удалять бэкапы (по умолчанию: 2026)",
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"--save-dir",
|
||||
type=str,
|
||||
default="F:/test_folder/MyReports",
|
||||
help="Папка для скачивания (по умолчанию: F:/test_folder/MyReports)",
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"--no-wait", action="store_true", help="Не ждать завершения создания бэкапа"
|
||||
)
|
||||
|
||||
parser.add_argument("--username", type=str, default="minzdravmo", help="Логин")
|
||||
|
||||
parser.add_argument(
|
||||
"--password", type=str, default="KB3ZS7*sv6j4zYr@bPdeFWQN38rbtQv", help="Пароль"
|
||||
)
|
||||
|
||||
parser.add_argument("--account", type=str, default="564622", help="ID аккаунта")
|
||||
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
# === ИСПОЛЬЗОВАНИЕ ===
|
||||
|
||||
if __name__ == "__main__":
|
||||
args = parse_args()
|
||||
|
||||
backup_data = args.type in ("all", "data")
|
||||
backup_mysql = args.type in ("all", "db")
|
||||
|
||||
mgr = BackupManager(
|
||||
username="minzdravmo",
|
||||
password="KB3ZS7*sv6j4zYr@bPdeFWQN38rbtQv",
|
||||
account_id="564622",
|
||||
username=args.username, password=args.password, account_id=args.account
|
||||
)
|
||||
|
||||
mgr.enable_output_log("F:/test_folder/MyReports/backup.log")
|
||||
|
||||
try:
|
||||
mgr.start()
|
||||
|
||||
if args.action == "list":
|
||||
mgr.print_backups()
|
||||
|
||||
elif args.action == "create":
|
||||
mgr.print_backups()
|
||||
print(f"\n{'=' * 70}")
|
||||
mgr.create_backup(
|
||||
backup_data=backup_data,
|
||||
backup_mysql=backup_mysql,
|
||||
wait_for_completion=not args.no_wait,
|
||||
)
|
||||
mgr.print_backups()
|
||||
|
||||
elif args.action == "download":
|
||||
mgr.download_latest(
|
||||
save_dir=args.save_dir,
|
||||
include_data=backup_data,
|
||||
include_sql_raw=backup_mysql,
|
||||
include_sql_zip=backup_mysql,
|
||||
)
|
||||
|
||||
elif args.action == "create-download":
|
||||
mgr.create_and_download(
|
||||
save_dir=args.save_dir,
|
||||
backup_data=backup_data,
|
||||
backup_mysql=backup_mysql,
|
||||
)
|
||||
elif args.action == "delete":
|
||||
groups = mgr.get_grouped_backups()
|
||||
year_groups = [g for g in groups if g.timestamp.startswith(str(args.year))]
|
||||
total = len(year_groups)
|
||||
|
||||
if total <= args.keep:
|
||||
print(
|
||||
f"[*] Бэкапов за {args.year}: {total}, оставляем: {args.keep}. Удалять нечего."
|
||||
)
|
||||
else:
|
||||
delete_count = total - args.keep
|
||||
mgr.delete_old_backups(delete_count=delete_count, year=args.year)
|
||||
|
||||
# 1. Показать текущие бэкапы
|
||||
groups = mgr.print_backups()
|
||||
print("\n" + "=" * 70)
|
||||
# groups = mgr.print_backups()
|
||||
# print("\n" + "=" * 70)
|
||||
|
||||
# 2. Создать бэкап только базы данных
|
||||
# mgr.create_backup_mysql_only(wait=True)
|
||||
|
||||
# 2. Создать бэкап и сразу скачать
|
||||
mgr.create_and_download(
|
||||
save_dir="F:/test_folder/MyReports",
|
||||
backup_data=True, # данные FTP (закомментировано)
|
||||
backup_mysql=True, # база данных
|
||||
)
|
||||
# mgr.create_and_download(
|
||||
# save_dir="F:/test_folder/MyReports",
|
||||
# backup_data=True, # данные FTP (закомментировано)
|
||||
# backup_mysql=True, # база данных
|
||||
# )
|
||||
|
||||
# 3. Показать, что удаляем и удалить
|
||||
mgr.print_deletion_plan(delete_count=1, year=2026)
|
||||
mgr.delete_old_backups(delete_count=1, year=2026)
|
||||
# mgr.print_deletion_plan(delete_count=1, year=2026)
|
||||
# mgr.delete_old_backups(delete_count=1, year=2026)
|
||||
|
||||
# Скачать только последний бэкап (без создания нового)
|
||||
# mgr.download_latest(save_dir="./backups")
|
||||
@ -751,3 +833,28 @@ if __name__ == "__main__":
|
||||
|
||||
finally:
|
||||
mgr.stop()
|
||||
|
||||
|
||||
# # Показать список бэкапов
|
||||
# python main.py --action list
|
||||
|
||||
# # Создать бэкап только БД
|
||||
# python main.py --action create --type db
|
||||
|
||||
# # Создать бэкап всего (данные + БД)
|
||||
# python main.py --action create --type all
|
||||
|
||||
# # Создать и сразу скачать БД
|
||||
# python main.py --action create-download --type db --save-dir ./backups
|
||||
|
||||
# # Скачать последний бэкап
|
||||
# python main.py --action download --type db
|
||||
|
||||
# # Удалить старые, оставить 3 за 2026 год
|
||||
# python main.py --action delete --keep 3 --year 2026
|
||||
|
||||
# # Удалить старые, оставить 1
|
||||
# python main.py --action delete --keep 1 --year 2026
|
||||
|
||||
# # Полный цикл: создать БД + скачать + удалить старые (оставить 3)
|
||||
# python main.py --action create-download --type db && python main.py --action delete --keep 3
|
||||
|
||||
Reference in New Issue
Block a user