Fix: улучшена фильтрация не-отелей, поддержка PDF-политики, исправлены ошибки DNS

This commit is contained in:
neo committed 2026-06-10 00:11:30 +05:00
1 parent 928637ad25
commit 7fb417dad5
10 files changed
+239 -41

No files matched your search

+52
View File
@@ -0,0 +1,52 @@
url
https://grand-hotel-ufa.ru
https://hotel-astoria.ru
https://mitino-ufa.ru
https://domsuvorova.ru
https://ufimgostinitsa.ru
https://hotelbriz.ru
https://cityotel-ufa.ru
https://amax-hotel.ru
https://hotel-pushkin.ru
https://president-ufa.ru
https://posadskaya-hotel.ru
https://adijo-hotel.ru
https://nestorov-plaza.ru
https://ural-tau.ru
https://art-hotel-ufa.ru
https://gostinyy-dvor.ru
https://parkcity-ufa.ru
https://hotel-naberezhnaya.ru
https://dolphin-ufa.ru
https://yunost-ufa.ru
https://sanatoriy-salyut.ru
https://zelenaya-rosha.ru
https://www.marriott.com/hotels/travel/ufcsp-sheraton-plaza-ufa/
https://www.radissonhotels.com/ru-ru/hotels/radisson-blu-ufa
https://www.hiltongardeninn.com/en/hotel/russia/ufa/
https://www.hamptonbyhilton.com/en/hotels/russia/ufa/ufham/index.html
https://www.bashkortostan.ru/ru/hotels
https://ufahotel.ru
https://hotel-ufa.ru
https://gostinydvor-ufa.ru
https://hotel-korona-ufa.ru
https://komfort-hotel.ru
https://iremel-hotel.ru
https://4sezona-hotel.ru
https://tihoretskaya-hotel.ru
https://semya-hotel.ru
https://svoyak-hotel.ru
https://hotel-ural-ufa.ru
https://gorodskaya-hotel.ru
https://slavyanskaya-hotel.ru
https://v-centre-hotel.ru
https://adzio-hotel.ru
https://klesopatra-hotel.ru
https://agidel-hotel.ru
https://shef-eck-hotel.ru
https://admin-komplex-hotel.ru
https://prof-tan-hotel.ru
https://park-city-hotel.ru
https://gorbatova-hotel.ru
https://tichoretskaya-hotel.ru
https://selena-rosha-hotel.ru
1 url
2 https://grand-hotel-ufa.ru
3 https://hotel-astoria.ru
4 https://mitino-ufa.ru
5 https://domsuvorova.ru
6 https://ufimgostinitsa.ru
7 https://hotelbriz.ru
8 https://cityotel-ufa.ru
9 https://amax-hotel.ru
10 https://hotel-pushkin.ru
11 https://president-ufa.ru
12 https://posadskaya-hotel.ru
13 https://adijo-hotel.ru
14 https://nestorov-plaza.ru
15 https://ural-tau.ru
16 https://art-hotel-ufa.ru
17 https://gostinyy-dvor.ru
18 https://parkcity-ufa.ru
19 https://hotel-naberezhnaya.ru
20 https://dolphin-ufa.ru
21 https://yunost-ufa.ru
22 https://sanatoriy-salyut.ru
23 https://zelenaya-rosha.ru
24 https://www.marriott.com/hotels/travel/ufcsp-sheraton-plaza-ufa/
25 https://www.radissonhotels.com/ru-ru/hotels/radisson-blu-ufa
26 https://www.hiltongardeninn.com/en/hotel/russia/ufa/
27 https://www.hamptonbyhilton.com/en/hotels/russia/ufa/ufham/index.html
28 https://www.bashkortostan.ru/ru/hotels
29 https://ufahotel.ru
30 https://hotel-ufa.ru
31 https://gostinydvor-ufa.ru
32 https://hotel-korona-ufa.ru
33 https://komfort-hotel.ru
34 https://iremel-hotel.ru
35 https://4sezona-hotel.ru
36 https://tihoretskaya-hotel.ru
37 https://semya-hotel.ru
38 https://svoyak-hotel.ru
39 https://hotel-ural-ufa.ru
40 https://gorodskaya-hotel.ru
41 https://slavyanskaya-hotel.ru
42 https://v-centre-hotel.ru
43 https://adzio-hotel.ru
44 https://klesopatra-hotel.ru
45 https://agidel-hotel.ru
46 https://shef-eck-hotel.ru
47 https://admin-komplex-hotel.ru
48 https://prof-tan-hotel.ru
49 https://park-city-hotel.ru
50 https://gorbatova-hotel.ru
51 https://tichoretskaya-hotel.ru
52 https://selena-rosha-hotel.ru
+1
View File
@@ -0,0 +1 @@
url
1 url
+45
View File
@@ -0,0 +1,45 @@
url
https://grand-hotel-ufa.ru
https://hotel-astoria.ru
https://mitino-ufa.ru
https://domsuvorova.ru
https://ufimgostinitsa.ru
https://hotelbriz.ru
https://cityotel-ufa.ru
https://amax-hotel.ru
https://hotel-pushkin.ru
https://president-ufa.ru
https://posadskaya-hotel.ru
https://adijo-hotel.ru
https://nestorov-plaza.ru
https://ural-tau.ru
https://art-hotel-ufa.ru
https://gostinyy-dvor.ru
https://zelenaya-rosha.ru
https://parkcity-ufa.ru
https://hotel-naberezhnaya.ru
https://dolphin-ufa.ru
https://yunost-ufa.ru
https://sanatoriy-salyut.ru
https://hotel-ufa.ru
https://gostinydvor-ufa.ru
https://hotel-korona-ufa.ru
https://komfort-hotel.ru
https://iremel-hotel.ru
https://4sezona-hotel.ru
https://tihoretskaya-hotel.ru
https://semya-hotel.ru
https://svoyak-hotel.ru
https://hotel-ural-ufa.ru
https://gorodskaya-hotel.ru
https://slavyanskaya-hotel.ru
https://v-centre-hotel.ru
https://adzio-hotel.ru
https://klesopatra-hotel.ru
https://agidel-hotel.ru
https://shef-eck-hotel.ru
https://admin-komplex-hotel.ru
https://prof-tan-hotel.ru
https://gorbatova-hotel.ru
https://tichoretskaya-hotel.ru
https://selena-rosha-hotel.ru
1 url
2 https://grand-hotel-ufa.ru
3 https://hotel-astoria.ru
4 https://mitino-ufa.ru
5 https://domsuvorova.ru
6 https://ufimgostinitsa.ru
7 https://hotelbriz.ru
8 https://cityotel-ufa.ru
9 https://amax-hotel.ru
10 https://hotel-pushkin.ru
11 https://president-ufa.ru
12 https://posadskaya-hotel.ru
13 https://adijo-hotel.ru
14 https://nestorov-plaza.ru
15 https://ural-tau.ru
16 https://art-hotel-ufa.ru
17 https://gostinyy-dvor.ru
18 https://zelenaya-rosha.ru
19 https://parkcity-ufa.ru
20 https://hotel-naberezhnaya.ru
21 https://dolphin-ufa.ru
22 https://yunost-ufa.ru
23 https://sanatoriy-salyut.ru
24 https://hotel-ufa.ru
25 https://gostinydvor-ufa.ru
26 https://hotel-korona-ufa.ru
27 https://komfort-hotel.ru
28 https://iremel-hotel.ru
29 https://4sezona-hotel.ru
30 https://tihoretskaya-hotel.ru
31 https://semya-hotel.ru
32 https://svoyak-hotel.ru
33 https://hotel-ural-ufa.ru
34 https://gorodskaya-hotel.ru
35 https://slavyanskaya-hotel.ru
36 https://v-centre-hotel.ru
37 https://adzio-hotel.ru
38 https://klesopatra-hotel.ru
39 https://agidel-hotel.ru
40 https://shef-eck-hotel.ru
41 https://admin-komplex-hotel.ru
42 https://prof-tan-hotel.ru
43 https://gorbatova-hotel.ru
44 https://tichoretskaya-hotel.ru
45 https://selena-rosha-hotel.ru
+6
View File
@@ -0,0 +1,6 @@
url
https://hotel-astoria.ru
https://hotel-ufa.ru
https://komfort-hotel.ru
https://slavyanskaya-hotel.ru
https://agidel-hotel.ru
1 url
2 https://hotel-astoria.ru
3 https://hotel-ufa.ru
4 https://komfort-hotel.ru
5 https://slavyanskaya-hotel.ru
6 https://agidel-hotel.ru
+23
View File
@@ -0,0 +1,23 @@
url
https://grand-hotel-ufa.ru
https://hotel-astoria.ru
https://mitino-ufa.ru
https://domsuvorova.ru
https://ufimgostinitsa.ru
https://hotelbriz.ru
https://cityotel-ufa.ru
https://amax-hotel.ru
https://hotel-pushkin.ru
https://president-ufa.ru
https://posadskaya-hotel.ru
https://adijo-hotel.ru
https://nestorov-plaza.ru
https://ural-tau.ru
https://art-hotel-ufa.ru
https://gostinyy-dvor.ru
https://zelenaya-rosha.ru
https://parkcity-ufa.ru
https://hotel-naberezhnaya.ru
https://dolphin-ufa.ru
https://yunost-ufa.ru
https://sanatoriy-salyut.ru
1 url
2 https://grand-hotel-ufa.ru
3 https://hotel-astoria.ru
4 https://mitino-ufa.ru
5 https://domsuvorova.ru
6 https://ufimgostinitsa.ru
7 https://hotelbriz.ru
8 https://cityotel-ufa.ru
9 https://amax-hotel.ru
10 https://hotel-pushkin.ru
11 https://president-ufa.ru
12 https://posadskaya-hotel.ru
13 https://adijo-hotel.ru
14 https://nestorov-plaza.ru
15 https://ural-tau.ru
16 https://art-hotel-ufa.ru
17 https://gostinyy-dvor.ru
18 https://zelenaya-rosha.ru
19 https://parkcity-ufa.ru
20 https://hotel-naberezhnaya.ru
21 https://dolphin-ufa.ru
22 https://yunost-ufa.ru
23 https://sanatoriy-salyut.ru
+40
View File
@@ -4,3 +4,43 @@ INFO: Started reloader process [83013] using WatchFiles
INFO: Started server process [83060] INFO: Started server process [83060]
INFO: Waiting for application startup. INFO: Waiting for application startup.
INFO: Application startup complete. INFO: Application startup complete.
WARNING: WatchFiles detected changes in 'scanner/checks/privacy_link.py'. Reloading...
INFO: Shutting down
INFO: Waiting for application shutdown.
INFO: Application shutdown complete.
INFO: Finished server process [83060]
INFO: Started server process [122538]
INFO: Waiting for application startup.
INFO: Application startup complete.
WARNING: WatchFiles detected changes in 'scanner/checks/server_location.py'. Reloading...
INFO: Shutting down
INFO: Waiting for application shutdown.
INFO: Application shutdown complete.
INFO: Finished server process [122538]
INFO: Started server process [123220]
INFO: Waiting for application startup.
INFO: Application startup complete.
WARNING: WatchFiles detected changes in 'scanner/checks/form_checkbox.py'. Reloading...
INFO: Shutting down
INFO: Waiting for application shutdown.
INFO: Application shutdown complete.
INFO: Finished server process [123220]
INFO: Started server process [123432]
INFO: Waiting for application startup.
INFO: Application startup complete.
WARNING: WatchFiles detected changes in 'main.py'. Reloading...
INFO: Shutting down
INFO: Waiting for application shutdown.
INFO: Application shutdown complete.
INFO: Finished server process [123432]
INFO: Started server process [123876]
INFO: Waiting for application startup.
INFO: Application startup complete.
WARNING: WatchFiles detected changes in 'main.py'. Reloading...
INFO: Shutting down
INFO: Waiting for application shutdown.
INFO: Application shutdown complete.
INFO: Finished server process [123876]
INFO: Started server process [125174]
INFO: Waiting for application startup.
INFO: Application startup complete.
+36 -1
View File
@@ -40,6 +40,29 @@ async def scan_single(url: str, checks: list[str] | None = None) -> SiteScan:
return result return result
def is_likely_hotel(url: str) -> bool:
"""Проверяет, похож ли URL на сайт отеля (фильтр не-отелей)."""
domain = url.replace("https://", "").replace("http://", "").split("/")[0].lower()
# Известные не-отели — пропускаем их
not_hotel_patterns = [
"wikipedia", "google", "example", "demo", "test", "toscrape",
"herokuapp", "phpstore", "myshopify", "wordpress", "joomla",
"drupal", "typo3", "prestashop", "magento", "opencart",
"wix", "squarespace", "webflow", "shopify", "woocommerce",
"tilda", "constructor", "builder", "playwright", "node",
"localhost", "127.0.0.1", "ip-api", "ipify", "my-ip",
"reg.ru", "nic.ru", "beget", "timeweb", "selectel",
]
for pattern in not_hotel_patterns:
if pattern in domain:
return False
# Разрешаем всё остальное — пользователь курирует список
return True
def scan_csv(filepath: str): def scan_csv(filepath: str):
"""Парксить CSV-файл с URL и запустить сканирование.""" """Парксить CSV-файл с URL и запустить сканирование."""
csv_path = Path(filepath) csv_path = Path(filepath)
@@ -48,13 +71,25 @@ def scan_csv(filepath: str):
sys.exit(1) sys.exit(1)
urls = [] urls = []
skipped = []
with open(csv_path, "r", encoding="utf-8") as f: with open(csv_path, "r", encoding="utf-8") as f:
reader = csv.reader(f) reader = csv.reader(f)
for row in reader: for row in reader:
if row: if row:
url = row[0].strip() url = row[0].strip()
if url and url.startswith(("http://", "https://")): if url and url.startswith(("http://", "https://")):
urls.append(url) if is_likely_hotel(url):
urls.append(url)
else:
skipped.append(url)
if skipped:
print(f"⚠️ Пропущено {len(skipped)} URL (не похожи на отели):")
for u in skipped[:5]:
print(f" {u}")
if len(skipped) > 5:
print(f" ...и ещё {len(skipped) - 5}")
print()
if not urls: if not urls:
print("❌ В CSV не найдено валидных URL") print("❌ В CSV не найдено валидных URL")
+1 -1
View File
@@ -97,7 +97,7 @@ class FormCheckboxCheck(BaseCheck):
details={ details={
"total_forms": forms_needing_consent, "total_forms": forms_needing_consent,
"without_consent": forms_without_consent, "without_consent": forms_without_consent,
"sample_texts": [f["checkboxes"][0] for f in forms_without_consent[:3]], "sample_texts": [f["checkboxes"][0] if f["checkboxes"] else "без чекбоксов" for f in forms_without_consent[:3]],
}, },
) )
+16
View File
@@ -63,6 +63,22 @@ class PrivacyLinkCheck(BaseCheck):
# Проверяем, что ссылка ведет на рабочую страницу # Проверяем, что ссылка ведет на рабочую страницу
policy_url = found_links[0]["url"] policy_url = found_links[0]["url"]
try: try:
# Проверяем, не является ли URL документом (PDF, DOCX, XLSX)
doc_extensions = ['.pdf', '.docx', '.doc', '.xlsx', '.xls', '.rtf', '.txt']
is_document = any(policy_url.lower().endswith(ext) for ext in doc_extensions)
if is_document:
# Документ для скачивания — это допустимо для политики
return self._pass_result(
message=f"Найдена ссылка на Политику конфиденциальности ({policy_url})",
details={
"policy_url": policy_url,
"link_text": found_links[0]["text"],
"is_document": True,
},
)
# Для HTML-страниц — проверяем доступность
await page.goto(policy_url, timeout=5000) await page.goto(policy_url, timeout=5000)
policy_text = await page.evaluate("() => document.body.innerText") policy_text = await page.evaluate("() => document.body.innerText")
await page.goto(url, timeout=5000) # Возвращаемся на главную await page.goto(url, timeout=5000) # Возвращаемся на главную
+19 -39
View File
@@ -5,6 +5,9 @@
""" """
from __future__ import annotations from __future__ import annotations
import socket
from urllib.parse import urlparse
from playwright.async_api import Page from playwright.async_api import Page
from scanner.checks.base import BaseCheck from scanner.checks.base import BaseCheck
@@ -20,65 +23,43 @@ class ServerLocationCheck(BaseCheck):
risk_on_fail = RiskLevel.CRITICAL risk_on_fail = RiskLevel.CRITICAL
default_weight = 25 default_weight = 25
# Популярные иностранные провайдеры (можно расширять) # Популярные русские DNS-серверы/хостеры
RUSSIAN_HOSTERS = [ RUSSIAN_HOSTERS = [
"yandex", "mail.ru", "vk", "selectel", "timeweb", "beget", "yandex", "mail.ru", "vk", "selectel", "timeweb", "beget",
"reg.ru", "nic.ru", "rtcdn", "astra", "sbercloud", "reg.ru", "nic.ru", "rtcdn", "astra", "sbercloud",
"cloud4russia", "гостех", "ростелеком", "мтс", "билайн", "cloud4russia", "гостех", "ростелеком", "мтс", "билайн",
"мегафон", "вымпелком", "ростелеком", "netology", "мегафон", "вымпелком", "netology",
"yandex.net", "mail.ru", "vk.com", "selectel.cloud",
] ]
async def check(self, page: Page, url: str) -> CheckResult: async def check(self, page: Page, url: str) -> CheckResult:
try: try:
# Получаем IP-адрес сервера через JavaScript # Извлекаем домен из URL
ip_info = await page.evaluate("""() => { parsed = urlparse(url)
return new Promise((resolve) => { hostname = parsed.hostname or ""
// Пробуем определить IP через несколько методов
const methods = [
() => fetch('https://api.ipify.org?format=json')
.then(r => r.json()).then(d => ({ip: d.ip, method: 'ipify'})),
() => fetch('https://api.my-ip.io/v2/json')
.then(r => r.json()).then(d => ({ip: d.ip, method: 'my-ip-io'})),
];
// Пробуем каждый метод if not hostname:
(async () => { return self._skip_result(message="Не удалось извлечь домен из URL.")
for (const method of methods) {
try {
const result = await method();
resolve(result);
return;
} catch (e) {}
}
resolve(null);
})();
});
}""")
if not ip_info: # Получаем IP через DNS
return self._skip_result( try:
message="Не удалось определить IP-адрес сервера.", ip = socket.gethostbyname(hostname)
) except socket.gaierror:
return self._skip_result(message=f"Не удалось разрешить DNS для {hostname}.")
ip = ip_info.get("ip", "") # Определяем страну по IP
method = ip_info.get("method", "")
# Определяем страну по IP (используем публичный API)
country = await self._get_country(ip) country = await self._get_country(ip)
if not country: if not country:
return self._skip_result( return self._skip_result(message=f"Не удалось определить страну для IP {ip}.")
message=f"Не удалось определить страну для IP {ip}.",
)
# Проверяем, Россия ли это # Проверяем, Россия ли это
if country.lower() == "ru" or "Россия" in country: if country.lower() == "ru" or "Россия" in country or "russia" in country.lower():
return self._pass_result( return self._pass_result(
message=f"Сервер находится в России (IP: {ip}, Страна: {country})", message=f"Сервер находится в России (IP: {ip}, Страна: {country})",
details={ details={
"ip": ip, "ip": ip,
"country": country, "country": country,
"method": method,
}, },
) )
@@ -91,7 +72,6 @@ class ServerLocationCheck(BaseCheck):
details={ details={
"ip": ip, "ip": ip,
"country": country, "country": country,
"method": method,
}, },
) )