diff --git a/routers/ip.py b/routers/ip.py index cb92b83..b568d75 100644 --- a/routers/ip.py +++ b/routers/ip.py @@ -66,30 +66,39 @@ class IPInfo: def _parse(self, html: str) -> Optional[IPInfoModel]: """Парсит HTML и возвращает модель""" soup = BeautifulSoup(html, 'html.parser') - script = soup.find('script', type='application/ld+json') - - if not script or not script.string: + scripts = soup.find_all('script', type='application/ld+json') + + if not scripts: return None - - try: - data: Dict = json.loads(script.string.strip()) - except json.JSONDecodeError: + + # Ищем первый скрипт с типом DataFeed + data = None + for script in scripts: + if not script.string: + continue + + try: + parsed = json.loads(script.string.strip()) + if parsed.get('@type') == 'DataFeed': + data = parsed + break + except json.JSONDecodeError: + continue + + if data is None: return None - - if data.get('@type') != 'DataFeed': - return None - + # Базовые поля result = IPInfoModel( ip=data.get('name', ''), url=data.get('url') ) - + # Парсим локацию location = data.get('contentLocation', {}) address = location.get('address', {}) geo = location.get('geo', {}) - + result.location = LocationModel( city=address.get('addressLocality'), region=address.get('addressRegion'), @@ -99,20 +108,20 @@ class IPInfo: longitude=geo.get('longitude'), timezone=self._find_value(data, 'Timezone') ) - + # Парсим ASN result.asn = ASNModel( asn=self._find_value(data, 'ASN'), name=self._find_value(data, 'AS Name'), route=self._find_value(data, 'AS Route') ) - + # Парсим компанию result.company = CompanyModel( name=self._find_value(data, 'Company Name'), abuse_contact=self._find_value(data, 'Abuse Contact') ) - + # Парсим безопасность result.security = SecurityModel( vpn=self._find_bool(data, 'VPN'), @@ -120,7 +129,7 @@ class IPInfo: tor=self._find_bool(data, 'Tor'), hosting=self._find_bool(data, 'Hosting') ) - + return result def _find_value(self, data: Dict, name: str) -> Optional[str]: