Web Scraping dengan Requests dan BeautifulSoup: Proyek Harga Marketplace
Blog/Tips & Trik/Web Scraping dengan Requests dan BeautifulSoup: Proyek Harga Marketplace

Web Scraping dengan Requests dan BeautifulSoup: Proyek Harga Marketplace

BimaBima
·25 September 2025·11 menit baca

Penulis

Bima

Bima

Founder & Data Professional

Bagikan

TL;DR

Web scraping adalah cara ngambil data dari halaman web dengan program, dan di Python kombinasi paling umum itu Requests buat ngunduh halamannya plus BeautifulSoup buat nyari elemen yang kamu mau. Alurnya empat langkah: cek robots.txt, unduh HTML, pilih elemen pakai CSS selector, lalu simpan ke DataFrame. Kasih jeda antar request dan pasang User-Agent yang jelas supaya server nggak keberatan.

Web scraping adalah cara ngambil data dari halaman web pakai program. Di Python, Requests yang ngunduh halamannya, BeautifulSoup yang nyari elemen yang kamu butuhin.

Kasus paling sering buat analis di Indonesia: ngumpulin harga produk sejenis dari marketplace, lalu bandingin sama harga sendiri. Kerjaan yang kalau manual makan dua jam seminggu, dan biasanya berhenti setelah minggu ketiga.

Di bawah ini alur lengkapnya, dari cek izin sampai file CSV yang siap dianalisis.

Apa itu web scraping dan kapan boleh dipakai?

Web scraping adalah proses ngambil data dari tampilan halaman web secara otomatis, lalu ngubahnya jadi tabel. Ini pilihan kedua setelah API. Kalau situsnya punya API resmi, pakai API karena datanya lebih stabil dan izinnya jelas. Scraping baru masuk waktu datanya cuma ada di halaman web biasa.

Sebelum nulis satu baris kode pun, buka dua hal: file robots.txt situsnya dan halaman syarat layanan. Robots.txt ngasih tau bagian mana yang boleh diambil program.

from urllib.robotparser import RobotFileParser

rp = RobotFileParser()
rp.set_url("https://books.toscrape.com/robots.txt")
rp.read()

print(rp.can_fetch("NgulikDataBot", "https://books.toscrape.com/catalogue/page-1.html"))
# True

Buat latihan di artikel ini aku pakai books.toscrape.com, situs yang emang dibikin khusus buat belajar scraping. Batas hukum dan etikanya aku bahas terpisah di artikel etika dan legalitas scraping di Indonesia.

Apa yang perlu diinstall?

pip install requests beautifulsoup4 pandas lxml

Empat paket, tugasnya beda-beda. Requests ngunduh halaman. BeautifulSoup4 baca HTML-nya. pandas nyimpen hasilnya jadi tabel. lxml itu parser tambahan yang lebih cepat, sifatnya opsional.

Dokumentasi resmi BeautifulSoup ada di crummy.com, dan itu rujukan paling lengkap buat semua metode pencarian elemennya.

Gimana cara ambil satu halaman dan baca isinya?

Alurnya tiga langkah: unduh halaman pakai requests.get, masukin teksnya ke BeautifulSoup, lalu pilih elemen pakai CSS selector. Selalu pasang User-Agent yang nyebut nama dan kontak kamu supaya pemilik situs tau siapa yang lagi ngambil data.

import requests
from bs4 import BeautifulSoup

HEADERS = {
    "User-Agent": "NgulikDataBot/1.0 (+https://ngulikdata.com)"
}

url = "https://books.toscrape.com/catalogue/page-1.html"
r = requests.get(url, headers=HEADERS, timeout=15)
r.raise_for_status()
r.encoding = r.apparent_encoding

soup = BeautifulSoup(r.text, "html.parser")
print(soup.title.get_text(strip=True))

Baris r.encoding = r.apparent_encoding itu penyelamat buat situs Indonesia. Tanpa itu, nama produk yang ada huruf beraksen sering berubah jadi karakter aneh.

Gimana cara nemuin selector yang bener?

Buka halamannya di browser, klik kanan di elemen yang kamu mau, pilih Inspect. Lihat nama tag dan class-nya, lalu tulis CSS selector yang paling pendek tapi masih spesifik. Selector pendek lebih tahan waktu desain situsnya diubah sedikit.

Di books.toscrape.com, tiap produk dibungkus article dengan class product_pod:

for card in soup.select("article.product_pod")[:3]:
    judul = card.h3.a["title"]
    harga = card.select_one("p.price_color").get_text(strip=True)
    stok  = card.select_one("p.instock.availability").get_text(strip=True)
    print(judul, "|", harga, "|", stok)
