How to Automate Your Daily Workflow with Python Scripts

How to Automate Your Daily Workflow with Python Scripts

I used to start every morning the same way: open my email, copy numbers from three different spreadsheets into a summary report, rename and sort a folder full of downloaded files, check a handful of websites for updates, and then paste everything into a Slack message for my team. It took about 45 minutes. Every single day. I was essentially a very expensive copy-paste machine.

Then I spent one afternoon writing Python scripts to handle all of it. Now my morning “routine” takes zero minutes because it runs automatically before I even open my laptop. In this post, I’ll walk you through exactly how I did it — with full, runnable code you can adapt for your own workflow.


How to Automate Your Daily Workflow with Python Scripts

The Problem: Death by a Thousand Manual Tasks

Manual daily workflows share a few common characteristics that make them perfect automation targets:

  • They’re repetitive — you do the same steps in the same order every day
  • They’re rule-based — there’s no genuine human judgment involved
  • They’re error-prone — copy-pasting at 8 AM when you haven’t finished your coffee is a reliability disaster
  • They’re time-sinking — individually small, collectively enormous

Before automation, my morning stack looked like this:

  1. Download reports from two web sources
  2. Parse data from CSV files in a downloads folder
  3. Rename and organize files by date and type
  4. Generate a summary with key metrics
  5. Send the summary to a Slack channel

Time cost: ~45 minutes daily, ~165 hours per year.

python-automation.png

Let’s automate all five of those steps.


The Automation Approach

I used Python because it has excellent libraries for every piece of this puzzle, it reads almost like plain English, and it runs on every operating system. The full solution uses:

  • requests and BeautifulSoup for web fetching
  • pandas for CSV processing
  • os, shutil, and pathlib for file management
  • smtplib / slack_sdk for notifications
  • schedule for running everything on a timer
  • A simple .env file for storing credentials safely

The architecture is a single orchestration script that calls modular functions. Each function handles one job, which means you can swap pieces in and out without breaking everything else.


Implementation

Step 0: Set Up Your Environment

First, create a project folder and install the dependencies.

mkdir daily_automation
cd daily_automation
python -m venv venv
source venv/bin/activate        # On Windows: venv\Scripts\activate
pip install requests beautifulsoup4 pandas slack_sdk schedule python-dotenv

Create a .env file to store your secrets. Never hardcode credentials in your scripts.

# .env
SLACK_BOT_TOKEN=xoxb-your-token-here
SLACK_CHANNEL_ID=C0123456789
DOWNLOAD_DIR=/Users/yourname/Downloads
REPORT_DIR=/Users/yourname/Reports
EMAIL_ADDRESS=you@example.com
EMAIL_PASSWORD=your_app_password

Step 1: File Organization — Taming the Downloads Folder

Before (manual): Open Downloads, look at 40 files, drag CSVs to one folder, PDFs to another, rename each one with today’s date. About 10 minutes.

After (automated):

# file_organizer.py
import os
import shutil
from pathlib import Path
from datetime import datetime
from dotenv import load_dotenv

load_dotenv()

DOWNLOAD_DIR = Path(os.getenv("DOWNLOAD_DIR"))
REPORT_DIR = Path(os.getenv("REPORT_DIR"))

# Map file extensions to destination subfolder names
EXTENSION_MAP = {
    ".csv": "data/csv",
    ".xlsx": "data/excel",
    ".pdf": "documents/pdf",
    ".png": "images",
    ".jpg": "images",
    ".zip": "archives",
}

def organize_downloads():
    """
    Scans the Downloads folder, moves files to categorized subfolders,
    and renames them with a date prefix for easy sorting.
    """
    today = datetime.now().strftime("%Y-%m-%d")
    moved_count = 0

    for file_path in DOWNLOAD_DIR.iterdir():
        # Skip directories and hidden files (like .DS_Store)
        if file_path.is_dir() or file_path.name.startswith("."):
            continue

        extension = file_path.suffix.lower()
        subfolder = EXTENSION_MAP.get(extension, "misc")

        # Build destination path, creating folders if they don't exist
        destination_folder = REPORT_DIR / subfolder
        destination_folder.mkdir(parents=True, exist_ok=True)

        # Prefix filename with today's date to make sorting trivial
        new_filename = f"{today}_{file_path.name}"
        destination = destination_folder / new_filename

        # Handle name collisions by appending a counter
        counter = 1
        while destination.exists():
            stem = file_path.stem
            suffix = file_path.suffix
            destination = destination_folder / f"{today}_{stem}_{counter}{suffix}"
            counter += 1

        shutil.move(str(file_path), str(destination))
        moved_count += 1
        print(f"  Moved: {file_path.name} → {subfolder}/{new_filename}")

    print(f"[File Organizer] Done. {moved_count} files organized.")
    return moved_count

if __name__ == "__main__":
    organize_downloads()

Why this works: pathlib.Path makes file path handling clean and cross-platform. shutil.move() works across different drives, unlike os.rename() which fails when source and destination are on different filesystems. The collision-handling loop means you’ll never silently overwrite a file.

Step 2: Data Fetching and CSV Processing

Before (manual): Visit a URL, click download, wait, open the CSV, copy specific columns, paste into a master sheet. Repeat for multiple sources. About 15 minutes.

After (automated):

“`python

data_fetcher.py

import requests import pandas as pd from pathlib import Path from datetime import datetime import os from dotenv import load_dotenv

load_dotenv()

REPORT_DIR = Path(os.getenv(“REPORT_DIR”))

— Web Data Fetching —

def fetch_csv_from_url(url: str, filename: str) -> Path: “”” Downloads a CSV from a URL and saves it locally. Returns the path to the saved file.

We stream the download so large files don't blow out memory.
"""
today = datetime.now().strftime("%Y-%m-%d")
save_path = REPORT_DIR / "data" / "csv" / f"{today}_{filename}"
save_path.parent.mkdir(parents=True, exist_ok=True)

headers = {
    "User-Agent": "Mozilla/5.0 (compatible; DailyBot/1.0)"
}

response = requests.get(url, headers=headers, stream=True, timeout=30)
response.raise_for_status()  # Raises an exception for 4xx/5xx responses

with open(save_path, "wb") as f:
    for chunk in response.iter_content(chunk_size=8192):
        f.write(chunk)

print(f"[Data Fetcher] Downloaded: {save_path.name}")
return save_path

— CSV Processing —

def process_sales_csv(file_path: Path) -> dict: “”” Reads a sales CSV and extracts the key metrics we report each morning. Returns a dictionary of summary statistics.

Using pandas here because it handles messy CSVs (mixed types, empty rows)
much more gracefully than the built-in csv module.
"""
df = pd.read_csv(file_path, skipinitialspace=True)

# Normalize column names: lowercase, replace spaces with underscores
df.columns = df.columns.str.lower().str.replace(" ", "_")

# Drop completely empty rows that often appear in exported spreadsheets
df.dropna(how="all", inplace=True)

# Convert the amount column to numeric, coercing errors (like "$1,200") to NaN
df["amount"] = pd.to_numeric(

More in Automation.

Leave a Reply

Your email address will not be published. Required fields are marked *.

*
*