Hunt down social media accounts by username across social networks
—
Data structures and enumerations for handling search results from username lookups. The result management system provides structured representations of query outcomes with comprehensive metadata about each search operation.
Enumeration that represents the possible outcomes of a username search on a social media platform.
class QueryStatus(Enum):
"""
Query Status Enumeration for username detection results.
"""
CLAIMED = "Claimed" # Username detected/exists on the platform
AVAILABLE = "Available" # Username not detected/available for registration
UNKNOWN = "Unknown" # Error occurred while trying to detect username
ILLEGAL = "Illegal" # Username format not allowable for this site
WAF = "WAF" # Request blocked by Web Application Firewall
def __str__(self) -> str:
"""
Convert status to string representation.
Returns:
String value of the status
"""Container object that holds comprehensive information about the result of a username query on a specific platform.
class QueryResult:
"""
Query Result Object containing information about username detection on a site.
"""
def __init__(
self,
username: str,
site_name: str,
site_url_user: str,
status: QueryStatus,
query_time: float = None,
context: str = None
):
"""
Create Query Result Object.
Args:
username: String indicating username that query result was about
site_name: String which identifies the site
site_url_user: String containing URL for username on site
(NOTE: may or may not exist - indicates what the URL would be)
status: QueryStatus enumeration indicating the status of the query
query_time: Time in seconds required to perform query (optional)
context: String indicating additional context about the query,
such as error details (optional)
"""
# Attributes set by constructor
username: str # Username that was searched
site_name: str # Name of the social media site
site_url_user: str # Full URL where the user profile would be located
status: QueryStatus # Result status of the query
query_time: float # Time taken for the query in seconds (may be None)
context: str # Additional context information (may be None)
def __str__(self) -> str:
"""
Convert Object to String representation.
Returns:
Nicely formatted string with status and context information
"""The QueryStatus enum provides these specific status values:
When the main sherlock() function returns results, each site result contains:
ResultDict = {
"url_main": str, # Main homepage URL of the site
"url_user": str, # Full URL to the user's profile page
"status": QueryResult, # QueryResult object with detailed information
"http_status": int, # HTTP status code from the request
"response_text": str # Raw response text (may be None on errors)
}from sherlock_project.sherlock import sherlock
from sherlock_project.result import QueryStatus
from sherlock_project.notify import QueryNotifyPrint
from sherlock_project.sites import SitesInformation
# Perform search
sites = SitesInformation()
notify = QueryNotifyPrint()
results = sherlock("john_doe", sites.sites, notify)
# Process results by status
claimed_accounts = []
available_usernames = []
errors = []
for site_name, result_data in results.items():
result = result_data['status'] # This is a QueryResult object
if result.status == QueryStatus.CLAIMED:
claimed_accounts.append({
'site': site_name,
'url': result.site_url_user,
'response_time': result.query_time
})
elif result.status == QueryStatus.AVAILABLE:
available_usernames.append(site_name)
elif result.status in [QueryStatus.UNKNOWN, QueryStatus.WAF]:
errors.append({
'site': site_name,
'error': result.context,
'status': result.status.value
})
print(f"Found accounts: {len(claimed_accounts)}")
print(f"Available on: {len(available_usernames)} sites")
print(f"Errors: {len(errors)}")# Find accounts with fast response times (under 500ms)
fast_results = []
for site_name, result_data in results.items():
result = result_data['status']
if (result.status == QueryStatus.CLAIMED and
result.query_time and result.query_time < 0.5):
fast_results.append({
'site': site_name,
'username': result.username,
'url': result.site_url_user,
'time': result.query_time
})
# Sort by response time
fast_results.sort(key=lambda x: x['time'])from sherlock_project.result import QueryResult, QueryStatus
# Create a custom result (e.g., for testing or custom site checking)
custom_result = QueryResult(
username="test_user",
site_name="CustomSite",
site_url_user="https://customsite.com/user/test_user",
status=QueryStatus.CLAIMED,
query_time=0.234,
context="Account verified"
)
print(f"Result: {custom_result}") # Uses __str__ method
print(f"Status: {custom_result.status}")
print(f"URL: {custom_result.site_url_user}")# Process results with detailed error information
for site_name, result_data in results.items():
result = result_data['status']
if result.status == QueryStatus.UNKNOWN:
print(f"Error on {site_name}: {result.context}")
elif result.status == QueryStatus.WAF:
print(f"Blocked by WAF on {site_name} - consider using proxy")
elif result.status == QueryStatus.ILLEGAL:
print(f"Username format invalid for {site_name}")import json
import csv
# Export claimed accounts to JSON
claimed_data = []
for site_name, result_data in results.items():
result = result_data['status']
if result.status == QueryStatus.CLAIMED:
claimed_data.append({
'username': result.username,
'site_name': result.site_name,
'profile_url': result.site_url_user,
'response_time_ms': round(result.query_time * 1000) if result.query_time else None,
'found_at': result_data.get('timestamp') # If you add timestamps
})
# Save to JSON
with open('sherlock_results.json', 'w') as f:
json.dump(claimed_data, f, indent=2)
# Save to CSV
with open('sherlock_results.csv', 'w', newline='') as f:
if claimed_data:
writer = csv.DictWriter(f, fieldnames=claimed_data[0].keys())
writer.writeheader()
writer.writerows(claimed_data)Install with Tessl CLI
npx tessl i tessl/pypi-sherlock-project