Dari Notebook ke Skrip Terjadwal: Menaikkan Level Analisis Pythonmu
Blog/Tips & Trik/Dari Notebook ke Skrip Terjadwal: Menaikkan Level Analisis Pythonmu

Dari Notebook ke Skrip Terjadwal: Menaikkan Level Analisis Pythonmu

BimaBima
·28 September 2025·12 menit baca

Penulis

Bima

Bima

Founder & Data Professional

Bagikan

TL;DR

Cara ubah Jupyter Notebook jadi skrip terjadwal ada empat langkah: ekspor notebook jadi file .py, rapikan isinya jadi fungsi dengan satu entry point, pindahin konfigurasi dan rahasia ke file .env, lalu daftarkan ke cron di Linux atau Task Scheduler di Windows. Tambahin logging supaya kamu tau skripnya gagal tanpa harus buka terminal.

Cara ubah Jupyter Notebook jadi skrip terjadwal itu empat langkah: ekspor jadi file .py, rapikan isinya jadi fungsi, pindahin konfigurasi ke file terpisah, lalu daftarkan ke penjadwal sistem.

Notebook itu tempat mikir. Kamu jalanin sel, lihat hasilnya, ganti angka, jalanin lagi.

Masalahnya muncul waktu analisis itu jadi kerjaan rutin. Tiap Senin pagi kamu buka laptop, buka notebook, klik Run All, tungguin, lalu kirim hasilnya ke grup WhatsApp.

Aku ngelakuin itu selama 7 bulan sebelum sadar total waktunya 21 jam setahun cuma buat nungguin dan copy-paste. Skrip yang gantiin kerjaan itu jalannya 11 detik dan aku gak perlu buka laptop.

Kenapa notebook gak cocok buat kerjaan rutin?

Karena notebook nyimpen urutan eksekusi, bukan urutan kode. Sel nomor 12 bisa aja dijalanin sebelum sel nomor 3, dan hasilnya tetap kelihatan bener di layar. Begitu file itu dijalanin dari atas ke bawah oleh mesin, error muncul di tempat yang gak kamu duga.

Ada empat sifat notebook yang jadi masalah pas dijadwalin:

  • State tersembunyi. Variabel dari sel yang udah kamu hapus masih nyangkut di memori.
  • Gak ada exit code. Sistem penjadwal gak tau skripmu berhasil atau gagal.
  • Path relatif ke folder notebook. Pindah folder, semuanya rusak.
  • Diff di git berantakan. Output gambar ikut kesimpan dalam bentuk teks base64 yang panjangnya ribuan baris.

Notebook tetap berguna. Pakai buat eksplorasi awal dan buat presentasi hasil. Buat yang jalan tiap hari, pindahin ke file .py.

Gimana cara ubah notebook jadi skrip Python?

Mulai dari ekspor otomatis, lalu rapikan manual. Perintah nbconvert bawaan Jupyter ngubah notebook jadi file .py dalam sekali jalan, tapi hasilnya masih berupa kode berurutan tanpa struktur. Bagian rapikannya yang bikin skrip kamu tahan dijadwalin.

jupyter nbconvert --to script analisis-penjualan.ipynb

Hasilnya analisis-penjualan.py yang isinya semua sel digabung, lengkap dengan komentar nomor sel. Jangan langsung dijadwalin. Ada lima hal yang harus kamu benerin dulu.

  1. Hapus semua kode eksplorasi. Baris df.head(), print(df.shape), dan plot yang cuma buat lihat-lihat.
  2. Kumpulin semua import ke atas. Notebook sering punya import yang nyebar di tengah.
  3. Bungkus tiap tahap jadi fungsi. Satu fungsi satu tugas.
  4. Pindahin angka dan path ke satu tempat. Jangan ada nilai yang ketik langsung di tengah logika.
  5. Tambahin entry point. Blok if __name__ == "__main__": di paling bawah.

Gimana struktur skrip yang enak dijadwalin?

Pola yang aku pakai selalu sama: konfigurasi di atas, fungsi-fungsi kecil di tengah, satu fungsi main() yang ngatur urutan, entry point di bawah. Struktur ini bikin kamu bisa tes satu bagian tanpa jalanin semuanya.

"""Rekap penjualan harian Toko Berkah."""

import logging
import os
from datetime import date, timedelta
from pathlib import Path

import pandas as pd

FOLDER_DATA = Path(os.environ.get("FOLDER_DATA", "./data"))
FOLDER_OUTPUT = Path(os.environ.get("FOLDER_OUTPUT", "./output"))
AMBANG_MINIMAL_BARIS = 50


