.22 Apartment .22 Programming

Small scripts, built to spec, priced before you start.

A web scraper. A spreadsheet that cleans itself up. A bot that does one boring task on a schedule. You describe the job, we quote a fixed price, you get working code — no subscriptions, no scope creep.

WORK ORDER — APT.22-0001 QUOTED IN 24H
SERVICE Pull daily prices from 12 supplier sites
DELIVERABLE Python script + scheduled run
TURNAROUND 3 business days
PRICE Fixed, quoted up front

What gets built here

Three kinds of jobs come through most often. If yours doesn't fit neatly into one, describe it on the waitlist form below — most scripting work fits somewhere in between.

SCRAPING

Web scrapers

Pull listings, prices, contact info, or postings from sites you check by hand. Delivered as a script you can run yourself or schedule.

Typical scope1–3 sites
SPREADSHEETS

Excel & data cleanup

Messy exports, inconsistent formatting, manual copy-pasting between sheets — turned into a script that does it in seconds.

Typical scope1 recurring report
BOTS

Small bots

A script that watches for something and reacts — sends an alert, files a record, posts an update. Runs quietly in the background.

Typical scopeSingle trigger, single action

How a job runs

The same four steps every time, so you know what a job costs before any code gets written.

01

Describe the task

What you do by hand today, and how often. Screenshots or a sample file help but aren't required.

02

Get a fixed quote

A price and a turnaround date, based on the actual scope — not an hourly estimate that can drift.

03

Review a working draft

You see the script run against your real data before final delivery, so there are no surprises at handoff.

04

Take the code

You get the script and a short note on running it. No retainer, no lock-in — hire again only if there's a next job.

See it run, not just described

A real before/after from a test run, plus the actual scripts behind each service line — not mockups.

Spreadsheet cleanup — real before/after

7 messy signup rows in → 6 clean rows out. Inconsistent casing, mixed date formats, mixed phone formats, and one duplicate — all fixed automatically, with missing data flagged rather than hidden.

FieldBeforeAfter
Name" ROBERT CHEN"Robert Chen
EmailJANE.DOE@EMAIL.COMjane.doe@email.com
Phone555.111.2222(555) 111-2222
Date3/17/262026-03-17
Missing phone(blank)MISSING (flagged)
Duplicate rowpresent twiceremoved

The actual code

Each of these is a real script, not a snippet — expand to read the full source.

cleanup_spreadsheet.py tested — verified output above
def clean_phone(raw):
    if pd.isna(raw) or str(raw).strip() == "":
        return "MISSING"
    digits = re.sub(r"\D", "", str(raw))
    if len(digits) == 10:
        return f"({digits[0:3]}) {digits[3:6]}-{digits[6:10]}"
    return str(raw).strip()

def clean_date(raw):
    raw = str(raw).strip()
    for fmt in ["%m/%d/%Y", "%m/%d/%y", "%Y-%m-%d", "%Y/%m/%d"]:
        try:
            return datetime.strptime(raw, fmt).strftime("%Y-%m-%d")
        except ValueError:
            continue
    return "UNPARSEABLE: " + raw

def clean_name(raw):
    if pd.isna(raw) or str(raw).strip() == "":
        return "MISSING"
    return str(raw).strip().title()

# ...reads messy_sample.csv, cleans every column, drops
# exact duplicates, writes a formatted cleaned_output.xlsx
watch_and_process_bot.py tested — caught & processed a file in seconds
def process_file(filepath):
    df = pd.read_csv(filepath)
    df.columns = [c.strip() for c in df.columns]
    if "Full Name" in df.columns:
        df["Full Name"] = df["Full Name"].apply(clean_name)
    if "Phone Number" in df.columns:
        df["Phone Number"] = df["Phone Number"].apply(clean_phone)
    # ...cleans and saves as .xlsx, then archives
    # the original file with a timestamp

# Polls a folder every 2 seconds; the moment a new
# .csv appears, it's cleaned and archived automatically —
# no one has to remember to run anything by hand.
scrape_demo.py correct & ready — run locally to see live output
def parse_page(html):
    soup = BeautifulSoup(html, "html.parser")
    rows = []
    for block in soup.select(".quote"):
        text = block.select_one(".text").get_text(strip=True)
        author = block.select_one(".author").get_text(strip=True)
        tags = [t.get_text(strip=True) for t in block.select(".tag")]
        rows.append({"quote": text, "author": author, "tags": ", ".join(tags)})
    return rows

# Walks every page of results automatically, with a polite
# delay between requests, and writes everything to one CSV.

Join the waitlist

Apartment .22 is opening up its first slots. Leave your email and, if you've got one, the task you'd want scripted first — you'll hear back with a quote when a slot opens.

One email, no spam. Used only to send your quote when a slot opens.