CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-sherlock-project

Hunt down social media accounts by username across social networks

Pending
Overview
Eval results
Files

notification-system.mddocs/

Notification System

Pluggable notification handlers for processing and displaying search results. The notification system provides a flexible architecture for customizing how search results are presented to users, supporting various output formats and interaction patterns.

Capabilities

Base Notification Class

Abstract base class that defines the notification interface for handling search results during and after the search process.

class QueryNotify:
    """
    Base class for query result notifications.
    
    Defines the interface for notifying callers about query results.
    Intended to be inherited by specific notification implementations.
    """
    
    def __init__(self, result: QueryResult = None):
        """
        Create Query Notify Object.
        
        Args:
            result: QueryResult object containing initial results (optional)
        """
        
    result: QueryResult  # Current result being processed
    
    def start(self, message: str = None):
        """
        Notify start of query process.
        
        Called once before any queries are performed.
        Override in subclasses for custom start behavior.
        
        Args:
            message: Context message for start of query (optional)
        """
        
    def update(self, result: QueryResult):
        """
        Notify query result update.
        
        Called for each query result as it becomes available.
        Override in subclasses for custom result processing.
        
        Args:
            result: QueryResult object containing results for this query
        """
        
    def finish(self, message: str = None):
        """
        Notify end of query process.
        
        Called once after all queries have been performed.
        Override in subclasses for custom finish behavior.
        
        Args:
            message: Context message for end of query (optional)
        """
        
    def __str__(self) -> str:
        """
        Convert object to string representation.
        
        Returns:
            String representation of current result
        """

Print-Based Notification

Concrete implementation that outputs search results to the console with colorized formatting and optional web browser integration.

class QueryNotifyPrint(QueryNotify):
    """
    Query notification implementation that prints results to console.
    
    Provides colorized output with configurable verbosity and filtering options.
    """
    
    def __init__(
        self,
        result: QueryResult = None,
        verbose: bool = False,
        print_all: bool = False,
        browse: bool = False
    ):
        """
        Create Query Notify Print Object.
        
        Args:
            result: QueryResult object containing initial results (optional)
            verbose: Boolean indicating whether to show response times and verbose output
            print_all: Boolean indicating whether to print all sites including not found
            browse: Boolean indicating whether to open found sites in web browser
        """
        
    verbose: bool     # Show detailed output including response times
    print_all: bool   # Show results for all sites, including failures
    browse: bool      # Open found URLs in web browser
    
    def start(self, message: str):
        """
        Print query start notification.
        
        Displays colored header with username being searched.
        
        Args:
            message: String containing username that queries are about
        """
        
    def update(self, result: QueryResult):
        """
        Print individual query result.
        
        Displays result with appropriate coloring based on status:
        - Green for claimed/found accounts
        - Red for errors and not found (if print_all enabled)
        - Includes response time if verbose mode enabled
        - Opens URLs in browser if browse mode enabled
        
        Args:
            result: QueryResult object containing results for this query
        """
        
    def finish(self, message: str = "The processing has been finished."):
        """
        Print completion notification.
        
        Displays summary with total number of accounts found.
        
        Args:
            message: Completion message to display
        """
        
    def countResults(self) -> int:
        """
        Count and return number of results found so far.
        
        Increments global result counter each time called.
        
        Returns:
            Integer count of results processed
        """
        
    def __str__(self) -> str:
        """
        Convert object to string representation.
        
        Returns:
            String representation of current result
        """

Global Variables

globvar: int  # Global variable to count the number of results

Usage Examples

Basic Console Output

from sherlock_project.sherlock import sherlock
from sherlock_project.notify import QueryNotifyPrint
from sherlock_project.sites import SitesInformation

# Create basic console notification handler
notify = QueryNotifyPrint()

# Load sites and perform search
sites = SitesInformation()
results = sherlock("john_doe", sites.sites, notify)

# Output will automatically be printed during search:
# [*] Checking username john_doe on:
# [+] GitHub: https://github.com/john_doe
# [+] Twitter: https://twitter.com/john_doe
# [*] Search completed with 2 results

Verbose Output with Timing

# Enable verbose mode to show response times
notify = QueryNotifyPrint(verbose=True)

results = sherlock("username", sites.sites, notify)

# Output includes timing information:
# [+] [245ms] GitHub: https://github.com/username  
# [+] [1.2s] Twitter: https://twitter.com/username

