Web Scraping Data Kost di Malang dari Mamikos dengan Selenium
Web scraping memungkinkan kita mengambil data dari halaman web secara otomatis. Salah satu studi kasus menarik adalah mengambil data kost dari situs populer seperti Mamikos. Dalam tutorial ini, kita akan menggunakan Selenium untuk melakukan scraping data kost di Kota Malang karena kontennya bersifat lazy-load dan dinamis, sehingga tidak bisa langsung diambil hanya dengan requests atau BeautifulSoup saja.
Tentang Mamikos
Mamikos adalah platform pencarian kost online terbesar di Indonesia yang memudahkan pencari kost menemukan hunian sesuai kebutuhan mereka. Mamikos menyediakan informasi lengkap mengenai:
- Tipe kost (Putra, Putri, Campur)
- Harga sewa per bulan/tahun
- Lokasi dan jarak ke kampus/tempat kerja
- Fasilitas seperti Wi-Fi, kamar mandi dalam, AC, dapur, dan lain-lain
- Rating, ulasan, dan foto kamar
Situs ini menggunakan infinite scroll dan tombol ‘Lihat lebih banyak lagi’ untuk menampilkan lebih banyak hasil, yang artinya kontennya dimuat secara dinamis menggunakan JavaScript. Oleh karena itu, scraping data dari Mamikos membutuhkan pendekatan berbasis browser seperti Selenium.
Tujuan
- Mengambil data kost bulanan di Kota Malang dari situs Mamikos.
- Menangani pemuatan konten dinamis (lazy load dan pagination).
- Menyimpan hasil dalam format CSV.
Tools dan Teknologi
| Library / Tool | Fungsi |
|---|---|
Selenium | Kontrol browser untuk scraping halaman dinamis |
BeautifulSoup | Memparsing HTML dan mengambil elemen data |
Pandas | Menyimpan data ke dalam bentuk tabel (CSV) |
time | Memberi delay agar konten dimuat dengan benar |
Kode Lengkap Web Scraping Mamikos
1. Import Library
Pertama-tama kita harus impor dulu semua library yang dibutuhkan. Selenium itu buat ngontrol browser (kayak ngeklik tombol atau scroll halaman), BeautifulSoup dipakai buat baca HTML dari halaman web, pandas buat nyimpen datanya ke CSV, dan time dipakai untuk kasih jeda agar elemen web sempat dimuat.
1
2
3
4
5
6
7
8
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from bs4 import BeautifulSoup
import pandas as pd
import time
2. Setup Driver
Fungsi ini kita pakai buat bikin browser otomatis yang udah dikonfigurasi. Di sini kita tambahkan beberapa opsi biar situs gak langsung curiga kalau kita bot. Misalnya, user-agent kita ubah supaya terlihat kayak pengguna Chrome biasa.
1
2
3
4
5
6
7
def setup_driver():
options = webdriver.ChromeOptions()
options.add_argument("--disable-gpu")
options.add_argument("--no-sandbox")
options.add_argument("--disable-blink-features=AutomationControlled")
options.add_argument("user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36")
return webdriver.Chrome(options=options)
3. Fungsi Klik Tombol “Lihat Lebih Banyak Lagi”
Langkah selanjutnya, program bakal menjalankan fungsi expand_all_listings() untuk nge-klik tombol “Lihat lebih banyak lagi” beberapa kali. Tujuannya jelas: supaya hasil kost yang muncul makin banyak.
1
2
3
4
5
6
7
8
9
10
11
def expand_all_listings(driver, max_clicks=5):
for _ in range(max_clicks):
try:
load_button = WebDriverWait(driver, 5).until(
EC.element_to_be_clickable((By.CLASS_NAME, "nominatim-list__see-more"))
)
ActionChains(driver).move_to_element(load_button).click().perform()
time.sleep(2)
except:
print("Tidak ada tombol 'Lihat lebih banyak lagi', lanjut ke scroll...")
break
4. Fungsi Scroll Otomatis
Setelah itu, program lanjut scroll ke bawah beberapa kali buat memicu teknik lazy load-nya — ini penting karena data kost baru dimuat saat halaman di-scroll.
1
2
3
4
5
6
7
8
9
def scroll_page(driver, times=5, pause=2):
last_height = driver.execute_script("return document.body.scrollHeight")
for _ in range(times):
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
time.sleep(pause)
new_height = driver.execute_script("return document.body.scrollHeight")
if new_height == last_height:
break
last_height = new_height
5. Fungsi Pengaman Ambil Teks
Menghindari error saat elemen HTML tidak ditemukan, fungsi ini mengembalikan teks atau default.
1
2
def get_text_or_default(tag, default="Tidak ada"):
return tag.text.strip() if tag else default
6. Ekstrak Data Kost dari HTML
Fungsi ini mem-parsing elemen-elemen data dari setiap kost card: gambar, nama, tipe, lokasi, fasilitas, harga, dan rating.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
def extract_data_from_page(html):
soup = BeautifulSoup(html, "html.parser")
kost_cards = soup.select('div[data-testid="kostRoomCard"]')
print(f"\U0001F4E6 Total kost ditemukan: {len(kost_cards)}")
hasil = []
for card in kost_cards:
img = card.select_one('img[data-testid="roomCardCover-photo"]')
image_url = img.get("src") or img.get("data-src") if img else "Tidak ada gambar"
name = get_text_or_default(card.select_one(".rc-info__name"))
tipe = get_text_or_default(card.select_one(".rc-overview__label"), "Tidak diketahui")
lokasi = get_text_or_default(card.select_one(".rc-info__location"))
rating = get_text_or_default(card.select_one(".rc-overview__rating-text"), "Tidak ada rating")
fasilitas_tags = card.select('span[data-testid="roomCardFacilities-facility"]')
fasilitas = ", ".join(tag.get_text(strip=True) for tag in fasilitas_tags) if fasilitas_tags else "Tidak ada"
harga_diskon = get_text_or_default(card.select_one(".rc-price__text"), "Tidak ada harga")
harga_awal = get_text_or_default(card.select_one(".rc-price__additional-discount-price"), "Tidak ada")
hasil.append([name, tipe, lokasi, fasilitas, rating, harga_awal, harga_diskon, image_url])
return hasil
7. Bagian Utama Program (Main Execution)
Setelah dipastikan semua elemen data kost udah muncul, program akan ngecek keberadaan elemen HTML bernama kostRoomCard (yaitu setiap kotak kost di halaman). Kalau elemen ini berhasil ditemukan, program lanjut ke proses ekstraksi data dengan memanggil extract_data_from_page() yang akan parsing data satu per satu. Data yang dikumpulkan kemudian diubah jadi DataFrame dengan pandas, lalu disimpan sebagai file CSV bernama kost_malang_mamikos.csv. Terakhir, browser ditutup dan jumlah data yang berhasil diambil akan ditampilkan.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
if __name__ == "__main__":
url = "https://mamikos.com/cari/malang-kota-malang-jawa-timur-indonesia/all/bulanan/0-15000000"
browser = setup_driver()
browser.get(url)
time.sleep(3)
expand_all_listings(browser)
scroll_page(browser, times=6)
try:
WebDriverWait(browser, 10).until(
EC.presence_of_element_located((By.CSS_SELECTOR, 'div[data-testid="kostRoomCard"]'))
)
except:
print("Elemen data kost tidak ditemukan!")
kost_data = extract_data_from_page(browser.page_source)
browser.quit()
df = pd.DataFrame(kost_data, columns=[
"Nama Kost", "Tipe Kost", "Lokasi", "Fasilitas",
"Rating", "Harga Sebelum Diskon", "Harga Setelah Diskon", "Gambar"
])
df.to_csv("kost_malang_mamikos.csv", index=False, encoding="utf-8-sig")
print("Data berhasil disimpan ke kost_malang_mamikos.csv")
print(df.shape)
Hasil
| Output File | Deskripsi |
|---|---|
kost_malang_mamikos.csv | Data kost dari Mamikos kota Malang |
Kendala & Solusi
| Masalah | Solusi |
|---|---|
| Lazy loading menyebabkan data tidak lengkap | Gunakan scroll otomatis |
| Elemen tidak muncul saat parsing | Tambahkan delay dengan WebDriverWait |
| Situs mendeteksi bot | Gunakan user-agent dan disable-blink-features |
Rencana Lanjutan
- Menambahkan filter berdasarkan harga maksimal/minimal.
- Menyimpan ke database SQL.
- Menambahkan deteksi otomatis jumlah halaman.