A Light in the Attic | £51.77 | In stock
Tipping the Velvet | £53.74 | In stock
Soumission | £50.10 | In stock

Dua metode yang bakal kamu pakai terus:

  • select() balikin semua elemen yang cocok sebagai list.
  • select_one() balikin satu elemen pertama, atau None kalau nggak ketemu.

Pakai select_one() lalu cek None-nya, jangan langsung .get_text(). Satu produk yang kebetulan nggak punya harga bisa bikin seluruh loop berhenti.

Gimana cara ambil banyak halaman dengan aman?

Bungkus proses satu halaman jadi fungsi, lalu panggil berulang sambil kasih jeda. Jeda satu sampai tiga detik itu batas wajar buat situs kecil, dan bikin script kamu nggak keblokir di tengah jalan.

import time
import pandas as pd

def scrape_halaman(nomor):
    url = f"https://books.toscrape.com/catalogue/page-{nomor}.html"
    r = requests.get(url, headers=HEADERS, timeout=15)

    if r.status_code == 404:
        return None

    r.raise_for_status()
    r.encoding = r.apparent_encoding
    soup = BeautifulSoup(r.text, "html.parser")

    hasil = []
    for card in soup.select("article.product_pod"):
        harga_el = card.select_one("p.price_color")
        hasil.append({
            "judul": card.h3.a["title"],
            "harga_teks": harga_el.get_text(strip=True) if harga_el else None,
            "rating": card.select_one("p.star-rating")["class"][1],
            "halaman": nomor,
        })
    return hasil

semua = []
for n in range(1, 51):
    batch = scrape_halaman(n)
    if batch is None:
        break
    semua.extend(batch)
    time.sleep(2)

df = pd.DataFrame(semua)
print(len(df), "produk")

Tiga pengaman di kode itu: batas 50 halaman, deteksi 404 buat berhenti otomatis, dan time.sleep(2) di tiap putaran.

Gimana cara ngubah harga teks jadi angka?

Harga di halaman web selalu berupa teks, lengkap sama simbol mata uang dan pemisah ribuan. Bersihin dulu sebelum dihitung, kalau nggak semua agregasi kamu bakal salah atau langsung error.

import re

def ke_angka(teks):
    if not teks:
        return None
    bersih = re.sub(r"[^0-9,.]", "", teks)
    bersih = bersih.replace(".", "").replace(",", ".")
    try:
        return float(bersih)
    except ValueError:
        return None

print(ke_angka("Rp1.250.000"))   # 1250000.0
print(ke_angka("Rp45.900"))      # 45900.0

Fungsi di atas dipasang buat format Indonesia, titik sebagai pemisah ribuan dan koma sebagai desimal. Kalau kamu scraping situs berbahasa Inggris, aturannya kebalik.

Habis itu, cek dulu sebelum dianalisis:

print(df["harga"].isna().sum(), "harga gagal diparsing")
print(df["harga"].describe())

Contoh kasus: toko_berkah bandingin harga sama pasar

Toko Berkah jual 34 SKU aksesoris HP. Harga jualnya diset sekali di awal tahun dan belum pernah dicek ulang sama harga pasar.

Aku ambil harga produk sejenis dari halaman katalog publik, 3 halaman per kata kunci, jeda 2 detik. Total 41 menit buat 118 halaman, sekali jalan.

pasar = pd.read_csv("harga_pasar.csv")

median_pasar = (
    pasar.groupby("kategori")["harga"]
    .median()
    .rename("median_pasar")
    .reset_index()
)

toko = pd.read_csv("harga_toko_berkah.csv")
banding = toko.merge(median_pasar, on="kategori", how="left")
banding["selisih_pct"] = (
    (banding["harga_jual"] - banding["median_pasar"]) / banding["median_pasar"] * 100
).round(1)

print(banding.sort_values("selisih_pct", ascending=False).head(8))

Hasil di dataset latihan ngulikdata: 9 dari 34 SKU dijual lebih dari 18 persen di atas median pasar. Yang paling jauh, kabel USB-C, dijual Rp42.000 sementara median pasarnya Rp29.500, selisih 42 persen.

Sisi lainnya juga muncul: 5 SKU dijual di bawah median pasar, dan salah satunya charger 20W yang laku 640 unit sebulan. Naikin Rp3.000 per unit di SKU itu doang nambah sekitar Rp1,9 juta sebulan tanpa ganti apa pun.