Show All Results Including Failures

# Show all sites including those where username was not found
notify = QueryNotifyPrint(print_all=True, verbose=True)

results = sherlock("username", sites.sites, notify)

# Output shows all attempted sites:
# [+] [245ms] GitHub: https://github.com/username
# [-] [180ms] Instagram: Not Found!
# [-] Facebook: Connection Error
# [+] [320ms] Twitter: https://twitter.com/username

Auto-Open Found Accounts in Browser

# Automatically open found profiles in web browser
notify = QueryNotifyPrint(browse=True, verbose=True)

results = sherlock("username", sites.sites, notify)

# Found URLs will automatically open in default web browser

Custom Notification Handler

from sherlock_project.notify import QueryNotify
from sherlock_project.result import QueryStatus
import logging

class QueryNotifyLogger(QueryNotify):
    """Custom notification handler that logs results."""
    
    def __init__(self):
        super().__init__()
        logging.basicConfig(level=logging.INFO)
        self.logger = logging.getLogger('sherlock')
        self.found_count = 0
        
    def start(self, message):
        self.logger.info(f"Starting search for username: {message}")
        self.found_count = 0
        
    def update(self, result):
        if result.status == QueryStatus.CLAIMED:
            self.found_count += 1
            self.logger.info(f"FOUND: {result.site_name} - {result.site_url_user}")
        elif result.status == QueryStatus.UNKNOWN:
            self.logger.warning(f"ERROR: {result.site_name} - {result.context}")
            
    def finish(self, message=None):
        self.logger.info(f"Search completed. Found {self.found_count} accounts.")

# Use custom handler
custom_notify = QueryNotifyLogger()
results = sherlock("username", sites.sites, custom_notify)

Silent Notification Handler

class QueryNotifySilent(QueryNotify):
    """Notification handler that collects results without output."""
    
    def __init__(self):
        super().__init__()
        self.results = []
        self.start_time = None
        
    def start(self, message):
        import time
        self.start_time = time.time()
        self.results = []
        
    def update(self, result):
        self.results.append({
            'site': result.site_name,
            'username': result.username,
            'status': result.status.value,
            'url': result.site_url_user,
            'response_time': result.query_time,
            'context': result.context
        })
        
    def finish(self, message=None):
        import time
        total_time = time.time() - self.start_time
        claimed = len([r for r in self.results if r['status'] == 'Claimed'])
        print(f"Silent search completed: {claimed} accounts found in {total_time:.2f}s")

# Use for batch processing without console spam
silent_notify = QueryNotifySilent()
results = sherlock("username", sites.sites, silent_notify)

# Access collected results
for result in silent_notify.results:
    if result['status'] == 'Claimed':
        print(f"Found: {result['site']} - {result['url']}")

File Export Notification Handler

import json
from datetime import datetime

class QueryNotifyFileExport(QueryNotify):
    """Notification handler that exports results to file."""
    
    def __init__(self, output_file="sherlock_results.json"):
        super().__init__()
        self.output_file = output_file
        self.session_data = {
            'timestamp': datetime.now().isoformat(),
            'results': []
        }
        
    def start(self, message):
        self.session_data['username'] = message
        print(f"Searching for {message}...")
        
    def update(self, result):
        self.session_data['results'].append({
            'site_name': result.site_name,
            'username': result.username,
            'url': result.site_url_user,
            'status': result.status.value,
            'query_time': result.query_time,
            'context': result.context
        })
        
        # Print only found accounts
        if result.status == QueryStatus.CLAIMED:
            print(f"✓ {result.site_name}: {result.site_url_user}")
            
    def finish(self, message=None):
        # Save results to file
        with open(self.output_file, 'w') as f:
            json.dump(self.session_data, f, indent=2)
            
        claimed = len([r for r in self.session_data['results'] if r['status'] == 'Claimed'])
        print(f"Search completed. {claimed} accounts found.")
        print(f"Results saved to {self.output_file}")

# Use for automated result collection
export_notify = QueryNotifyFileExport("john_doe_results.json")
results = sherlock("john_doe", sites.sites, export_notify)

Install with Tessl CLI

npx tessl i tessl/pypi-sherlock-project

docs

core-search.md

index.md

notification-system.md

result-management.md

site-management.md

tile.json