Scrapping data pemilu 2024 membuat custom Web Apps dan deploy ke vercel
Category: Tutorial | 174 views
February 15, 2024
Halo! Pada kesempatan kali ini, saya akan membagikan tutorial mengenai cara melakukan scraping data dari website KPU untuk mengambil data quick count dan menampilkan data tersebut kembali menggunakan Requests dan Flask . Sebelum masuk ke dalam pembahasan, mari kita simak terlebih dahulu apa itu Python3.
Apa itu Python3 ?
Python3 adalah bahasa pemrograman tingkat tinggi yang bersifat interpretatif, dinamis, dan memiliki banyak kegunaan. Bahasa ini populer karena mudah dipelajari, digunakan, dan memiliki banyak pustaka (library) yang mendukung berbagai macam tugas pemrograman. Python3 banyak digunakan untuk berbagai macam keperluan, seperti:
- Analisis data
- Pemrograman web
- Pemrograman ilmiah
- Pembelajaran mesin
- Otomasi
- Dan banyak lagi
Apa itu Scraping Data?
Scraping data adalah proses pengambilan data dari website secara otomatis. Data yang diambil dapat berupa teks, gambar, video, atau format lainnya. Scraping data dapat dilakukan dengan berbagai cara, salah satunya menggunakan bahasa pemrograman Python3.
Selanjutnya apa saja library yang perlu disiapkan?
Sebelum menentukan library biasanya saya melakukan survey dulu terhadap web yang akan di scrapping datanya dengan cara membuka halaman web tersebut, berikut adalah hasil analisa saya mengenai web KPU
Install library Requests
pip install requests
Install library Flask
pip install Flask
okayy setelah semua library yang dibutuhkan berhasil diinstall waktunya membuat Helper atau fungsi bantuan yang nanti akan dipanggil di main program, disini saya membuatnya di dalam folder lib dengan nama requestHelper.py
import requests
class requestHelper:
BASE_URL = "https://sirekap-obj-data.kpu.go.id/"
def __init__(self):
self.request = requests.Session()
self.request.headers.update({
"Accept": "application/json",
"Content-Type": "application/json"
})
self.response = None
Penjelasan kode diatas adalah :
- Melakukan import library requests
- Menginisialisasi BASE URL API yang akan digunakan untuk requests
- Membuat init constructor yang berisi request session
Data Daerah
Data Tabel
def get_wilayah(self):
self.response = self.request.get(self.BASE_URL + "wilayah/pemilu/ppwp/0.json")
return self.response.json()
def get_paslon(self):
self.response = self.request.get(self.BASE_URL + "pemilu/ppwp.json")
return self.response.json()
def get_table(self):
self.response = self.request.get(self.BASE_URL + "pemilu/hhcw/ppwp.json")
return self.response.json()
def get_count(self):
serialized_data_wilayah = []
serialized_data_paslon = []
final_data = []
data_paslon = self.get_paslon()
for paslon in data_paslon:
serialized_data_paslon.append({
"id_paslon": paslon,
"nama": data_paslon[paslon]["nama"],
"nomor_urut": data_paslon[paslon]["nomor_urut"],
})
data_wilayah = self.get_wilayah()
for wilayah in data_wilayah:
serialized_data_wilayah.append({
"id": wilayah["id"],
"nama": wilayah["nama"],
"kode": wilayah["kode"],
})
data_table = self.get_table()
for wilayah in range(len(serialized_data_wilayah)):
wilayah_data = data_table.get("table")[serialized_data_wilayah[wilayah].get("kode")]
modified_data = {}
for key, value in wilayah_data.items():
if key in [str(paslon['id_paslon']) for paslon in serialized_data_paslon]:
nomor_urut = next(paslon['nomor_urut'] for paslon in serialized_data_paslon if paslon['id_paslon'] == key)
modified_data[nomor_urut] = value
else:
modified_data[key] = value
final_data.append({
"data_wilayah": serialized_data_wilayah[wilayah],
"data_paslon": modified_data
})
return {
'data': final_data,
'data_paslon': serialized_data_paslon,
'chart': data_table.get('chart'),
'last_updated': data_table.get('ts'),
'progres': data_table.get('progres'),
}
Penjelasan kode diatas adalah :
- Membuat 3 method untuk mengambil data Dearah, Paslon & Table
- Method GetCount digunakan untuk menampung semua data final yang akan ditampilkan ke halaman web
nah untuk versi lengkapnya dapat dilihat di github link berikut ini : requestHelper.py
saatnya melakukan test pada method yang telah dibuat sebelumnya. membuat file main.py
from lib.requestHelper import requestHelper
import json
request = requestHelper()
data = request.get_count()
print(
json.dumps(data, indent=4)
)
Penjelasan kode diatas adalah :
- Melakukan import Class requestHelper
- Menginstansiasi Class requestHelper
- Memanggil dan menampilkan method get_count dari class requestHelper
Hasilnya jika berhasil akan tampil seperti berikut ini :
from flask import Flask, request, jsonify, render_template
from flask_humanize import Humanize
from lib.requestHelper import requestHelper
app = Flask(__name__, template_folder="templates")
humanize = Humanize(app)
@humanize.localeselector
def get_locale():
return 'id_ID'
@app.route("/")
def index():
request_helper = requestHelper()
data = request_helper.get_count()
return render_template(
"index.html",
data_paslon=data["data_paslon"],
data_chart=data["chart"],
data_table=data["data"],
data_last_updated=data["last_updated"],
data_progres=data["progres"],
)
Penjelasan kode diatas adalah :
- Melakukan import Class
requestHelper
dari modulrequestHelper
yang berada dalam direktorilib
. Kemudian, sebuah aplikasi Flask dibuat dengan namaapp
, dengan menentukan folder template-nya sebagai"templates"
. Dilanjutkan dengan penggunaan ekstensi Flask-Humanize untuk membantu dalam pemformatan data. - Fungsi
get_locale()
digunakan sebagai penentu lokal yang akan digunakan, dalam kasus ini, lokal yang diatur adalahid_ID
untuk Bahasa Indonesia. - Rute utama
/
diatur untuk menangani permintaan ke root URL. Saat rute ini diakses, objekrequestHelper
dibuat untuk membantu dalam memproses permintaan. Data yang diperoleh kemudian diteruskan ke templateindex.html
menggunakan fungsirender_template
. Data tersebut meliputi informasi tentang jumlah paslon, data grafik, data tabel, waktu terakhir diperbarui, dan kemajuan data.
nah setelah membuat app.py jangan lupa untuk membuat folder templates dan berisi file index.html berikut ini adalah contoh dari file html nya
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta content="width=device-width, initial-scale=1.0" name="viewport">
<title>Hasil Hitung Suara Pemilu Presiden & Wakil Presiden RI 2024</title>
<!-- Bootstrap CSS -->
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
<script src="https://code.jquery.com/jquery-3.7.0.min.js"></script>
<style>
#hasil-perolehan-suara {
font-size: 20px;
font-weight: bold;
text-align: center;
margin-top: 20px;
}
.card-style {
font-size: 20px;
font-weight: bold;
}
</style>
</head>
<body>
<div class="container" style="margin-top: 120px; margin-bottom: 120px;">
<div class="row justify-content-center">
<div class="col-md-10">
<h1 class="text-center">HASIL HITUNG SUARA PEMILU PRESIDEN & WAKIL PRESIDEN RI 2024</h1>
<p class="text-center">Updated at : {{ data_last_updated }}</p>
<p class="text-center"><span class="badge bg-info">Progress : {{ data_progres.total }} dari {{ data_progres.progres }} TPS</span></p>
</div>
<div id="chart-container" style="width: 120%; height: 600px;"></div>
{% for paslon in data_paslon %}
<div class="col-md-4">
<div class="card mb-3">
<div class="card-header text-center card-style">
{{ paslon.nama.split('-')[0] }}<br>
{{ paslon.nama.split('-')[1] }}.
</div>
<div class="card-body">
{% for key, value in data_chart.items() %}
{% if key == paslon.id_paslon: %}
<div class="row">
<div class="col-md-12" id="hasil-perolehan-suara">
{{ value|humanize('intcomma') }} Suara
</div>
</div>
{% endif %}
{% endfor %}
</div>
</div>
</div>
{% endfor %}
</div>
<div class="container" style="margin-top: 10px; margin-bottom: 120px;">
<div class="row justify-content-center">
<!-- Your other content here -->
<div class="col-md-13">
<!-- DataTables container -->
<div class="table-responsive">
<table class="table table-bordered table-hover" id="table-data">
<thead>
<tr class="table-primary text-center">
<th>#</th>
<th>Wilayah</th>
<th>Progress</th>
{% for paslon in data_paslon %}
<th>{{ paslon.nama.split('-')[0] }}<br>{{ paslon.nama.split('-')[1] }}</th>
{% endfor %}
</tr>
</thead>
<tbody class="text-center" style="font-size: 20px;">
{% for data in data_table %}
<tr>
<td>{{ loop.index }}</td>
<td>{{ data.data_wilayah.nama }}</td>
<td>{{ data.data_paslon.persen|humanize('intcomma') }}%</td>
<td>{{ data.data_paslon.1|safe|humanize('intcomma') }}</td>
<td>{{ data.data_paslon.2|safe|humanize('intcomma') }}</td>
<td>{{ data.data_paslon.3|safe|humanize('intcomma') }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
<div class="container text-center" style="font-size: 20px; font-weight: bold; background-color: #f8d7da; padding: 20px; width: 100%;">
<div class="row justify-content-center">
<div class="col-md-10">
<p class="text-center">Data diambil dari API KPU : https://pemilu2024.kpu.go.id/ </p>
<p class="text-center">Tampilan web ini dibuat oleh : <a href="https://sandroputra.com" target="_blank">Sandro Putra</a></p>
</div>
</div>
</div>
<!-- Bootstrap JS -->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/apexcharts"></script>
<script>
// Initialize DataTables
$(document).ready(function() {
// Extracting data from HTML
var paslon1Data = [];
var paslon2Data = [];
var paslon3Data = [];
var wilayah = [];
{% for data in data_table %}
paslon1Data.push({{ data.data_paslon.1 }});
paslon2Data.push({{ data.data_paslon.2 }});
paslon3Data.push({{ data.data_paslon.3 }});
wilayah.push("{{ data.data_wilayah.nama }}");
{% endfor %}
// Create chart
var options = {
chart: {
type: 'line',
height: 600,
width: '100%',
toolbar: {
show: true,
},
zoom: {
enabled: true
},
},
colors: ['#388E3C', '#0288D1', '#D32F2F'], // Change colors here
series: [{
name: 'Paslon 1',
data: paslon1Data
}, {
name: 'Paslon 2',
data: paslon2Data
}, {
name: 'Paslon 3',
data: paslon3Data
}],
xaxis: {
categories: wilayah
},
yaxis: {
title: {
text: 'Suara'
}
},
tooltip: {
y: {
formatter: function (val) {
return val.toLocaleString() + " Suara"
}
}
}
};
var chart = new ApexCharts(document.querySelector("#chart-container"), options);
chart.render();
});
</script>
</body>
</html>
dari html diatas kita melakukan parsing data dari backend ke html dengan cara
<p class="text-center">Updated at : {{ data_last_updated }}</p>
kemudian membuat chart untuk menampilkan presentase dengan apexchart.
nah ketika html dan backend py telah berhasil dibuat saatnya melakukan test dengan membuat file server.py. dimana server.py ini akan bekerja seperti webserver untuk menjalankan kode yang telah dibuat sebelumnya berikut ini adalah kodenya
from app import app
if __name__ == "__main__":
app.run(host="0.0.0.0", port=5020, debug=True)
nah ketika dijalankan server.py di terminal memiliki tampilan seperti berikut ini maka program telah berhasil dibuat
Selanjutnya adalah membuat konfigurasi vercel.json yang digunakan untuk publish ke web vercel dengan bantuan github, berikut ini adalah konfigurasinya :
{
"version": 2,
"builds": [
{
"src": "./server.py",
"use": "@vercel/python"
}
],
"routes": [
{
"src": "/(.*)",
"dest": "server.py"
}
]
}
setelah semuanya berhasil dibuat langkah terakhir sebelum push repository adalah melaukan freeze requirements yang dibutuhkan dengan command berikut ini
pip freeze > requirements.txt
command diatas akan melakukan extract semua library yang dibutuhkan kedalam file requirements.txt, baik selanjutnya adalah tinggal melakukan push ke github anda masing masing dan buka vercel untuk melakukan deploy di vercel. berikut ini adalah tampilan ketika web sudah di vercel
okayy sekian tutorial Scrapping data pemilu 2024 dan membuat custom Web Apps deploy vercel semoga bermanfaat ✨?