From ea7bdb426ca9b9b7bbd7f42eae764c622e2a8213 Mon Sep 17 00:00:00 2001 From: admin Date: Mon, 6 Apr 2026 22:48:19 +1000 Subject: [PATCH] =?UTF-8?q?=D0=BF=D1=80=D0=BE=D0=B1=D1=83=D0=B5=D0=BC=20?= =?UTF-8?q?=D0=B2=D1=8B=D0=B3=D1=80=D1=83=D0=B7=D0=BA=D1=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main.py | 102 ++++++++++++++++++++++++++++++++++++++++------- requirements.txt | Bin 1666 -> 0 bytes 2 files changed, 88 insertions(+), 14 deletions(-) diff --git a/main.py b/main.py index 502b8d5..1a0aaf3 100644 --- a/main.py +++ b/main.py @@ -5,9 +5,12 @@ import os import subprocess import time from datetime import datetime as dt -from datetime import datetime +from datetime import datetime, timedelta import random +from rarfile import RarFile +import tempfile + # Сторонние библиотеки (third-party) from apscheduler.schedulers.asyncio import AsyncIOScheduler from bs4 import BeautifulSoup @@ -51,9 +54,8 @@ scheduler = AsyncIOScheduler() logging.basicConfig(filename="app.log", level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s") logger = logging.getLogger(__name__) - # Инициализация таблицы статуса парсинга -wp.create_table() +# wp.create_table() app.add_middleware( CORSMiddleware, @@ -249,7 +251,6 @@ def gpt_response_message(content, ist_number=1): # except subprocess.CalledProcessError: # print(f"Не удалось перезапустить сервес {service_name}") - # Общие функции проверки ссылок def check_url(url): print(url) @@ -323,7 +324,7 @@ def update_bd_and_create_document(response_text, article_date, url, parsed_at, o logger.info(f"Ошибка при обработке ответа GPT: {ex}") #Функции start первого источника (газета) -def start_pars_one_istochnik(data_init): +def start_pars_one_istochnik(data_init=""): if data_init != ['']: current_day = data_init[0] current_month = data_init[1] @@ -396,8 +397,7 @@ def start_pars_two_istochnik(): # Функции для автоматического запуска def scheduled_parser_1(): - istochnik = "" # пустая строка = текущая дата - start_pars_one_istochnik(istochnik.split(".")) + start_pars_one_istochnik() def scheduled_parser_2(): start_pars_two_istochnik() @@ -407,7 +407,7 @@ class ParserOneRequest(BaseModel): @app.post("/parser_1", summary="Запуск процесса парсинга первого источника") async def process_data(data: ParserOneRequest, background_tasks: BackgroundTasks): - istochnik = data.time.split(".") + istochnik = data.time.split("-") background_tasks.add_task(start_pars_one_istochnik, istochnik) return {"message": "Процесс парсинга 1 источника запущен"} @@ -435,17 +435,12 @@ def set_settings(settings: wp.Source): def delete_task(task_id: int): return print(wp.delete_task(task_id)) -# @app.get("/file_download", summary="Метод для скачивания файла") -# async def download_file(path: str, title: str): -# path = f"./{path}/{title}.docx" #os.path.abspath(path) -# return FileResponse(path=path, filename=f'{title}.docx', media_type='multipart/form-data') - @app.get("/file_download", summary="Метод для скачивания файла") async def download_file(path: str, title: str): file_name = f"{title}.docx" file_path = os.path.join(DOCUMENTS_DIR, path, file_name) logger.warning(f"Файл: {file_path}") - + # Проверяем существование файла if not os.path.exists(file_path): logger.warning(f"Файл не найден: {file_path}") @@ -464,6 +459,85 @@ async def download_file(path: str, title: str): logger.warning(response) return response +class DownloadRange(BaseModel): + data_start: str + data_finish: str + +@app.post("/download_all", summary="Скачать все файлы за период") +async def download_all(dates: DownloadRange): + + date_start = dates.data_start + date_finish = dates.data_finish + # Парсим даты + try: + start_date = datetime.strptime(date_start, "%Y-%m-%d") + finish_date = datetime.strptime(date_finish, "%Y-%m-%d") + except ValueError: + return {"error": "Неверный формат даты. Используйте YYYY-MM-DD"} + + if start_date > finish_date: + return {"error": "Дата начала не может быть позже даты окончания"} + + all_files = [] + + # Собираем файлы за каждый день + current_date = start_date + while current_date <= finish_date: + date_path = current_date.strftime("%Y/%m/%d") + full_dir_path = os.path.join(DOCUMENTS_DIR, date_path) + logger.info(f"Проверяем путь: {full_dir_path}") + + # if os.path.exists(full_dir_path): + for file in os.listdir(full_dir_path): + if file.endswith('.docx'): + all_files.append(os.path.join(full_dir_path, file)) + + current_date += timedelta(days=1) + + logger.info(f"Найдено файлов: {len(all_files)}") + + # print(all_files) + if not all_files: + return {"error": "Файлы не найдены за указанный период", "date_start": date_start, "date_finish": date_finish} + + # Создаём архив во временной директории + archive_name = f"documents.rar" + archive_path = os.path.join(tempfile.gettempdir(), archive_name) + + try: + with RarFile(archive_path, 'w') as rar: + for file_path in all_files: + rar.write(file_path, os.path.basename(file_path)) + except Exception as e: + logger.error(f"Ошибка создания архива: {e}") + return {"error": f"Ошибка создания архива: {e}"} + + logger.info(f"Архив создан: {archive_path}") + + # Возвращаем архив + response = FileResponse( + path=archive_path, + filename=archive_name, + media_type="application/x-rar-compressed" + ) + response.headers["Access-Control-Allow-Origin"] = "*" + response.headers["Access-Control-Allow-Methods"] = "GET, OPTIONS" + response.headers["Access-Control-Allow-Headers"] = "Content-Type" + + # Удаляем архив после отправки + # Примечание: FileResponse сам отдаёт файл, удаление нужно делать после + @response.streaming_callback + async def cleanup(): + await response.body_send() + try: + if os.path.exists(archive_path): + os.remove(archive_path) + logger.info(f"Архив удалён: {archive_path}") + except Exception as e: + logger.warning(f"Не удалось удалить архив: {e}") + + return response + @app.get("/logs") def get_logs(): with open("app.log", "r") as file: diff --git a/requirements.txt b/requirements.txt index df4020799c54a210f1afaef5e48eff396a7c86aa..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644 GIT binary patch literal 0 HcmV?d00001 literal 1666 zcmZXVL2uJg5QN_uiJy|Hc9PN_IB?;BgjA^qj#cV5sUgI{P9W)z2j<)HvkjH?;>tU_ zJ3G5?`{(y6?esM1kXAZR=`qc8npCCtdM?vNoJD$@-U#s;dr0TBmtQyF--S=cpHr=9 z#9HWkk;?eR`XH}WIx1_O)_QLhqtSaWfUt?$^2K35}aqnN9R1A=^bUkwN{Vxdl~_H}noVc{!WopG&bU37Ba*I}h=%cGTMOz@rlUMovxfim;xE1lWuY0|H-`bJ=PWqaMHN)htB zdD6`=M>zL&Fw?%L*d58UOcd8@%zfW0GXlL3K2QFw(0Bbjj1$K_wsu52=ngc}C2t4M zA2CMd==KlQ&o)49_m;}RnA!iBS=>4LJk`p1^FHWQrza*yybdir>uoc zdXW85wv#w<-zvSqasS7O@*bn}8`a3Wi@gS#4YnI%j~i*~bKhrRYT=8A6#!pEHuK?D zFafnT;5?#Qojd_Y-3|K6-I`_{XXJ}=F==d`qxfd!=!Q4Ji@e#&7dq3M#>86N5kakJ z*Qyh!V-?v~#54Lsy48fR2l)@duFg9+-?7Youd10~@^94lnW`iM^L!qv<*wgE5B~xJ CZ15)l