Files
Kavosh/app/services/ua_classifier.py
T
2026-08-07 21:17:17 +03:30

55 lines
1.7 KiB
Python

"""Lightweight browser/OS classification for human traffic (Chapter 08).
Separate from Chapter 07's bot_identifier — that identifies automated
crawlers via UA substring + DNS verification. This classifies ordinary
browsers/OSes, same ordered-substring-match pattern, signatures as JSON
data (not hardcoded), no third-party UA-parsing dependency — consistent
with the low-footprint bias in Chapter 03.
Order matters within each signature list: e.g. Edge/Opera must be checked
before Chrome (their UAs also contain "Chrome/"); iOS before macOS (iPhone
UAs also contain "like Mac OS X"); Android before Linux (Android UAs also
contain "Linux").
"""
from __future__ import annotations
import json
from dataclasses import dataclass
from pathlib import Path
_DATA_DIR = Path(__file__).parent / "data"
@dataclass(frozen=True)
class UASignature:
name: str
ua_substrings: tuple[str, ...]
def _load(filename: str) -> list[UASignature]:
raw = json.loads((_DATA_DIR / filename).read_text())
return [UASignature(name=e["name"], ua_substrings=tuple(e["ua_substrings"])) for e in raw]
_BROWSER_SIGNATURES = _load("browser_signatures.json")
_OS_SIGNATURES = _load("os_signatures.json")
def _match(user_agent: str, signatures: list[UASignature], default: str) -> str:
for sig in signatures:
if any(sub in user_agent for sub in sig.ua_substrings):
return sig.name
return default
def classify_browser(user_agent: str | None) -> str:
if not user_agent:
return "Unknown"
return _match(user_agent, _BROWSER_SIGNATURES, "Other")
def classify_os(user_agent: str | None) -> str:
if not user_agent:
return "Unknown"
return _match(user_agent, _OS_SIGNATURES, "Other")