def ambil_data(tanggal: date) -> pd.DataFrame:
    berkas = FOLDER_DATA / f"penjualan-{tanggal:%Y-%m-%d}.csv"
    if not berkas.exists():
        raise FileNotFoundError(f"File {berkas} gak ketemu")
    return pd.read_csv(berkas, parse_dates=["tanggal"])


def bersihin(df: pd.DataFrame) -> pd.DataFrame:
    df = df.dropna(subset=["cabang", "nilai"])
    df = df[df["nilai"] > 0]
    return df


def ringkas(df: pd.DataFrame) -> pd.DataFrame:
    hasil = (
        df.groupby("cabang", as_index=False)
        .agg(transaksi=("nilai", "size"), omzet=("nilai", "sum"))
        .sort_values("omzet", ascending=False)
    )
    return hasil


def simpan(df: pd.DataFrame, tanggal: date) -> Path:
    FOLDER_OUTPUT.mkdir(parents=True, exist_ok=True)
    tujuan = FOLDER_OUTPUT / f"rekap-{tanggal:%Y-%m-%d}.csv"
    df.to_csv(tujuan, index=False)
    return tujuan


def main() -> None:
    tanggal = date.today() - timedelta(days=1)
    logging.info("Mulai rekap untuk %s", tanggal)

    df = ambil_data(tanggal)
    if len(df) < AMBANG_MINIMAL_BARIS:
        raise ValueError(f"Cuma {len(df)} baris, di bawah ambang wajar")

    hasil = simpan(ringkas(bersihin(df)), tanggal)
    logging.info("Selesai. Output di %s", hasil)


if __name__ == "__main__":
    main()

Perhatiin pengecekan AMBANG_MINIMAL_BARIS. Ini penjaga sederhana yang bikin skrip berhenti kalau data sumbernya cuma sebagian. Tanpa itu, skrip bakal tetap sukses dan kirim laporan omzet yang salah.

Cek kewarasan kayak gini bagian dari jaga data quality. Lebih baik gagal berisik daripada berhasil dengan angka ngawur.

Gimana cara pisahin rahasia dan konfigurasi dari kode?

Simpan di file .env dan baca lewat os.environ. Password database, token API, dan path folder beda antara laptop kamu dan server. Kalau nilainya ketik langsung di kode, skripmu cuma jalan di satu tempat dan rahasianya ikut ke-push ke git.

# file .env
DB_HOST=10.20.30.40
DB_USER=analis_readonly
DB_PASSWORD=rahasia-banget
FOLDER_DATA=/srv/data/penjualan
FOLDER_OUTPUT=/srv/output/rekap
from dotenv import load_dotenv
import os

load_dotenv()

DB_HOST = os.environ["DB_HOST"]
DB_PASSWORD = os.environ["DB_PASSWORD"]

Install dulu pakai pip install python-dotenv. Lalu tambahin .env ke file .gitignore kamu, ini langkah yang paling sering kelupaan.

Pakai os.environ["NAMA"] dengan kurung siku buat nilai yang wajib ada. Kalau variabelnya kosong, skrip langsung gagal di awal, bukan setengah jalan.

Gimana cara nambahin logging biar tau kalau gagal?

Ganti semua print() jadi logging. Bedanya, logging otomatis nyatet waktu kejadian, tingkat keparahan, dan bisa nulis ke file sekaligus ke layar. Waktu skrip jalan jam 6 pagi tanpa ada yang nonton, file log itu satu-satunya jejak.

import logging
from logging.handlers import RotatingFileHandler

def siapin_log(path_log: str = "rekap.log") -> None:
    berkas = RotatingFileHandler(path_log, maxBytes=1_000_000, backupCount=5)
    logging.basicConfig(
        level=logging.INFO,
        format="%(asctime)s | %(levelname)s | %(message)s",
        handlers=[berkas, logging.StreamHandler()],
    )

RotatingFileHandler bikin file log dipotong tiap 1 MB dan nyimpen 5 file terakhir. Tanpa itu, log kamu bisa jadi 4 GB dalam setahun.

Bungkus main() supaya error kecatat lengkap dan exit code-nya bener:

import sys

if __name__ == "__main__":
    siapin_log()
    try:
        main()
    except Exception:
        logging.exception("Rekap gagal")
        sys.exit(1)

sys.exit(1) itu yang bikin cron dan tool monitoring tau skripnya gagal. Tanpa baris ini, skrip yang error tetap dianggap sukses.

Penjelasan lengkap tiap level dan handler ada di panduan logging resmi Python.

Gimana cara menjadwalkan skripnya?

Pilihannya tergantung tempat skripmu jalan. Di Linux dan macOS pakai cron, di Windows pakai Task Scheduler, di cloud pakai GitHub Actions atau layanan sejenis. Tiga-tiganya butuh satu hal yang sama: path lengkap ke interpreter Python di dalam virtual environment kamu.