Median dipakai, bukan rata-rata, soalnya ada beberapa penjual yang masang harga aneh dan bikin rata-rata melenceng. Cara mikirin pencilan begini aku bahas di glossary outlier.

Kalau halamannya kosong waktu di-scrape

Banyak situs modern ngisi kontennya pakai JavaScript setelah HTML awal dimuat. Requests cuma ngambil HTML awal itu, jadi hasilnya kelihatan kosong.

Cara ngeceknya: klik kanan lalu View Page Source, bukan Inspect Element. View Page Source nampilin persis yang diterima Requests.

Kalau datanya nggak ada di situ, ada dua jalan:

  1. Buka tab Network di browser, refresh halamannya, cari request yang balikin JSON. Panggil endpoint itu langsung pakai requests, jauh lebih ringan daripada scraping HTML. Caranya sama kayak di panduan ambil data REST API.
  2. Kalau nggak ketemu juga, baru pakai browser otomatis kayak Playwright. Lebih berat dan lebih lambat, jadi jadikan pilihan terakhir.

Kesalahan umum waktu scraping

KesalahanAkibatnyaPerbaikannya
Nggak kasih jeda antar requestIP diblokir, data cuma separuhtime.sleep(2) di tiap putaran
Selector kepanjanganRusak begitu desain berubahPegang class semantik atau atribut data
Langsung .get_text() tanpa cek NoneLoop berhenti di tengahCek hasil select_one() dulu
Lupa set encodingHuruf berubah jadi simbol anehr.encoding = r.apparent_encoding
Simpan harga sebagai teksAgregasi salah atau errorBersihin jadi float sebelum disimpan
Nggak nyimpen tanggal ambilNggak bisa bandingin antar waktuTambahin kolom tanggal_ambil

Nomor enam sering kelewat, dan itu justru yang bikin proyek ini berguna jangka panjang. Simpan tiap hasil scraping dengan tanggalnya, tiga bulan kemudian kamu punya data tren harga yang nggak dipunya kompetitor. Pengecekan kualitas datanya jalanin tiap kali script selesai.

FAQ

Web scraping itu legal atau nggak?

Tergantung apa yang kamu ambil dan gimana caranya. Ngambil data harga publik dengan jeda wajar dan tanpa nembus login umumnya aman. Yang bikin masalah itu ngambil data pribadi, ngelanggar syarat layanan situs, atau ngirim request begitu banyak sampai servernya terganggu. Cek robots.txt dan halaman syarat layanan sebelum mulai.

Kenapa hasil scraping saya kosong padahal di browser ada datanya?

Kemungkinan besar halaman itu ngisi kontennya pakai JavaScript setelah HTML awal dimuat, sedangkan Requests cuma ngambil HTML awalnya. Cek dengan klik kanan lalu View Page Source, bukan Inspect Element. Kalau datanya nggak ada di situ, cari endpoint API yang dipanggil halamannya lewat tab Network.

Berapa jeda yang wajar antar request?

Satu sampai tiga detik buat situs kecil, dan turutin nilai Crawl-delay kalau robots.txt nyebutin. Jeda ini bukan sekadar sopan santun, tapi juga bikin script kamu nggak kena blokir di tengah jalan. Kalau kamu butuh ribuan halaman, jalankan malam hari dan pecah jadi beberapa sesi.

Pakai html.parser atau lxml?

html.parser udah bawaan Python jadi nggak perlu install apa-apa, dan cukup buat sebagian besar halaman. lxml lebih cepat dan lebih tahan sama HTML yang rusak, tapi harus diinstall terpisah. Buat proyek di bawah seribu halaman, bedanya nggak kerasa.

Gimana kalau struktur HTML situsnya berubah?

Script kamu bakal balikin kolom kosong atau langsung error. Makanya jangan pakai selector yang kepanjangan kayak div > div > div > span. Pilih pegangan yang stabil kayak nama class semantik atau atribut data. Tambahin juga pengecekan jumlah baris di akhir, supaya kamu langsung tau waktu hasilnya anjlok.

Jadikan proyek portofolio

Empat hal yang bikin script scraping kamu layak dipakai berulang: cek robots.txt di awal, jeda di tiap request, parsing harga yang tahan format Indonesia, dan kolom tanggal ambil di tiap baris.

Jalanin seminggu berturut-turut, kamu udah punya dataset tren harga yang orisinal.

Coba mulai dari satu kategori produk yang kamu ngerti. Kalau mau tau batas amannya sebelum jalan, baca dulu rambu UU PDP untuk scraping.

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