Spaces:
Sleeping
Sleeping
| """Feature extraction from URLScan.io results.""" | |
| from typing import Dict, Any, Optional | |
| import pandas as pd | |
| def extract_domain_age(result: Dict[str, Any]) -> Optional[int]: | |
| """ | |
| Extract domain age in days from URLScan result. | |
| Args: | |
| result: URLScan.io API result dictionary | |
| Returns: | |
| Domain age in days, or None if not available | |
| """ | |
| try: | |
| return result.get("page", {}).get("domainAgeDays") | |
| except (KeyError, TypeError): | |
| return None | |
| def extract_secure_percentage(result: Dict[str, Any]) -> Optional[float]: | |
| """ | |
| Extract percentage of secure requests from URLScan result. | |
| Args: | |
| result: URLScan.io API result dictionary | |
| Returns: | |
| Percentage of secure requests (0-100), or None if not available | |
| """ | |
| try: | |
| return result.get("stats", {}).get("securePercentage") | |
| except (KeyError, TypeError): | |
| return None | |
| def extract_umbrella_rank(result: Dict[str, Any]) -> Optional[int]: | |
| """ | |
| Extract Cisco Umbrella popularity rank from URLScan result. | |
| Lower rank = more popular/legitimate site. | |
| Args: | |
| result: URLScan.io API result dictionary | |
| Returns: | |
| Umbrella rank, or None if not available (unranked sites) | |
| """ | |
| try: | |
| return result.get("page", {}).get("umbrellaRank") | |
| except (KeyError, TypeError): | |
| return None | |
| def extract_tls_valid_days(result: Dict[str, Any]) -> Optional[int]: | |
| """ | |
| Extract TLS certificate validity period in days from URLScan result. | |
| Args: | |
| result: URLScan.io API result dictionary | |
| Returns: | |
| Number of days the TLS certificate is valid for, or None if not available | |
| """ | |
| try: | |
| return result.get("page", {}).get("tlsValidDays") | |
| except (KeyError, TypeError): | |
| return None | |
| def extract_url_length(result: Dict[str, Any]) -> Optional[int]: | |
| """ | |
| Extract URL length from URLScan result. | |
| Args: | |
| result: URLScan.io API result dictionary | |
| Returns: | |
| Length of the URL, or None if not available | |
| """ | |
| try: | |
| url = result.get("task", {}).get("url") | |
| return len(url) if url else None | |
| except (KeyError, TypeError): | |
| return None | |
| def extract_subdomain_count(result: Dict[str, Any]) -> Optional[int]: | |
| """ | |
| Extract number of subdomains from URLScan result. | |
| Example: www.example.com has 1 subdomain, example.com has 0. | |
| Args: | |
| result: URLScan.io API result dictionary | |
| Returns: | |
| Number of subdomains, or None if not available | |
| """ | |
| try: | |
| domain = result.get("page", {}).get("domain") | |
| if not domain: | |
| return None | |
| # Count dots and subtract 1 for TLD (e.g., example.com has 1 dot = 0 subdomains) | |
| # www.example.com has 2 dots = 1 subdomain | |
| parts = domain.split(".") | |
| # Assuming TLD is last part and domain is second-to-last | |
| # subdomain count = total parts - 2 (domain + TLD) | |
| subdomain_count = max(0, len(parts) - 2) | |
| return subdomain_count | |
| except (KeyError, TypeError, AttributeError): | |
| return None | |
| def extract_features(result: Dict[str, Any]) -> Dict[str, Any]: | |
| """ | |
| Extract all available features from URLScan result. | |
| Args: | |
| result: URLScan.io API result dictionary | |
| Returns: | |
| Dictionary of extracted features | |
| """ | |
| # Extract umbrella rank and create two features from it | |
| umbrella_rank = extract_umbrella_rank(result) | |
| has_umbrella_rank = 1 if umbrella_rank is not None else 0 | |
| umbrella_rank_filled = umbrella_rank if umbrella_rank is not None else 999999 | |
| # Extract TLS validity and create two features from it | |
| tls_valid_days = extract_tls_valid_days(result) | |
| has_tls = 1 if tls_valid_days is not None else 0 | |
| tls_valid_days_filled = tls_valid_days if tls_valid_days is not None else 0 | |
| features = { | |
| "domain_age_days": extract_domain_age(result), | |
| "secure_percentage": extract_secure_percentage(result), | |
| "has_umbrella_rank": has_umbrella_rank, | |
| "umbrella_rank": umbrella_rank_filled, | |
| "has_tls": has_tls, | |
| "tls_valid_days": tls_valid_days_filled, | |
| "url_length": extract_url_length(result), | |
| "subdomain_count": extract_subdomain_count(result), | |
| } | |
| return features | |
| def extract_features_to_dataframe(results: list[Dict[str, Any]]) -> pd.DataFrame: | |
| """ | |
| Extract features from multiple URLScan results into a DataFrame. | |
| Args: | |
| results: List of URLScan.io API result dictionaries | |
| Returns: | |
| DataFrame with extracted features | |
| """ | |
| features_list = [] | |
| for result in results: | |
| features = extract_features(result) | |
| # Add URL and UUID for reference | |
| # Use original_url if available (preserves submitted URL), otherwise use task URL | |
| features["url"] = result.get("original_url") or result.get("task", {}).get("url") | |
| features["scan_uuid"] = result.get("task", {}).get("uuid") | |
| features_list.append(features) | |
| return pd.DataFrame(features_list) |