Bagian ini menjelaskan bagaimana data dikumpulkan dan diolah. Bisnis di depan, teknis di sini.
🗺️ Gambaran Besar: Dari Mana Data Ini Berasal?
Portfolio ini tidak menggunakan dataset yang sudah jadi. Semua data dikumpulkan sendiri dari sumber publik, lalu diolah menjadi satu dataset terpadu.
🗺️
Google Maps
552 outlet + lokasi
→
🍕
GrabFood
60+ menu + harga
→
📈
IDX (Bursa)
Revenue quarterly
→
🧩
Master Dataset
Unified + generated
📦 Sumber Data: Dari Mana & Kenapa?
Setiap sumber data dipilih karena alasan spesifik. Tidak ada data yang diambil "karena bisa" — semuanya menjawab kebutuhan analisis.
🗺️
Google Maps — Lokasi Outlet
Kenapa? Pizza Hut tidak mempublikasikan daftar outlet lengkap. Google Maps adalah satu-satunya sumber publik yang punya nama, alamat, koordinat, rating, dan foto untuk setiap outlet.
552 outlet~65 menit scraping
🍕
GrabFood — Menu & Harga
Kenapa? Website resmi pizzahut.co.id adalah SPA dengan API yang di-protect — tidak bisa di-scrape. GrabFood web version menampilkan menu lengkap dengan harga real.
60+ itemsHarga real-time
📈
IDX (Bursa Efek) — Keuangan
Kenapa? Pizza Hut Indonesia (PZZA) adalah perusahaan publik. Laporan keuangan mereka bisa diakses siapa saja — ini anchor untuk memastikan angka revenue realistis.
Quarterly revenueTTM derivation
🧮
Generated — Performance Data
Kenapa? Data revenue per outlet tidak publik. Jadi di-generate secara realistis — anchored ke total revenue PZZA dari IDX, lalu didistribusikan ke 552 outlet berdasarkan tipe, lokasi, dan rating.
Revenue, cost, transactions~5 detik
🔄 Pipeline: 4 Langkah dari Nol ke Dataset
Setiap script punya satu tugas. Jalankan berurutan = full pipeline dari scraping sampai data siap analisis.
1
Scrape Lokasi Outlet 01_scrape_locations.py
🎯 Tujuan: Dapatkan daftar semua outlet Pizza Hut di Indonesia
Melakukan 99 search query di Google Maps ("Pizza Hut [kota]" + "PHD [kota]" untuk 50 kota). Scroll feed sampai habis, extract nama + URL + koordinat. Deduplicate berdasarkan URL.
🎯 Tujuan: Lengkapi profil setiap outlet (alamat, rating, foto)
Buka halaman Google Maps setiap outlet satu per satu. Extract alamat lengkap, rating, kategori (Restoran/PHD), jam operasional, nomor telepon, dan foto.
📦 Alamat, rating, foto⏱️ ~30 menit🔧 CSS selectors
3
Build Master Dataset 03_build_outlet_master.py
🎯 Tujuan: Gabungkan semua data + hitung jarak antar outlet
Merge data lokasi + detail. Hitung jarak Haversine antar semua pasangan outlet. Tandai outlet yang punya ≥3 neighbors dalam 2km (cannibalization risk). Assign region dan tipe.
📦 Unified master + proximity⏱️ ~2 menit🔧 Haversine formula
4
Generate Performance Data 04_generate_performance_data.py
🎯 Tujuan: Buat data revenue & cost per outlet yang realistis
Revenue per outlet tidak publik, jadi di-generate. Total revenue di-anchor ke laporan keuangan PZZA (IDX), lalu didistribusikan ke 552 outlet berdasarkan tipe (Dine-in vs PHD), lokasi, rating, dan jumlah neighbors. Cost structure mengikuti benchmark industri QSR.
📦 Revenue, cost, transactions⏱️ ~5 detik🔧 Anchored ke IDX
🔍 Detail: Scraping Google Maps
Scraping dilakukan dalam 2 tahap. Tahap 1 mengumpulkan daftar outlet, tahap 2 mengambil detail per outlet.
99
Search Queries
"Pizza Hut [kota]" + "PHD [kota]" untuk 50 kota besar
552
Outlet Unik
Setelah deduplicate berdasarkan URL Google Maps
65
Menit Total
Scrape lokasi (~35m) + detail (~30m)
4
Data Fields
Alamat, rating, foto, koordinat
Kelengkapan Data (Completeness Rate)
Tidak semua field berhasil di-extract. Berikut tingkat kelengkapan per field:
Alamat — button[data-item-id="address"]100%
Rating — div.F7nice span99.6%
Foto — img[src*="googleusercontent"]99.1%
Review count — tidak di-render Google Maps0%
⚠️ Kenapa review count 0%?
Google Maps tidak me-render jumlah review untuk listing bisnis franchise besar seperti Pizza Hut. Elemen HTML-nya ada, tapi isinya kosong. Ini bukan bug scraping — memang tidak tersedia.
📐 Haversine: Menghitung Jarak Antar Outlet
Kenapa perlu hitung jarak?
Kalau 2 outlet Pizza Hut terlalu dekat (< 2km), mereka saling "makan" pelanggan satu sama lain — ini disebut cannibalization. Outlet yang punya ≥3 neighbors dalam 2km berisiko tinggi.
Kenapa Haversine, bukan jarak biasa?
Bumi itu bulat. Jarak lurus (Euclidean) antara dua koordinat GPS tidak akurat. Haversine menghitung jarak di permukaan bola — hasilnya dalam kilometer, akurat untuk jarak pendek.
Threshold: 2km
Radius delivery standar PHD (Pizza Hut Delivery). Kalau ada outlet lain dalam radius ini, mereka bersaing untuk pelanggan yang sama.
a = sin²(Δlat/2) + cos(lat₁)·cos(lat₂)·sin²(Δlon/2)
d = 2R · arcsin(√a)
R = 6,371 km (radius Bumi) · Threshold: 2km (radius delivery PHD)
import math
def haversine_km(lat1, lon1, lat2, lon2):
"""Hitung jarak (km) antara 2 koordinat GPS di permukaan Bumi."""
R = 6371 # radius Bumi dalam km
dlat = math.radians(lat2 - lat1)
dlon = math.radians(lon2 - lon1)
a = (math.sin(dlat/2)**2 +
math.cos(math.radians(lat1)) *
math.cos(math.radians(lat2)) *
math.sin(dlon/2)**2)
return R * 2 * math.asin(math.sqrt(a))
# Contoh: 2 outlet di Jakarta
# haversine_km(-6.175, 106.827, -6.200, 106.845)
# → ~3.2 km → TIDAK cannibalize (> 2km)
💰 Keuangan: Derivasi dari IDX
Kenapa perlu derivasi?
PZZA melaporkan revenue dalam format TTM (Trailing Twelve Months) — bukan per kuartal. Untuk mendapatkan revenue kuartal tunggal, perlu dihitung mundur:
single_Q(t) = single_Q(t-4) + [TTM(t) − TTM(t-1)]
Ambil Q yang sama tahun lalu, lalu tambahkan selisih TTM terbaru
💡 Ini penting karena revenue total dari IDX menjadi "anchor" — memastikan data generated per outlet tidak ngawur. Total revenue 552 outlet harus match dengan laporan keuangan PZZA.
🛠️ Tools & Stack
Setiap tool dipilih karena alasan spesifik — bukan karena populer.
🐍
Python 3.13 + scrapling
Scraping Google Maps. Scrapling = wrapper di atas Playwright (headless browser). Dipilih karena Google Maps butuh JavaScript rendering.
📊
Chart.js
Visualisasi chart (bar, line, scatter, doughnut). Ringan, responsive, dan bisa di-embed langsung di HTML tanpa backend.
🗺️
Leaflet.js
Peta interaktif untuk visualisasi lokasi 552 outlet. Open-source, ringan, dan support circle markers + radius overlay.
🌐
HTML / CSS / JS
Seluruh portfolio ini adalah static HTML — tidak ada backend, tidak ada database. Bisa dibuka langsung di browser manapun.
♻️ Reproducible
Semua code di folder scripts/. Run 4 scripts berurutan = full pipeline dari scraping sampai data generation.
✅ Kenapa ini penting untuk portfolio?
Halaman ini menunjukkan bahwa data tidak "jatuh dari langit". Ada proses engineering yang jelas — collect, validate, transform, generate. Ini yang membedakan Senior DA dari Junior: bukan cuma bisa analisis, tapi juga bisa build pipeline-nya.