Pernah nggak sih kamu butuh data dari internet, tapi nggak ada API-nya? Atau datanya ada, tapi formatnya berantakan dan harus copy-paste ratusan halaman secara manual? Kalau pernah, selamat — kamu baru saja menemukan alasan kenapa web scraping itu game changer banget.
Saya pribadi pertama kali kenal web scraping sekitar tahun 2019. Waktu itu saya butuh data harga produk dari beberapa marketplace buat riset sederhana. Bayangin, ada ribuan produk yang harus saya catat. Manual? Bisa gila. Akhirnya saya coba Python, dan sejak saat itu saya nggak pernah balik lagi ke cara manual.
Artikel ini saya tulis berdasarkan pengalaman bertahun-tahun — termasuk jatuh bangun kena ban, bikin scraper yang crash di tengah jalan, sampai akhirnya menemukan workflow yang solid. Di panduan web scraping dengan Python ini, kamu akan belajar dari nol sampai bisa bikin scraper yang andal di tahun 2026.
Nggak perlu jago Python banget kok. Asal kamu kenal dasar-dasarnya — variabel, loop, function — kamu sudah bisa mulai. Oke, langsung gas aja ya.
Apa Itu Web Scraping dan Kenapa Kamu Perlu Tahu?
Secara sederhana, web scraping adalah teknik mengambil data dari halaman web secara otomatis. Alih-alih kamu buka browser, scroll, copy-paste satu per satu, scraper melakukannya untukmu — dalam hitungan detik.
Bayangin kamu lagi riset harga laptop di 5 e-commerce. Setiap situs punya ratusan produk. Kalau manual, bisa seharian. Dengan scraper? Mungkin 10 menit, tergantung seberapa banyak data dan seberapa cepat servernya.
Use Case Nyata di 2026
Sekarang di tahun 2026, web scraping makin relevan. Beberapa use case yang paling sering saya temui:
- Riset pasar: Ambil data harga, review, rating dari marketplace atau situs kompetitor.
- Machine learning: Kumpulkan dataset dari berbagai sumber untuk training model AI.
- Monitoring harga: Pantau fluktuasi harga tiket pesawat, hotel, atau properti secara real-time.
- Aggregasi konten: Kumpulkan berita, artikel, atau lowongan kerja dari berbagai portal.
- SEO analysis: Scrape data SERP untuk analisis keyword dan posisi ranking.
Yang perlu kamu catat: web scraping itu legal, tapi ada batasannya. Selama kamu menghormati robots.txt, nggak mengganggu server, dan nggak mengambil data pribadi yang dilindungi, kamu aman-aman saja. Jangan lupa juga baca Terms of Service situs yang mau kamu scrape. Etika tetap nomor satu, bro.
Persiapan: Tools dan Library yang Kamu Butuhkan
Sebelum mulai nulis kode, mari siapkan “dapur” dulu. Berikut ini setup yang saya rekomendasikan di tahun 2026.
Python Environment
Pastikan kamu sudah install Python 3.10 ke atas. Saya sarankan bikin virtual environment biar rapi:
python -m venv scraping-env
source scraping-env/bin/activate # Linux/Mac
scraping-env\Scripts\activate # Windows
Library Utama
Ada beberapa library yang wajib kamu kenal:
| Library | Fungsi |
|---|---|
| requests | Mengirim HTTP request ke server |
| BeautifulSoup4 | Parsing HTML dan mengekstrak data |
| lxml | Parser HTML/XML yang cepat |
| Scrapy | Framework scraping tingkat lanjut |
| Selenium | Automasi browser untuk situs dinamis |
| Playwright | Alternatif modern untuk Selenium |
| pandas | Mengolah dan menyimpan data |
Install semuanya sekaligus:
pip install requests beautifulsoup4 lxml scrapy selenium playwright pandas
Kalau mau pakai Playwright, jangan lupa install juga browser-nya:
playwright install
Saya di sini akan pakai requests + BeautifulSoup sebagai starting point karena paling ramah pemula. Nanti kita juga akan bahas Scrapy dan Selenium/Playwright untuk kasus yang lebih kompleks.
Web Scraping Pertamamu: BeautifulSoup + Requests
Oke, ini bagian paling seru — langsung praktik. Kita akan scrape data sederhana dari sebuah halaman web.
Langkah 1: Kirim HTTP Request
Pertama-tama, kita perlu “minta” halaman web dari server:
import requests
url = "https://quotes.toscrape.com"
response = requests.get(url)
print(response.status_code) # 200 artinya sukses
print(response.text[:500]) # Lihat 500 karakter pertama HTML-nya
Situs quotes.toscrape.com sengaja dibuat untuk latihan scraping, jadi kamu nggak perlu khawatir soal legalitas. Cocok banget buat belajar.
Langkah 2: Parsing HTML
Sekarang kita ambil HTML-nya dan ubah jadi objek yang bisa kita “telusuri”:
from bs4 import BeautifulSoup
soup = BeautifulSoup(response.text, "lxml")
# Lihat judul halaman
print(soup.title.text)
# Output: Quotes to Scrape
Langkah 3: Ekstrak Data
Ini bagian intinya. Kita akan ambil semua quotes beserta penulisnya:
quotes = soup.find_all("div", class_="quote")
for quote in quotes:
text = quote.find("span", class_="text").get_text()
author = quote.find("small", class_="author").get_text()
tags = [tag.get_text() for tag in quote.find_all("a", class_="tag")]
print(f"Quote: {text}")
print(f"Author: {author}")
print(f"Tags: {', '.join(tags)}")
print("-" * 50)
Output-nya kurang lebih seperti ini:
Langkah 4: Simpan ke CSV
Data tanpa penyimpanan yang proper itu percuma. Simpan ke CSV pakai pandas:
import pandas as pd
data = []
for quote in quotes:
text = quote.find("span", class_="text").get_text()
author = quote.find("small", class_="author").get_text()
tags = [tag.get_text() for tag in quote.find_all("a", class_="tag")]
data.append({"quote": text, "author": author, "tags": ", ".join(tags)})
df = pd.DataFrame(data)
df.to_csv("quotes.csv", index=False, encoding="utf-8")
print(f"Berhasil menyimpan {len(data)} quotes!")
Mudah kan? Nah, tapi itu baru permukaan. Situs di dunia nyata jauh lebih rumit. Makanya kita perlu naik level.
Scraping Situs dengan Pagination dan Data Dinamis
Di dunia nyata, data jarang muat di satu halaman. Biasanya ada pagination — “Halaman 1, 2, 3 … Next”. Kita harus bisa handle itu.
Menangani Pagination
import requests
from bs4 import BeautifulSoup
import pandas as pd
import time
base_url = "https://quotes.toscrape.com/page/{}/"
all_quotes = []
for page in range(1, 11): # Scrape halaman 1-10
url = base_url.format(page)
response = requests.get(url)
soup = BeautifulSoup(response.text, "lxml")
quotes = soup.find_all("div", class_="quote")
if not quotes:
print(f"Halaman {page} kosong, berhenti.")
break
for quote in quotes:
text = quote.find("span", class_="text").get_text()
author = quote.find("small", class_="author").get_text()
all_quotes.append({"quote": text, "author": author})
print(f"Halaman {page} selesai: {len(quotes)} quotes")
time.sleep(1) # Jangan spam server!
df = pd.DataFrame(all_quotes)
df.to_csv("all_quotes.csv", index=False)
print(f"Total: {len(all_quotes)} quotes berhasil di-scrape!")
Perhatikan time.sleep(1) di situ. Ini penting banget. Kamu nggak mau server mengira kamu DDoS. Kasih jeda 1-3 detik antar request. Ini soal etika dan keamanan — kalau kamu di-ban IP-nya, scraper-mu mati.
Menangani Situs Dinamis (JavaScript-rendered)
Nah ini yang bikin banyak orang frustasi. Banyak situs modern di 2026 yang datanya di-load pakai JavaScript. Kalau kamu pakai requests biasa, yang kamu dapat cuma HTML kosong — datanya belum di-render.
Solusinya: Selenium atau Playwright.
Contoh pakai Playwright (saya lebih rekomendasikan ini di 2026 karena lebih modern dan cepat):
from playwright.sync_api import sync_playwright
import pandas as pd
data = []
with sync_playwright() as p:
browser = p.chromium.launch(headless=True)
page = browser.new_page()
page.goto("https://example-dynamic-site.com/products")
# Tunggu konten muncul
page.wait_for_selector(".product-card")
products = page.query_selector_all(".product-card")
for product in products:
name = product.query_selector(".product-name").inner_text()
price = product.query_selector(".product-price").inner_text()
data.append({"name": name, "price": price})
browser.close()
df = pd.DataFrame(data)
df.to_csv("products.csv", index=False)
print(f"Berhasil scrape {len(data)} produk!")
Playwright itu lebih stabil dibanding Selenium karena arsitekturnya berbeda. Dia juga support async, yang artinya kamu bisa scrape beberapa halaman sekaligus secara paralel. Di 2026, Playwright sudah jadi standar baru untuk browser automation.
Async Scraping dengan Playwright
Untuk dataset besar, scraping async bisa menghemat waktu secara drastis:
import asyncio
from playwright.async_api import async_playwright
import pandas as pd
async def scrape_page(browser, url):
page = await browser.new_page()
await page.goto(url)
await page.wait_for_selector(".product-card")
products = await page.query_selector_all(".product-card")
results = []
for product in products:
name = await (await product.query_selector(".product-name")).inner_text()
price = await (await product.query_selector(".product-price")).inner_text()
results.append({"name": name, "price": price})
await page.close()
return results
async def main():
urls = [f"https://example.com/page/{i}" for i in range(1, 21)]
all_data = []
async with async_playwright() as p:
browser = await p.chromium.launch(headless=True)
# Scrape 5 halaman sekaligus
for i in range(0, len(urls), 5):
batch = urls[i:i+5]
tasks = [scrape_page(browser, url) for url in batch]
results = await asyncio.gather(*tasks)
for result in results:
all_data.extend(result)
print(f"Batch {i//5 + 1} selesai")
await browser.close()
df = pd.DataFrame(all_data)
df.to_csv("products_async.csv", index=False)
print(f"Total: {len(all_data)} produk!")
asyncio.run(main())
Naik Level: Web Scraping dengan Scrapy
Kalau kamu serius mau scraping di skala besar — ribuan sampai jutaan halaman — pakai Scrapy. Ini adalah framework scraping paling powerful di Python.
Scrapy bukan sekadar library, dia adalah framework lengkap yang sudah include:
- Request management dan concurrency
- Pipeline untuk memproses dan menyimpan data
- Middleware untuk rotasi user-agent dan proxy
- Built-in retry mechanism
- Export ke berbagai format (JSON, CSV, XML)
Install dan Buat Project Scrapy
pip install scrapy
scrapy startproject my_scraper
cd my_scraper
scrapy genspider quotes quotes.toscrape.com
Tulis Spider
Buka file my_scraper/spiders/quotes.py:
import scrapy
class QuotesSpider(scrapy.Spider):
name = "quotes"
start_urls = ["https://quotes.toscrape.com/"]
def parse(self, response):
for quote in response.css("div.quote"):
yield {
"text": quote.css("span.text::text").get(),
"author": quote.css("small.author::text").get(),
"tags": quote.css("a.tag::text").getall(),
}
# Ikuti pagination
next_page = response.css("li.next a::attr(href)").get()
if next_page:
yield response.follow(next_page, self.parse)
Jalankan:
scrapy crawl quotes -o quotes.json
Dan voila — semua data tersimpan dalam quotes.json. Scrapy otomatis handle pagination, error handling, dan rate limiting. Dia juga punya robots.txt compliance yang bisa kamu aktifkan di settings.py:
# settings.py
ROBOTSTXT_OBEY = True
DOWNLOAD_DELAY = 1
CONCURRENT_REQUESTS = 8
Scrapy + Playwright untuk Situs Dinamis
Di 2026, ada plugin scrapy-playwright yang memungkinkan kamu pakai browser rendering langsung di dalam Scrapy pipeline:
pip install scrapy-playwright
import scrapy
class DynamicSpider(scrapy.Spider):
name = "dynamic"
def start_requests(self):
yield scrapy.Request(
url="https://example.com/dynamic-page",
meta={"playwright": True},
)
def parse(self, response):
for item in response.css(".dynamic-item"):
yield {
"title": item.css("h3::text").get(),
"content": item.css("p::text").get(),
}
Ini kombinasi terbaik untuk scraping modern: kekuatan Scrapy + rendering JavaScript dari Playwright.
Best Practices: Biar Scraper-mu Nggak Gampang Mati
Setelah bertahun-tahun scraping, saya belajar banyak dari kesalahan. Berikut ini tips yang saya wish someone told me earlier:
1. Selalu Pakai Header yang Realistis
Banyak situs yang nge-block request tanpa User-Agent yang jelas:
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/128.0.0.0 Safari/537.36",
"Accept-Language": "id-ID,id;q=0.9,en;q=0.8",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
}
response = requests.get(url, headers=headers)
2. Implementasi Retry Mechanism
Server bisa error kapan saja. Selalu siapkan retry:
import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
session = requests.Session()
retry = Retry(total=3, backoff_factor=1, status_forcelist=[500, 502, 503, 504])
adapter = HTTPAdapter(max_retries=retry)
session.mount("http://", adapter)
session.mount("https://", adapter)
response = session.get(url, headers=headers, timeout=30)
3. Cache Response Saat Development
Nggak mau kan setiap kali debug harus request ulang? Pakai requests-cache:
pip install requests-cache
import requests_cache
requests_cache.install_cache("my_cache", expire_after=3600) # Cache 1 jam
# Request pertama ke server, setelahnya dari cache
response = requests.get(url)
4. Handle Error Gracefully
def safe_scrape(url):
try:
response = requests.get(url, headers=headers, timeout=30)
response.raise_for_status()
return BeautifulSoup(response.text, "lxml")
except requests.exceptions.HTTPError as e:
print(f"HTTP error untuk {url}: {e}")
except requests.exceptions.ConnectionError:
print(f"Koneksi gagal: {url}")
except requests.exceptions.Timeout:
print(f"Timeout: {url}")
except Exception as e:
print(f"Error tak terduga: {e}")
return None
5. Simpan Progress
Kalau scraper-mu berjalan lama, simpan progress secara berkala supaya kalau crash, kamu nggak harus mulai dari awal:
import json
import os
PROGRESS_FILE = "progress.json"
def load_progress():
if os.path.exists(PROGRESS_FILE):
with open(PROGRESS_FILE, "r") as f:
return json.load(f)
return {"last_page": 0, "scraped_ids": []}
def save_progress(data):
with open(PROGRESS_FILE, "w") as f:
json.dump(data, f)
# Di dalam loop scraping:
progress = load_progress()
start_page = progress["last_page"]
for page in range(start_page, total_pages):
# ... scraping logic ...
progress["last_page"] = page + 1
save_progress(progress)
6. Rotasi User-Agent dan Proxy
Kalau kamu scraping ribuan halaman, rotasi user-agent bisa mengurangi risiko di-ban:
import random
user_agents = [
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/128.0.0.0 Safari/537.36",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 Safari/605.1.15",
"Mozilla/5.0 (X11; Linux x86_64; rv:130.0) Gecko/20100101 Firefox/130.0",
]
headers = {"User-Agent": random.choice(user_agents)}
Studi Kasus: Scrape Data Produk E-Commerce
Sekarang mari kita gabungkan semua yang sudah dipelajari ke dalam studi kasus nyata. Kita akan buat scraper yang cukup robust untuk mengambil data produk:
import requests
from bs4 import BeautifulSoup
import pandas as pd
import time
import random
from datetime import datetime
class ProductScraper:
def __init__(self):
self.session = requests.Session()
self.session.headers.update({
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 Chrome/128.0.0.0 Safari/537.36",
"Accept-Language": "id-ID,id;q=0.9",
})
self.data = []
self.scraped_at = datetime.now().isoformat()
def fetch_page(self, url):
try:
response = self.session.get(url, timeout=30)
response.raise_for_status()
return BeautifulSoup(response.text, "lxml")
except Exception as e:
print(f"[ERROR] Gagal fetch {url}: {e}")
return None
def parse_products(self, soup):
products = soup.select(".product-card")
for product in products:
try:
name = product.select_one(".product-title").get_text(strip=True)
price = product.select_one(".product-price").get_text(strip=True)
rating = product.select_one(".rating-value")
rating_text = rating.get_text(strip=True) if rating else "N/A"
self.data.append({
"name": name,
"price": price,
"rating": rating_text,
"scraped_at": self.scraped_at,
})
except AttributeError:
continue
return len(products)
def scrape(self, base_url, max_pages=10):
print(f"🚀 Mulai scraping: {base_url}")
for page in range(1, max_pages + 1):
url = f"{base_url}?page={page}"
soup = self.fetch_page(url)
if not soup:
break
count = self.parse_products(soup)
print(f" ✅ Halaman {page}: {count} produk")
if count == 0:
print(" 📌 Tidak ada data lagi, berhenti.")
break
# Random delay antara 1-3 detik
delay = random.uniform(1, 3)
time.sleep(delay)
print(f"🏁 Selesai! Total: {len(self.data)} produk")
return self.data
def save(self, filename="products.csv"):
df = pd.DataFrame(self.data)
df.to_csv(filename, index=False, encoding="utf-8-sig")
print(f"💾 Disimpan ke {filename}")
# Penggunaan
if __name__ == "__main__":
scraper = ProductScraper()
scraper.scrape("https://example-ecommerce.com/products", max_pages=20)
scraper.save("ecommerce_products.csv")
Pattern seperti ini sudah saya pakai di berbagai project dan terbukti solid. Tinggal kamu sesuaikan selector CSS-nya dengan situs target.
Tantangan Web Scraping di 2026 dan Cara Mengatasinya
Jujur saja, web scraping di 2026 makin menantang. Banyak situs yang sudah pakai teknologi anti-scraping canggih. Tapi bukan berarti nggak bisa diakali.
Cloudflare dan Anti-Bot
Banyak situs yang dilindungi Cloudflare. Pakai requests biasa nggak akan tembus. Solusinya:
- Playwright/Scrapy-Playwright: Browser automation bisa menembus challenge halaman.
- FlareSolverr: Proxy server yang bisa menyelesaikan Cloudflare challenge.
- Respect delay: Kadang cukup dengan memberi delay yang wajar.
CAPTCHA
Ini musuh utama scraper. Beberapa pendekatan:
- Hindari: Crawl dengan lambat supaya nggak trigger CAPTCHA.
- Layanan solving: Ada layanan seperti 2Captcha atau Anti-Captcha.
- Session management: Simpan cookies supaya kamu nggak dianggap visitor baru terus.
Rate Limiting
Server modern makin pintar mendeteksi pola request yang mencurigakan. Solusinya:
- Gunakan proxy pool (rotating proxy)
- Random delay antar request
- Simulasi perilaku browsing manusia
Menyimpan dan Mengolah Data Hasil Scraping
Data mentah itu belum berguna. Kamu perlu membersihkan dan mengolahnya:
import pandas as pd
df = pd.read_csv("products.csv")
# Bersihkan harga: "Rp 1.500.000" -> 1500000
df["price_numeric"] = (
df["price"]
.str.replace("Rp", "")
.str.replace(".", "")
.str.strip()
.astype(float)
)
# Filter produk di atas 500rb
expensive = df[df["price_numeric"] > 500000]
# Statistik sederhana
print(f"Rata-rata harga: Rp {df['price_numeric'].mean():,.0f}")
print(f"Produk termurah: Rp {df['price_numeric'].min():,.0f}")
print(f"Produk termahal: Rp {df['price_numeric'].max():,.0f}")
# Export ke Excel
expensive.to_excel("expensive_products.xlsx", index=False)
Kesimpulan
Web scraping dengan Python itu skill yang sangat bernilai di 2026. Dari riset pasar, pengumpulan dataset untuk AI, sampai monitoring harga — semuanya butuh scraping.
Ringkasan apa yang sudah kita bahas:
- BeautifulSoup + Requests → Untuk scraping sederhana dan situs statis.
- Playwright → Untuk situs yang di-render JavaScript.
- **Scrapy3. Scrapy → Untuk proyek scraping berskala besar.
Kalau lo butuh bantuan atau mau tanya lebih lanjut, langsung email ke [email protected]. Happy scraping!
FAQ
Q: Apakah web scraping legal? A: Tergantung situasi. Scraping data publik umumnya legal, tapi kalau situs tersebut punya kebijakan anti-scraping atau lo mengambil data privat, itu bisa bermasalah. Selalu baca robots.txt dan Terms of Service sebelum scraping.
Q: Apakah saya butuh proxy untuk scraping? A: Untuk scraping skala kecil biasanya tidak perlu. Tapi untuk scraping dalam jumlah besar, proxy sangat disarankan agar IP kamu tidak diblokir oleh target website.
Q: Apa perbedaan BeautifulSoup dan Scrapy? A: BeautifulSoup lebih ringan dan cocok untuk scraping sederhana. Scrapy adalah framework lengkap untuk proyek scraping berskala besar dengan fitur pipeline, middleware, dan parallelism built-in.