CaraCocok buatKelebihanYang perlu diperhatiin
cronServer Linux, MacBawaan sistem, ringanEnvironment minim, path harus lengkap
Task SchedulerLaptop atau server WindowsAda antarmuka grafisLaptop harus nyala
GitHub ActionsSkrip yang cuma butuh internetGak perlu server sendiriJadwalnya pakai zona waktu UTC
AirflowBanyak skrip yang saling nungguRetry dan pantauan lengkapBerat buat 1-2 skrip doang

Setting cron

Buka daftar jadwal pakai crontab -e, lalu tambahin satu baris:

0 6 * * * cd /srv/rekap && /srv/rekap/venv/bin/python /srv/rekap/rekap_harian.py >> /srv/rekap/cron.log 2>&1

Lima angka di depan artinya menit, jam, tanggal, bulan, hari. Contoh di atas jalan tiap hari jam 6 pagi.

Bagian cd /srv/rekap penting kalau skripmu baca file pakai path relatif. Bagian 2>&1 bikin pesan error ikut kesimpan ke log, bukan hilang.

Setting Task Scheduler di Windows

Lewat command prompt, satu baris ini bikin tugas harian jam 6 pagi:

schtasks /create /tn "Rekap Harian" /tr "C:\rekap\venv\Scripts\python.exe C:\rekap\rekap_harian.py" /sc daily /st 06:00

Setting GitHub Actions

Simpan sebagai .github/workflows/rekap.yml:

name: Rekap Harian
on:
  schedule:
    - cron: "0 23 * * *"   # 23:00 UTC = 06:00 WIB
  workflow_dispatch:

jobs:
  rekap:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: "3.12"
      - run: pip install -r requirements.txt
      - run: python rekap_harian.py
        env:
          DB_PASSWORD: ${{ secrets.DB_PASSWORD }}

Jadwal di GitHub Actions selalu dihitung pakai UTC. WIB itu UTC plus 7, jadi jam 6 pagi WIB ditulis sebagai 23:00 hari sebelumnya. Ini jebakan yang bikin banyak orang bingung kenapa skripnya jalan sore.

Contoh kasus: rekap harian Toko Berkah

Toko Berkah punya 4 cabang. Tiap pagi, supervisor butuh rekap omzet kemarin sebelum briefing jam 7.

Sebelumnya, satu staf datang jam 6 pagi buat buka notebook, jalanin semua sel, screenshot tabelnya, lalu kirim ke grup. Rata-rata 38 menit termasuk nunggu laptop nyala.

Setelah dijadwalin, skripnya jalan jam 5.30 dan hasilnya masuk grup jam 5.31. Waktu eksekusinya 11 detik buat 4 cabang dengan rata-rata 640 transaksi per hari.

Efek samping yang gak diduga: karena skripnya berhenti waktu data kurang dari 50 baris, mereka nemu masalah sinkronisasi kasir cabang Godean yang selama 3 bulan diam-diam kehilangan transaksi sore. Rata-rata 22 transaksi per hari gak kecatat.

Masalah itu gak pernah kelihatan waktu rekapnya manual, soalnya orang cuma lihat angka totalnya dan ngerasa wajar.

Kesalahan umum waktu pindah ke skrip terjadwal

1. Pakai path relatif

Cron gak jalan dari folder skripmu. Tulis Path(__file__).parent buat dapetin lokasi file, atau pindah direktori dulu di perintah cron-nya.

2. Lupa aktifin virtual environment

Perintah python di cron nunjuk ke Python sistem yang gak punya pandas. Tulis path lengkap ke venv/bin/python.

3. Gak ada notifikasi sama sekali

Skrip yang gagal diam-diam lebih berbahaya dari skrip yang gak pernah dibuat. Minimal kirim satu pesan ke Slack atau email waktu terjadi error.

4. Nulis file output dengan nama yang sama terus

Kalau skrip jalan dua kali, versi lamanya hilang. Sisipin tanggal di nama file, kayak rekap-2025-09-28.csv.

5. Skrip jalan sebelum data sumbernya siap

Kalau proses ETL di hulu selesai jam 5.15, jangan jadwalin skripmu jam 5.00. Kasih jarak, atau bikin skripmu nunggu sampai file sumbernya muncul.

FAQ

Bisa gak jadwalin file .ipynb langsung tanpa diubah ke .py?

Bisa pakai papermill atau nbconvert dengan flag execute, dan itu masuk akal kalau outputnya memang notebook berisi grafik buat dibagikan. Tapi buat kerjaan rutin, file .py lebih gampang di-debug, lebih ringan dijalanin, dan riwayat perubahannya kebaca jelas di git. Notebook nyimpen output sekalian, jadi diff-nya berantakan.

