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:
neo committed 2026-06-10 00:49:07 +05:00
1 parent 7fb417dad5
commit b9db935389
24 files changed
+1725 -286

No files matched your search

+21 -26
View File
@@ -79,39 +79,34 @@ class ServerLocationCheck(BaseCheck):
return self._error_result(message=f"Ошибка при проверке геолокации: {str(e)}")
async def _get_country(self, ip: str) -> str | None:
"""Получает страну по IP через публичный API."""
"""Получает страну по IP через публичный API (асинхронно)."""
try:
import urllib.request
import json
import aiohttp
# Пробуем несколько бесплатных API
apis = [
f"https://ipapi.co/{ip}/json/",
f"https://ip-api.com/json/{ip}?fields=country",
f"https://api.ipgeolocation.io/ipgeo?ip={ip}",
]
for api_url in apis:
try:
req = urllib.request.Request(
api_url,
headers={"User-Agent": "Mozilla/5.0"}
)
with urllib.request.urlopen(req, timeout=5) as response:
data = json.loads(response.read().decode())
# ipapi.co формат
if "country_name" in data:
return data["country_name"]
# ip-api.com формат
if "country" in data:
return data["country"]
# ipgeolocation формат
if "country_name" in data:
return data["country_name"]
except Exception:
continue
async with aiohttp.ClientSession() as session:
for api_url in apis:
try:
async with session.get(
api_url,
headers={"User-Agent": "Mozilla/5.0"},
timeout=aiohttp.ClientTimeout(total=5),
) as response:
if response.status != 200:
continue
data = await response.json()
# ipapi.co формат
if "country_name" in data:
return data["country_name"]
# ip-api.com формат
if "country" in data:
return data["country"]
except Exception:
continue
return None