Sherlock‑style Username Search CLI (Python)

A minimal clone that checks usernames on a few social sites

Welcome to another official UVF IT guide! In this quick build you’ll create a lightweight command‑line tool that mimics Sherlock’s core idea: probing a handful of social networks for the existence of a given username.

We’ll use plain Python 3, the standard library and the free‑tier requests package – no paid APIs, no Docker, just a few minutes of coding and you’ll have a working clone you can extend.

Before you start…

Minimal Sherlock Clone Architecture
LOCAL RUNTIME EXTERNAL SITES CLI Python Script Twitter.com GitHub.com Reddit.com
1

Phase 1: Scaffold the project

Create a new folder and a virtual environment; install the only dependency.

mkdir sherlock_clone && cd sherlock_clone
python3 -m venv .venv
source .venv/bin/activate
pip install --upgrade pip
pip install requests
2

Phase 2: Define the site list and URL builder

We store a tiny mapping of site name → URL pattern where {} will be replaced by the username.

sites.py

# sites.py – minimal site map for the clone
# The key is a friendly name, the value is a format string where `{}` becomes the username.
SITE_URLS = {
    "Twitter": "https://twitter.com/{}",
    "GitHub": "https://github.com/{}",
    "Reddit": "https://www.reddit.com/user/{}",
}

def build_url(site, username):
    """Return the full URL for *site* with *username* inserted.
    Raises KeyError if the site is unknown.
    """
    pattern = SITE_URLS[site]
    return pattern.format(username)
3

Phase 3: Core lookup logic (API)

In this step we create the heart of the clone: a function that walks through each social‑media site we support, builds the profile URL for the target username, and sends a simple GET request. If the response returns HTTP 200 we treat the username as found on that platform; any other status means the name is likely unavailable. The function returns a dictionary mapping site names to the full URL for successful hits, which the CLI will later display and store.

The implementation relies on the popular requests library because it handles redirects and timeouts gracefully out of the box. Keeping the logic isolated in its own module makes testing easy and lets the CLI stay focused on user interaction.

lookup.py

import requests
from urllib.parse import quote

# Simple site map – keys are readable names, values are URL patterns where {username} will be inserted.
SITES = {
    "GitHub": "https://github.com/{username}",
    "Twitter": "https://twitter.com/{username}",
    "Reddit": "https://www.reddit.com/user/{username}",
    "Instagram": "https://www.instagram.com/{username}/",
}

def check_username(username: str, timeout: float = 5.0) -> dict:
    """Return a dict of sites where *username* exists.

    The function iterates over :data:`SITES`, formats each URL, performs a GET request,
    and records the URL when the response status code is 200.
    """
    found = {}
    encoded = quote(username)  # ensure special characters are URL‑safe
    for site, pattern in SITES.items():
        url = pattern.format(username=encoded)
        try:
            resp = requests.get(url, timeout=timeout, allow_redirects=True)
            if resp.status_code == 200:
                found[site] = url
        except requests.RequestException:
            # Network hiccups or DNS failures are ignored – treat as not found.
            continue
    return found
4

Phase 4: CLI entry point (UI)

Now we expose the lookup functionality to the command line. Using Python's built‑in argparse we accept a single required argument – the username to search – and an optional --output-dir to control where result files are written. After calling check_username, we print a friendly summary to the console and also dump each successful URL into a text file named <username>.txt for later reference.

The script is deliberately lightweight: it imports only what it needs, handles missing results gracefully, and creates the output directory if it doesn't exist. This mirrors the minimal‑clone philosophy while still providing a useful user experience.

Running the script directly (e.g., python sherlock_clone.py alice) will trigger the full flow without any extra setup.

sherlock_clone.py

#!/usr/bin/env python3
import argparse
import os
from pathlib import Path
from lookup import check_username

def main() -> None:
    parser = argparse.ArgumentParser(
        description="Minimal Sherlock‑style username search across a few platforms"
    )
    parser.add_argument("username", help="The username to look up")
    parser.add_argument(
        "--output-dir",
        default=".",
        help="Directory where the result .txt file will be saved",
    )
    args = parser.parse_args()

    results = check_username(args.username)
    print(f"Results for '{args.username}':")
    if results:
        for site, url in results.items():
            print(f"  {site}: {url}")
    else:
        print("  No profiles found.")

    # Write results to a per‑user text file
    out_path = Path(args.output_dir) / f"{args.username}.txt"
    os.makedirs(out_path.parent, exist_ok=True)
    with open(out_path, "w", encoding="utf-8") as f:
        if results:
            for url in results.values():
                f.write(url + "\n")
        else:
            f.write("No profiles found.\n")
    print(f"\nSaved results to {out_path}")

if __name__ == "__main__":
    main()
5

Phase 5: Run locally and verify

With the code in place, it's time to see it work. First, ensure the script is executable (or invoke it via the Python interpreter) and run it with a sample username such as python. The console should list any discovered profiles and confirm the path of the generated text file.

Next, open the created <username>.txt file to verify that it contains the URLs reported on the screen. If the file exists and includes at least one URL, the minimal clone is functioning correctly.

chmod +x sherlock_clone.py  # make it executable (optional)
./sherlock_clone.py python   # run the clone for the username "python"
cat python.txt               # view the saved results

Verifying the Stack

CheckCommand / Why it matters
Python 3.9+ is activepython --version
requests package installed without errorspip show requests
Running the CLI prints a line starting with "Results for"./sherlock_clone.py python
A file named "python.txt" appears containing at least one URLcat python.txt

What’s next?

You now have a functional prototype. Extend it by adding more sites to the SITES dict, handling redirects, or outputting CSV/JSON. Happy hunting!