Kenapa skripku jalan di terminal tapi gagal waktu dijadwalin cron?

Hampir selalu karena path. Cron jalan dengan environment yang minim, jadi perintah python biasa belum tentu nunjuk ke virtual environment kamu. Tulis path lengkap ke interpreter di dalam venv dan path lengkap ke file skripnya. Tambahin juga baris pindah direktori kerja kalau skripmu baca file dengan path relatif.

Gimana cara nyimpen password database dengan aman di skrip Python?

Jangan pernah tulis langsung di kode. Simpan di file .env yang gak ikut masuk git, lalu baca pakai os.environ. Di server produksi, isi variabelnya lewat environment variable sistem atau secret manager. Kalau skripnya jalan di GitHub Actions, taruh di menu Secrets repositori kamu.

Berapa sering sebaiknya skrip analisis dijadwalin?

Ikutin ritme keputusannya, bukan ritme datanya. Kalau tim baca laporan tiap pagi sebelum briefing, jadwalin jam 6 pagi sekali sehari. Jadwal tiap jam cuma masuk akal kalau ada orang yang beneran ambil tindakan tiap jam. Frekuensi berlebihan cuma nambah beban server dan bikin notifikasi gagal jadi diabaikan.

Gimana cara tau kalau skrip terjadwalku gagal jalan?

Pasang logging ke file dan kirim notifikasi saat terjadi error. Bungkus proses utama pakai try except, catat pesan lengkapnya pakai logging.exception, lalu kirim ke email atau webhook Slack. Kasih juga notifikasi sukses ringkas biar kamu bisa bedain antara skrip berhasil dan skrip yang gak pernah jalan sama sekali.

Langkah berikutnya

Empat hal yang bikin skrip kamu tahan jalan tanpa dipantengin: struktur fungsi dengan satu entry point, konfigurasi di file .env, logging ke file, dan pengecekan kewarasan data sebelum hasilnya dipakai.

Mulai dari satu notebook yang paling sering kamu jalanin ulang. Ekspor, rapikan, jadwalin. Butuh sekitar dua jam buat yang pertama, dan 20 menit buat yang kedua.

Kalau sumber datamu masih berupa file PDF, gabungin dulu sama teknik di artikel ekstrak tabel PDF dengan Python. Dan buat bikin tahap eksplorasi di notebook lebih cepat, ada 28 trik Jupyter Notebook yang layak dicoba.

Skrip pertama kamu jadwalin buat kerjaan yang mana? Ceritain di komentar.

Coba Langsung

Mau praktek langsung? Mulai latihan SQL gratis

Latihan interaktif, langsung di browser.

Buka NgulikSQL →
Bagikan:
Bima
Ditulis oleh

Bima

Founder & Data Professional

Founder Ngulik Data. Passionate about making data analysis accessible for everyone.

Artikel terkait

Pandas groupby: Agregasi Data ala Pivot di Python (2026)
Tips & Trik
20 Juli 2026•9 menit baca

Pandas groupby: Agregasi Data ala Pivot di Python (2026)

groupby ngelompokin baris berdasarkan kolom, lalu ngitung ringkasan per grup kayak total atau rata-rata. Ini pivot-nya pandas.

BimaBima
Pandas to_excel: Ekspor DataFrame ke Excel (2026)
Tips & Trik
18 Juli 2026•8 menit baca

Pandas to_excel: Ekspor DataFrame ke Excel (2026)

to_excel nyimpen DataFrame pandas jadi file Excel .xlsx. Ini cara pakainya, dari satu sheet sampai banyak sheet, plus setelan yang bikin hasilnya rapi.

BimaBima
Pandas read_excel: Baca File Excel di Python
Tips & Trik
16 Juli 2026•8 menit baca

Pandas read_excel: Baca File Excel di Python

pandas read_excel baca file Excel jadi DataFrame, bisa pilih sheet tertentu dan lompatin baris judul yang berantakan. Ini cara pakai plus parameter penting dengan contoh data toko.

BimaBima
Kembali ke Blog
Ngulik Data logoNgulik Data

Platform edukasi data lengkap untuk professionals Indonesia. Belajar SQL, Data Analysis, dan lebih banyak lagi dengan praktek langsung dan feedback real-time.

© 2026 Ngulik Data. Semua hak dilindungi.

TAUTAN
BantuanHargaDatasetBlogAfiliasi
LEGAL
Syarat & KetentuanKebijakan Privasi
Ngulik Data
DatasetLeaderboardBlogStore