refactor: Move GAS Pravosudie scraper into standalone page 'Жатва ГАС'

This commit is contained in:
Admin 2026-07-03 10:54:44 +04:00
parent 48b23f5980
commit 2f92e81ec5
4 changed files with 131 additions and 79 deletions

View file

@ -842,6 +842,10 @@ async def get_infra_page(request: Request, username: str = Depends(get_current_a
return templates.TemplateResponse(request=request, name="infra.html", context={"username": username, "speedtests": speedtests}) return templates.TemplateResponse(request=request, name="infra.html", context={"username": username, "speedtests": speedtests})
@app.get("/sudrf")
async def sudrf_page(request: Request, username: str = Depends(get_current_admin)):
return templates.TemplateResponse(request=request, name="sudrf.html", context={"username": username})
@app.post("/api/infra/run_speedtest") @app.post("/api/infra/run_speedtest")
async def api_run_speedtest(username: str = Depends(get_current_admin)): async def api_run_speedtest(username: str = Depends(get_current_admin)):
script_path = "/app/infra/speedtest_monitor.py" if os.path.exists("/app/infra/speedtest_monitor.py") else "/home/matrixhasyou/infra/speedtest_monitor.py" script_path = "/app/infra/speedtest_monitor.py" if os.path.exists("/app/infra/speedtest_monitor.py") else "/home/matrixhasyou/infra/speedtest_monitor.py"

View file

@ -70,6 +70,11 @@
<i class="bi bi-calendar3"></i> СОБЫТИЯ <i class="bi bi-calendar3"></i> СОБЫТИЯ
</a> </a>
<div class="mt-3 px-3"><small class="text-success opacity-50 text-uppercase" style="font-size: 0.6em;">Юрист</small></div>
<a class="nav-link {% block nav_sudrf %}{% endblock %}" href="/sudrf">
<i class="bi bi-bank text-danger"></i> ЖАТВА ГАС
</a>
<div class="mt-3 px-3"><small class="text-success opacity-50 text-uppercase" style="font-size: 0.6em;">Система</small></div> <div class="mt-3 px-3"><small class="text-success opacity-50 text-uppercase" style="font-size: 0.6em;">Система</small></div>
<a class="nav-link {% block nav_infra %}{% endblock %}" href="/infra"> <a class="nav-link {% block nav_infra %}{% endblock %}" href="/infra">
<i class="bi bi-cpu"></i> ИНФРАСТРУКТУРА <i class="bi bi-cpu"></i> ИНФРАСТРУКТУРА

View file

@ -78,30 +78,6 @@
</div> </div>
</div> </div>
</div> </div>
<div class="col-md-6">
<div class="card bg-dark border-danger">
<div class="card-header text-danger">ГАС ПРАВОСУДИЕ (СУДЕБНЫЙ АРХИВ)</div>
<div class="card-body">
<div class="d-flex justify-content-between align-items-center mb-3">
<button id="runSudrfParserBtn" class="btn btn-outline-danger flex-grow-1 me-2">
<i class="bi bi-play-circle"></i> ЗАПУСТИТЬ ЖАТВУ СУДОВ
</button>
<div id="sudrfStatusBadge" class="badge bg-secondary p-2">СТАТУС: НЕИЗВЕСТНО</div>
</div>
<div class="d-flex justify-content-between align-items-center mb-3">
<a href="http://192.168.10.116:6080/vnc.html" target="_blank" class="btn btn-outline-info w-100">
<i class="bi bi-window"></i> ОТКРЫТЬ VNC БРАУЗЕР (ДЛЯ ЕСИА)
</a>
</div>
<div class="mb-2 d-flex justify-content-between">
<span class="small text-muted">ПОСЛЕДНИЕ ЛОГИ:</span>
<button id="refreshSudrfStatusBtn" class="btn btn-sm btn-link p-0 text-danger">ОБНОВИТЬ СТАТУС</button>
</div>
<pre id="sudrfLogs" class="bg-black text-danger p-2 small border border-secondary" style="height: 200px; overflow-y: scroll; font-size: 0.7rem;"></pre>
<div class="small opacity-50 mt-2">Выполняет: Открытие сессии -> Ввод 2FA пользователем -> Парсинг ej.sudrf.ru -> Сборка PDF -> Google Drive</div>
</div>
</div>
</div>
<div class="col-md-6"> <div class="col-md-6">
<div class="card bg-dark border-warning"> <div class="card bg-dark border-warning">
<div class="card-header text-warning">ДЕЙСТВИЯ</div> <div class="card-header text-warning">ДЕЙСТВИЯ</div>
@ -179,62 +155,9 @@ async function refreshGisStatus() {
} }
} }
document.getElementById('runSudrfParserBtn').addEventListener('click', async function() {
const btn = this;
if (!confirm('Запустить сборку судебного архива ГАС Правосудие? Потребуется войти через Госуслуги во VNC.')) return;
btn.disabled = true;
btn.innerHTML = '<span class="spinner-border spinner-border-sm"></span> СЕССИЯ СУДОВ...';
try {
const response = await fetch('/api/infra/run_sudrf_parser', { method: 'POST' });
const result = await response.json();
alert(result.message);
} catch (e) {
alert('Ошибка: ' + e);
} finally {
btn.disabled = false;
btn.innerHTML = '<i class="bi bi-play-circle"></i> ЗАПУСТИТЬ ЖАТВУ СУДОВ';
refreshSudrfStatus();
}
});
async function refreshSudrfStatus() {
const badge = document.getElementById('sudrfStatusBadge');
const logs = document.getElementById('sudrfLogs');
try {
const response = await fetch('/api/infra/sudrf_status');
const data = await response.json();
if (data.alive) {
badge.className = 'badge bg-success p-2';
badge.innerText = 'СТАТУС: РАБОТАЕТ';
} else {
badge.className = 'badge bg-danger p-2';
badge.innerText = 'СТАТУС: ОСТАНОВЛЕН';
}
logs.innerText = data.log;
logs.scrollTop = logs.scrollHeight;
} catch (e) {
badge.className = 'badge bg-warning p-2';
badge.innerText = 'ОШИБКА API';
}
}
document.getElementById('refreshGisStatusBtn').addEventListener('click', refreshGisStatus); document.getElementById('refreshGisStatusBtn').addEventListener('click', refreshGisStatus);
document.getElementById('refreshSudrfStatusBtn').addEventListener('click', refreshSudrfStatus); window.addEventListener('load', refreshGisStatus);
window.addEventListener('load', () => {
refreshGisStatus();
refreshSudrfStatus();
});
// Авто-обновление раз в 30 секунд // Авто-обновление раз в 30 секунд
setInterval(() => { setInterval(refreshGisStatus, 30000);
refreshGisStatus();
refreshSudrfStatus();
}, 30000);
</script> </script>
{% endblock %} {% endblock %}

120
web/templates/sudrf.html Normal file
View file

@ -0,0 +1,120 @@
{% extends "base.html" %}
{% block title %}Жатва ГАС Правосудие - LKM37{% endblock %}
{% block nav_sudrf %}active{% endblock %}
{% block content %}
<h2 class="mb-4"><i class="bi bi-bank text-danger"></i> Жатва ГАС Правосудие</h2>
<div class="row">
<!-- Инструкция и Статус -->
<div class="col-md-6 mb-4">
<div class="card bg-dark border-danger h-100">
<div class="card-header border-danger text-danger">
<i class="bi bi-info-circle"></i> ИНСТРУКЦИЯ И УПРАВЛЕНИЕ
</div>
<div class="card-body d-flex flex-column justify-content-between">
<div>
<p class="text-white">Этот модуль предназначен для автоматизированного сбора поданных обращений, заявлений и ответов судов с портала ГАС «Правосудие» (ej.sudrf.ru) для последующей склейки в PDF и загрузки в Google Drive (NotebookLM).</p>
<h5 class="text-danger mt-4"><i class="bi bi-1-circle"></i> Шаг 1: Подготовка сессии</h5>
<p class="small text-muted">Нажмите кнопку «Запустить Жатву ГАС Правосудие» ниже. Система откроет скрытый браузер Chromium на виртуальном рабочем столе.</p>
<h5 class="text-danger mt-3"><i class="bi bi-2-circle"></i> Шаг 2: Авторизация ЕСИА</h5>
<p class="small text-muted">Откройте VNC-браузер по ссылке справа и войдите в свой личный кабинет ГАС «Правосудие» через Госуслуги (потребуется пройти 2FA/SMS).</p>
<h5 class="text-danger mt-3"><i class="bi bi-3-circle"></i> Шаг 3: Автоматический парсинг</h5>
<p class="small text-muted">Как только вход будет обнаружен, скрипт перехватит сессию, соберет список дел, сделает скриншоты, скачает вложения и загрузит сводные PDF на Google Drive.</p>
</div>
<div class="mt-4 pt-3 border-top border-secondary">
<div class="d-flex justify-content-between align-items-center mb-3">
<span class="text-white">Статус парсера:</span>
<div id="sudrfStatusBadge" class="badge bg-secondary p-2">НЕИЗВЕСТНО</div>
</div>
<button id="runSudrfParserBtn" class="btn btn-danger w-100 py-2">
<i class="bi bi-play-circle-fill"></i> ЗАПУСТИТЬ ЖАТВУ ГАС ПРАВОСУДИЕ
</button>
</div>
</div>
</div>
</div>
<!-- VNC и Логи -->
<div class="col-md-6 mb-4">
<div class="card bg-dark border-info h-100">
<div class="card-header border-info text-info">
<i class="bi bi-display"></i> СЕССИЯ И ЛОГИ СКАНИРОВАНИЯ
</div>
<div class="card-body d-flex flex-column">
<a href="http://192.168.10.116:6080/vnc.html" target="_blank" class="btn btn-outline-info w-100 py-3 mb-3">
<i class="bi bi-window-fullscreen"></i> ОТКРЫТЬ VNC ЭКРАН (noVNC)
</a>
<div class="d-flex justify-content-between align-items-center mb-2">
<span class="small text-muted">ЛОГИ В РЕАЛЬНОМ ВРЕМЕНИ:</span>
<button id="refreshSudrfStatusBtn" class="btn btn-sm btn-outline-secondary py-0 px-2" style="font-size: 0.75rem;">
<i class="bi bi-arrow-clockwise"></i> ОБНОВИТЬ
</button>
</div>
<pre id="sudrfLogs" class="bg-black text-danger p-3 small border border-secondary flex-grow-1" style="min-height: 250px; overflow-y: scroll; font-family: monospace; font-size: 0.75rem;"></pre>
</div>
</div>
</div>
</div>
{% endblock %}
{% block extra_script %}
<script>
document.getElementById('runSudrfParserBtn').addEventListener('click', async function() {
const btn = this;
if (!confirm('Запустить сборку судебного архива ГАС Правосудие? Потребуется войти через Госуслуги во VNC.')) return;
btn.disabled = true;
btn.innerHTML = '<span class="spinner-border spinner-border-sm"></span> СЕССИЯ ЗАПУЩЕНА...';
try {
const response = await fetch('/api/infra/run_sudrf_parser', { method: 'POST' });
const result = await response.json();
alert(result.message);
} catch (e) {
alert('Ошибка при запуске: ' + e);
} finally {
btn.disabled = false;
btn.innerHTML = '<i class="bi bi-play-circle-fill"></i> ЗАПУСТИТЬ ЖАТВУ ГАС ПРАВОСУДИЕ';
refreshSudrfStatus();
}
});
async function refreshSudrfStatus() {
const badge = document.getElementById('sudrfStatusBadge');
const logs = document.getElementById('sudrfLogs');
try {
const response = await fetch('/api/infra/sudrf_status');
const data = await response.json();
if (data.alive) {
badge.className = 'badge bg-success p-2';
badge.innerText = 'СТАТУС: РАБОТАЕТ';
} else {
badge.className = 'badge bg-danger p-2';
badge.innerText = 'СТАТУС: ОСТАНОВЛЕН';
}
logs.innerText = data.log || "Лог пуст или еще не создан.";
logs.scrollTop = logs.scrollHeight;
} catch (e) {
badge.className = 'badge bg-warning p-2';
badge.innerText = 'ОШИБКА API';
}
}
document.getElementById('refreshSudrfStatusBtn').addEventListener('click', refreshSudrfStatus);
window.addEventListener('load', refreshSudrfStatus);
// Автообновление логов каждые 15 секунд
setInterval(refreshSudrfStatus, 15000);
</script>
{% endblock %}