Spaces:
Runtime error
Runtime error
| # Location: features.py | |
| import re | |
| from urllib.parse import urlparse | |
| def extract_url_features(url): | |
| """ | |
| Transforms a raw URL string into a fixed 14-dimensional numerical vector. | |
| Bakes protocol layout logic directly into the metrics—no hardcoded strings. | |
| """ | |
| url_str = str(url).strip() | |
| # Normalize scheme purely for structural parsing accuracy | |
| if not url_str.lower().startswith(('http://', 'https://')): | |
| parse_target = 'http://' + url_str | |
| else: | |
| parse_target = url_str | |
| try: | |
| parsed = urlparse(parse_target) | |
| # FIX: Extract the true domain name using parsed.hostname instead of parsed.netloc. | |
| # parsed.netloc returns 'youtube@evil-site.com', which contaminates the host measurements. | |
| # parsed.hostname correctly isolates and returns 'evil-site.com'. | |
| host = parsed.hostname if parsed.hostname else url_str | |
| path = parsed.path if parsed.path else "" | |
| # Ensure the anomaly flag catches userinfo components reliably across both parsers | |
| has_userinfo_anomaly = 1.0 if (parsed.username or parsed.password or '@' in parsed.netloc) else 0.0 | |
| except Exception: | |
| host = url_str | |
| path = "" | |
| has_userinfo_anomaly = 0.0 | |
| # Feature engineering pipeline (Maintained at exactly 14 Dimensions) | |
| features = [ | |
| len(url_str), # 1. Total length | |
| len(host), # 2. Hostname layout length (Corrected to true domain length) | |
| url_str.count('.'), # 3. Subdomain count | |
| url_str.count('-'), # 4. Hyphen count | |
| has_userinfo_anomaly, # 5. Structural Credential Injection Anomaly Flag | |
| url_str.count('?'), # 6. Query parameters | |
| url_str.count('='), # 7. Variable assignments | |
| url_str.count('_'), # 8. Underscores | |
| 1 if re.search(r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}', host) else 0, # 9. IP address in hostname | |
| host.count('.'), # 10. Dots in hostname specifically | |
| path.count('/'), # 11. Directory depth | |
| sum(1 for c in url_str if c.isdigit()), # 12. Total numbers in URL | |
| 1 if parsed.scheme == "https" else 0, # 13. Uses HTTPS | |
| 1 if url_str.lower().startswith(('bit.ly', 'tinyurl')) else 0 # 14. Shortener | |
| ] | |
| return features |