v2.0: исправлены критические баги, добавлены 4 новые проверки, 4-фазный cookie-аудит, retry-логика, YAML-словари, LLM-анализ, тесты
Исправлено: - engine: _calculate_score() при ошибке загрузки (score не 100 для мёртвых сайтов) - privacy_link: замена page.goto() на aiohttp (гонка данных) - form_checkbox: 3-уровневый поиск label + dark-pattern detection - server_location: синхронный urllib → aiohttp - api/server: перепутанные request/response модели в batch - main.py: csv --checks флаг - engine: фазовая модель (cookie_audit отдельно, остальные параллельно) - engine: retry-логика (3 попытки, exponential backoff) - PDF: emoji заменены на текст (WeasyPrint) Добавлено: - consent_doc: проверка отдельного согласия на обработку ПД - operator_info: проверка ИНН/ОГРН/DPO (читает главную + политику) - cookie_audit: 4-фазный аудит (load→detect→reject→compare) - llm_policy: опциональный LLM-анализ 16 разделов (--deep) - external_scripts: YAML-словари trackers.yaml (critical/warning/russian) - logging (output.py), .gitignore, pyproject.toml - smoke-тесты (16/16)
This commit is contained in:
1 parent
7fb417dad5
commit
b9db935389
24 files changed
+1725
-286
No files matched your search
@@ -0,0 +1,46 @@
|
||||
"""
|
||||
Вывод результатов: консоль + файл.
|
||||
Прозрачная замена print() — всё что идёт в out(), дублируется в лог-файл.
|
||||
"""
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from datetime import datetime
|
||||
from typing import Any
|
||||
|
||||
|
||||
class Output:
|
||||
"""Дуплексный вывод: консоль + лог-файл."""
|
||||
|
||||
def __init__(self, log_dir: str | None = None):
|
||||
if log_dir is None:
|
||||
log_dir = Path(__file__).parent.parent / "logs"
|
||||
Path(log_dir).mkdir(parents=True, exist_ok=True)
|
||||
|
||||
self._log_path = Path(log_dir) / f"scan_{datetime.now().strftime('%Y%m%d_%H%M%S')}.log"
|
||||
self._file = open(self._log_path, "w", encoding="utf-8")
|
||||
|
||||
def __call__(self, *args, **kwargs):
|
||||
"""out('текст') — вывести на консоль и в лог."""
|
||||
sep = kwargs.get("sep", " ")
|
||||
end = kwargs.get("end", "\n")
|
||||
text = sep.join(str(a) for a in args) + end
|
||||
|
||||
# Консоль
|
||||
sys.stdout.write(text)
|
||||
sys.stdout.flush()
|
||||
|
||||
# Файл (без emoji для читаемости)
|
||||
clean = text.encode("ascii", errors="replace").decode("ascii")
|
||||
self._file.write(clean)
|
||||
self._file.flush()
|
||||
|
||||
def close(self):
|
||||
self._file.close()
|
||||
|
||||
@property
|
||||
def log_path(self) -> Path:
|
||||
return self._log_path
|
||||
|
||||
|
||||
# Глобальный экземпляр
|
||||
out = Output()
|
||||
Reference in new issue
Block a user