Skip to content
Muhammet Şafak
tr
Languages 4 min read

Automating repetitive tasks with Python

How to move manual workflows into reliable Python scripts: which tasks are worth scripting and how to do it right.


When you find yourself doing the same workflow for the third time by hand, something should happen: write the script. This rule applies in any language, but Python is a particularly good fit for the job — minimal syntax, a broad standard library, and an ecosystem built exactly for this kind of work.

In this post I want to share my thinking on scripting repetitive tasks, along with a few patterns I use in practice. Not large automation frameworks or orchestration tools — just concrete, hands-on scripts.

Recognizing what’s worth scripting

Not every repetitive task is worth automating. I ask these questions:

  • How often does this happen? It should be multiple times a day or every day — not once a week.
  • Are the steps fixed, or does each run require different judgment calls? Tasks with fixed steps can be scripted; decision-heavy tasks generally can’t.
  • Is there error risk? Is it easy to skip a step, write to the wrong directory, or delete a file when doing this by hand?

The more yes answers accumulate, the higher the value of the script.

File operations: simple but common

Renaming files in a directory according to a rule, moving files with certain extensions to another folder, merging a large number of CSV files — these are tasks you can write with Python’s standard library in minutes.

import os
import shutil
from pathlib import Path

def move_by_extension(source_dir: str, target_dir: str, extension: str) -> int:
    source = Path(source_dir)
    target = Path(target_dir)
    target.mkdir(parents=True, exist_ok=True)

    moved = 0
    for file in source.glob(f"*.{extension}"):
        dest = target / file.name
        if dest.exists():
            print(f"Atlandı (zaten var): {file.name}")
            continue
        shutil.move(str(file), str(dest))
        moved += 1

    return moved

if __name__ == "__main__":
    count = move_by_extension("./indirilenler", "./arsiv/pdf", "pdf")
    print(f"{count} dosya taşındı.")

I prefer pathlib over os.path — it’s more readable and object-oriented. shutil.move handles the actual move in a platform-independent way.

Fetching data from external APIs

Having to regularly pull and process data from a third-party service is extremely common. Python’s requests library makes this straightforward:

import requests
import json
from datetime import datetime

def fetch_and_save(api_url: str, output_file: str) -> None:
    response = requests.get(api_url, timeout=10)
    response.raise_for_status()  # raises on 4xx/5xx responses

    data = response.json()

    with open(output_file, "w", encoding="utf-8") as f:
        json.dump({
            "fetched_at": datetime.utcnow().isoformat(),
            "count": len(data),
            "data": data,
        }, f, ensure_ascii=False, indent=2)

    print(f"{len(data)} kayıt kaydedildi: {output_file}")

raise_for_status() is a small but important habit. It prevents silent failures — if the response isn’t 200 you get an early, explicit error right there, not buried somewhere in the data-processing logic.

A few habits for reliable scripts

Writing a script is fast; writing a reliable script takes a bit more care.

Idempotency: Running the script twice should not undo what the first run did. Skip the file if it already exists, skip the record if it has already been processed. The if dest.exists(): continue in the example above is a small but solid illustration of this.

Error handling: Not sprinkling try/except everywhere, but making sure that when something fails you know what failed and why. The exception message should carry enough information to diagnose the problem.

Execution logging: A simple logging mechanism, especially for scheduled scripts. print is enough in most cases; for more critical scripts, Python’s logging module.

Argument support: Don’t hard-code values inside the script. Use argparse or sys.argv so the script can accept parameters from the outside. This improves testability and makes the script usable across different environments.

import argparse

parser = argparse.ArgumentParser(description="Dosya taşıma betiği")
parser.add_argument("source", help="Kaynak klasör")
parser.add_argument("target", help="Hedef klasör")
parser.add_argument("--ext", default="pdf", help="Dosya uzantısı (varsayılan: pdf)")
args = parser.parse_args()

When to reach for Python instead of PHP or Go

I work with all three languages, and for automation tasks I usually reach for Python. The reason is simple: Python’s standard library is ready-made for this kind of work. csv, json, os, shutil, pathlib, argparse, logging — you can get a lot done without pulling in extra dependencies.

PHP works too, of course — but PHP’s execution model is oriented toward web requests. You can use it for scripts, but the ecosystem isn’t focused in that direction. Go’s binary distribution is a strong advantage, but for small internal tools the compile cycle creates extra friction.

With Python you write fast, you iterate fast, and it works. A handful of simple habits is all it takes for your scripts to be reliable and readable. It’s the right tool for this job.

If you see a repetitive task, write the script. Then make that script reusable and reliable. Over time, that cycle compounds into a significant productivity gain.

Tags: #Python
Share:

Comments

Sign in with your GitHub account to join the discussion. Comments are stored in GitHub Discussions.

Related Posts

Search the site

Start typing to search posts, projects and pages.

Esc to close Powered by Pagefind