Automation

Automate Repetitive Tasks with Python: A Practical Guide

Stop doing manually what your computer can do for you. Learn how to automate file management, web scraping, email sending, and scheduling with Python.

April 10, 20269 min read
Share
Advertisement (not configured)

Introduction

Every developer has tasks they do manually that they know should be automated: renaming hundreds of files, sending weekly report emails, downloading data from a website, or backing up a folder. Python is the best tool for all of this.

In this guide, we'll build four real automation scripts:

  1. Bulk file organizer
  2. Web scraper for data collection
  3. Automated email sender
  4. Task scheduler

Each script is standalone and production-ready.

1. Automate File Organization

If your Downloads folder looks like a crime scene, this script will clean it up automatically. It sorts files into subfolders based on their extension:

import shutil
from pathlib import Path

FOLDER_MAP = {
    "Images": [".jpg", ".jpeg", ".png", ".gif", ".svg", ".webp"],
    "Documents": [".pdf", ".docx", ".doc", ".txt", ".xlsx", ".csv"],
    "Videos": [".mp4", ".mov", ".avi", ".mkv"],
    "Audio": [".mp3", ".wav", ".flac", ".aac"],
    "Code": [".py", ".js", ".ts", ".html", ".css", ".json"],
    "Archives": [".zip", ".tar", ".gz", ".rar"],
}

def get_destination(extension: str) -> str:
    for folder, extensions in FOLDER_MAP.items():
        if extension.lower() in extensions:
            return folder
    return "Other"

def organize_folder(folder_path: str) -> dict:
    folder = Path(folder_path)
    moved = {}

    for file in folder.iterdir():
        if not file.is_file():
            continue

        destination_name = get_destination(file.suffix)
        destination = folder / destination_name
        destination.mkdir(exist_ok=True)

        new_path = destination / file.name
        # Handle duplicates
        counter = 1
        while new_path.exists():
            stem = file.stem
            new_path = destination / f"{stem}_{counter}{file.suffix}"
            counter += 1

        shutil.move(str(file), str(new_path))
        moved[str(file)] = str(new_path)

    return moved

if __name__ == "__main__":
    downloads = Path.home() / "Downloads"
    result = organize_folder(str(downloads))
    print(f"Moved {len(result)} files.")
    for src, dst in result.items():
        print(f"  {Path(src).name}{Path(dst).parent.name}/")

Run this once and it will sort everything. Schedule it to run weekly and your Downloads folder stays clean forever.

2. Web Scraping for Data Collection

Let's scrape job listings from a public jobs board. We'll use requests and BeautifulSoup — the two most practical scraping libraries:

import time
import csv
import requests
from bs4 import BeautifulSoup
from dataclasses import dataclass, fields, astuple

@dataclass
class Job:
    title: str
    company: str
    location: str
    url: str
    posted: str

def scrape_python_jobs(base_url: str, pages: int = 3) -> list[Job]:
    jobs = []
    headers = {"User-Agent": "Mozilla/5.0 (compatible; JobScraper/1.0)"}

    for page in range(1, pages + 1):
        url = f"{base_url}?page={page}"
        response = requests.get(url, headers=headers, timeout=10)
        response.raise_for_status()

        soup = BeautifulSoup(response.text, "html.parser")
        listings = soup.select(".job-listing")  # Adjust selector to target site

        for listing in listings:
            job = Job(
                title=listing.select_one(".job-title").get_text(strip=True),
                company=listing.select_one(".company-name").get_text(strip=True),
                location=listing.select_one(".location").get_text(strip=True),
                url=listing.select_one("a")["href"],
                posted=listing.select_one(".date-posted").get_text(strip=True),
            )
            jobs.append(job)

        print(f"Page {page}: found {len(listings)} jobs")
        time.sleep(1)  # Be respectful to the server

    return jobs

def save_to_csv(jobs: list[Job], filename: str):
    with open(filename, "w", newline="", encoding="utf-8") as f:
        writer = csv.writer(f)
        writer.writerow([f.name for f in fields(Job)])
        writer.writerows([astuple(job) for job in jobs])

if __name__ == "__main__":
    all_jobs = scrape_python_jobs("https://example-jobs.com/python", pages=5)
    save_to_csv(all_jobs, "python_jobs.csv")
    print(f"Saved {len(all_jobs)} jobs to python_jobs.csv")

Always respect robots.txt and add delays between requests. Never hammer a server.

3. Automated Email Sending

Sending weekly reports, notifications, or digest emails manually is a time sink. Python's smtplib plus Gmail handles this perfectly:

import smtplib
import os
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
from email import encoders
from pathlib import Path

class EmailSender:
    def __init__(self, gmail_address: str, app_password: str):
        self.address = gmail_address
        self.password = app_password

    def send(
        self,
        to: list[str],
        subject: str,
        body_html: str,
        attachments: list[str] | None = None,
    ) -> bool:
        msg = MIMEMultipart("alternative")
        msg["From"] = self.address
        msg["To"] = ", ".join(to)
        msg["Subject"] = subject
        msg.attach(MIMEText(body_html, "html"))

        for filepath in (attachments or []):
            path = Path(filepath)
            if not path.exists():
                continue
            part = MIMEBase("application", "octet-stream")
            part.set_payload(path.read_bytes())
            encoders.encode_base64(part)
            part.add_header("Content-Disposition", f'attachment; filename="{path.name}"')
            msg.attach(part)

        try:
            with smtplib.SMTP_SSL("smtp.gmail.com", 465) as server:
                server.login(self.address, self.password)
                server.sendmail(self.address, to, msg.as_string())
            return True
        except Exception as e:
            print(f"Email failed: {e}")
            return False


def send_weekly_report(recipients: list[str], stats: dict):
    sender = EmailSender(
        gmail_address=os.environ["GMAIL_ADDRESS"],
        app_password=os.environ["GMAIL_APP_PASSWORD"],
    )

    html = f"""
    <h2>Weekly Report</h2>
    <table border="1" cellpadding="8" style="border-collapse: collapse;">
      <tr><td><b>Total Users</b></td><td>{stats['users']}</td></tr>
      <tr><td><b>New Signups</b></td><td>{stats['signups']}</td></tr>
      <tr><td><b>Revenue</b></td><td>${stats['revenue']}</td></tr>
    </table>
    <p>Generated automatically by Python.</p>
    """

    success = sender.send(recipients, "Weekly Report", html)
    print("Report sent!" if success else "Failed to send report.")

For Gmail, use an App Password (not your regular password). Enable 2FA first, then generate one at myaccount.google.com/apppasswords.

4. Scheduling Tasks with Python

Instead of relying on cron or Task Scheduler, you can run Python-based schedules within your script:

import schedule
import time
import logging
from datetime import datetime

logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s — %(message)s",
    datefmt="%Y-%m-%d %H:%M",
)

def organize_downloads():
    logging.info("Running: organize downloads")
    # Call your organize_folder() here
    logging.info("Done: downloads organized")

def send_daily_report():
    logging.info("Sending daily report...")
    # Call your send_weekly_report() here
    logging.info("Done: report sent")

def backup_database():
    logging.info("Backing up database...")
    # pg_dump or similar
    logging.info("Done: backup complete")

# Configure your schedule
schedule.every().monday.at("09:00").do(organize_downloads)
schedule.every().day.at("18:00").do(send_daily_report)
schedule.every().day.at("02:00").do(backup_database)
schedule.every(30).minutes.do(lambda: logging.info("Heartbeat — scheduler running"))

if __name__ == "__main__":
    logging.info("Scheduler started")
    while True:
        schedule.run_pending()
        time.sleep(60)

Run this in the background on your server or local machine with:

nohup python scheduler.py > scheduler.log 2>&1 &

Or wrap it in a systemd service on Linux for automatic startup on reboot.

Putting It All Together

You've now got four automation scripts that solve real problems:

Script Time saved Complexity
File organizer 10 min/week Low
Web scraper Hours of manual data entry Medium
Email sender 30 min/week Low
Task scheduler Eliminates manual reminders Medium

The real power of automation isn't any single script — it's the habit of recognizing repeated work and writing a script for it. Next time you find yourself doing something for the third time, open a Python file.

Install the required packages:

pip install requests beautifulsoup4 schedule

These four scripts are your foundation. Combine them, extend them, and build bigger automations on top. That's how you turn Python into a personal productivity superpower.

Advertisement (not configured)

Written by

Raretechsol

Software company from Pakistan, specializing in Python and JavaScript. Passionate about automation, AI, and building practical web applications.

Related Articles