Membangun spider pertama dengan Scrapling: mendefinisikan start_urls dan callback parse, mengikuti tautan dengan response.follow hingga menjelajah banyak halaman, mengatur koncurrency dan throttling, memakai multi-session, serta mengendalikan kedalaman crawl untuk hasil yang terstruktur.

Sepuluh episode terakhir mengajarkan kalian bermain di level request dan parsing. Sekarang saatnya merangkai semuanya menjadi sebuah mesin crawl yang utuh. Di episode 11 ini kita masuk ke framework spider Scrapling — struktur yang mirip Scrapy tapi tetap dengan satu bahasa yang sama: Adaptor, selector CSS/XPath, dan fetchers yang sudah kalian kenal.
Kalian akan belajar kenapa perlu spider, mendefinisikan spider pertama dengan start_urls dan callback parse, mengikuti tautan antar halaman dengan response.follow, mengatur koncurrency dan throttling, memakai multi-session untuk rute request berbeda, mengendalikan kedalaman crawl, lalu menjalankan spider dan mengumpulkan hasilnya. Setelah episode ini, satu start_urls bisa meledak menjadi ribuan halaman yang ter-crawl otomatis.
Semua yang kalian buat sejauh ini adalah pola request-tunggal: ambil satu URL, parse, selesai. Kalau kalian ingin meng-crawl 10 ribu halaman — mulai dari halaman indeks, mengikuti tautan ke halaman detail, lalu pagination — pola manual akan berantakan. Kalian harus mengatur sendiri antrian URL, deduplikasi, konkurensi, dan jeda antar request.
Spider adalah jawaban terstruktur. Ia mendefinisikan di mana memulai (start_urls), apa yang dilakukan saat halaman tiba (callback parse), dan halaman mana yang dikunjungi berikutnya (yield tautan baru). Framework menangani sisanya: antrian request, deduplikasi URL otomatis, penjadwalan, dan pengumpulan item. Ini memungkinkan satu spider kecil melahirkan crawl besar yang tetap rapi.
Struktur dasar spider sangat ringkas. Subclass Spider, beri name, daftar start_urls, dan definisikan parse sebagai fungsi async yang menerima Response. Setiap yield dictionary di dalam parse dianggap sebagai satu item hasil scraping.
from scrapling.spiders import Spider, Response
class QuoteSpider(Spider):
name = "quotes"
start_urls = ["https://quotes.toscrape.com/"]
async def parse(self, response: Response):
for quote in response.css(".quote"):
yield {
"teks": quote.css(".text::text").get(),
"penulis": quote.css(".author::text").get(),
}
QuoteSpider().start()start_urls memuat halaman awal, parse dieksekusi untuk setiap respons, dan setiap dictionary yang di-yield dikumpulkan sebagai item. Perhatikan bahwa parse adalah async def — spider Scrapling berjalan di atas event loop, sehingga semua kemampuan asinkron yang kalian pelajari di episode 6 tersedia di sini secara bawaan.
Kekuatan spider muncul ketika parse tidak hanya mengumpulkan data, tetapi juga mengikuti tautan. Saat kalian menemukan URL yang harus dikunjungi, yield sebuah request baru. Cara paling aman adalah response.follow, yang otomatis menyelesaikan URL relatif dan mewarisi referer. Berikut spider yang mengikuti pagination sampai halaman terakhir:
from scrapling.spiders import Spider, Response
class QuoteSpider(Spider):
name = "quotes"
start_urls = ["https://quotes.toscrape.com/"]
async def parse(self, response: Response):
for quote in response.css(".quote"):
yield {
"teks": quote.css(".text::text").get(),
"penulis": quote.css(".author::text").get(),
}
next_page = response.css(".next a::attr(href)").get()
if next_page:
yield response.follow(next_page)
result = QuoteSpider().start()
print("total:", len(result.items))Alur ini bagus: page satu menghasilkan item dan meminta page dua, page dua menghasilkan item dan meminta page tiga, dan seterusnya sampai .next tidak lagi ditemukan. Deduplikasi otomatis memastikan URL yang sudah dikunjungi tidak dikunjungi ulang. Pola yang sama bisa dipakai untuk mengikuti tautan ke halaman detail: yield response.follow(href, callback=self.parse_detail) dengan callback terpisah untuk memparsing halaman detail.
Spider mengeksekusi request secara paralel, dan kalian mengendalikan seberapa agresif lewat atribut kelas. concurrent_requests membatasi jumlah request yang boleh berjalan bersamaan secara global. concurrent_requests_per_domain membatasi konkurensi per domain — berguna saat meng-crawl banyak domain sekaligus tanpa membanjiri masing-masing.
from scrapling.spiders import Spider, Response
class PolitesSpider(Spider):
name = "polites"
start_urls = ["https://example.com/"]
concurrent_requests = 4
concurrent_requests_per_domain = 2
download_delay = 1.0
async def parse(self, response: Response):
yield {"judul": response.css("title::text").get("")}download_delay{python} menambahkan jeda tetap sebelum setiap request — rate limiting sederhana yang membuat spider sopan. Untuk penyesuaian otomatis, aktifkan AutoThrottle dengan autothrottle_enabled=True; spider akan mengukur seberapa cepat server merespons lalu menyesuaikan jeda per domain — mempercepat di server cepat, mengerem di server lambat atau yang mulai memblokir.
Tidak semua halaman perlu diperlakukan sama. Website sering punya kombinasi halaman publik yang mudah dan halaman yang dilindungi anti-bot. Spider mendukung multi-session: daftarkan beberapa session, lalu rute setiap request ke session yang sesuai dengan parameter sid.
from scrapling.spiders import Spider, Request, Response
from scrapling.fetchers import FetcherSession, AsyncStealthySession
class HybridSpider(Spider):
name = "hybrid"
start_urls = ["https://example.com/indeks"]
def configure_sessions(self, manager):
manager.add("fast", FetcherSession(impersonate="chrome"))
manager.add("stealth", AsyncStealthySession(headless=True), lazy=True)
async def parse(self, response: Response):
for link in response.css("a::attr(href)").getall():
if "lindungi" in link:
yield Request(link, sid="stealth", callback=self.parse_detail)
else:
yield Request(link, sid="fast", callback=self.parse_detail)
async def parse_detail(self, response: Response):
yield {"judul": response.css("h1::text").get()}configure_sessions{python} mendaftarkan session fast (HTTP murah) dan stealth (browser anti-deteksi, dibuat lazily supaya tidak boros). Setiap Request dirutekan lewat sid. Ini pola produksi yang sangat umum: halaman indeks ringan lewat HTTP, halaman lindungi lewat browser stealth — keduanya dalam satu spider.
Untuk kedalaman crawl, spider Scrapling mendeduplikasi URL otomatis, tapi kedalaman tetap tanggung jawab kalian. Pola umumnya adalah melacak kedalaman lewat meta request, lalu berhenti mengikuti tautan setelah melewati batas.
from scrapling.spiders import Spider, Request, Response
class DepthSpider(Spider):
name = "depth"
start_urls = ["https://example.com/"]
async def parse(self, response: Response):
kedalaman = response.meta.get("kedalaman", 0)
yield {"url": response.url, "kedalaman": kedalaman}
if kedalaman < 3:
for link in response.css("a::attr(href)").getall():
yield Request(
link,
callback=self.parse,
meta={"kedalaman": kedalaman + 1},
)response.meta membawa data dari request yang menghasilkan respons ini. Setiap kali spider mengikuti tautan, kedalaman bertambah; ketika mencapai batas (di sini 3), spider berhenti memperluas — mencegah crawl tak terkendali yang menyusuri seluruh internet.
Menjalankan spider semudah memanggil .start(). Hasilnya adalah objek result dengan koleksi item, statistik, dan helper ekspor. Untuk crawl panjang, Spider mendukung checkpoint: berikan crawldir, dan spider menyimpan progress secara berkala; tekan Ctrl+C untuk berhenti dengan rapi, lalu jalankan ulang untuk melanjutkan dari titik terakhir.
from scrapling.spiders import Spider, Response
class QuoteSpider(Spider):
name = "quotes"
start_urls = ["https://quotes.toscrape.com/"]
async def parse(self, response: Response):
for quote in response.css(".quote"):
yield {
"teks": quote.css(".text::text").get(),
"penulis": quote.css(".author::text").get(),
}
next_page = response.css(".next a::attr(href)").get()
if next_page:
yield response.follow(next_page)
result = QuoteSpider(crawldir="./crawl_data").start()
result.items.to_json("quotes.json")result.items.to_json("quotes.json"){python} menyerialisasi seluruh item ke file JSON — persis yang kalian pelajari secara manual di episode 10, tapi sekarang dalam satu baris. Gabungkan dengan crawldir dan spider kalian menjadi pipeline yang bisa dihentikan, di-resume, dan diekspor kapan saja. Ini adalah fondasi arsitektur crawl produksi yang akan kalian perdalam di fase-fase berikutnya.
Episode 11 ini menutup fase dasar Scrapling dengan merangkai semuanya menjadi spider. Kalian sudah belajar struktur spider dengan start_urls dan callback parse, mengikuti tautan dan pagination lewat response.follow, mengendalikan koncurrency dan throttling dengan concurrent_requests, download_delay, dan AutoThrottle, memakai multi-session untuk merutekan request HTTP vs stealth, mengatur kedalaman crawl dengan response.meta, serta menjalankan spider dan mengekspor hasil dengan .to_json. Satu request telah menjadi crawl skala penuh.
Inti yang harus dibawa pulang:
start_urls + callback parse async; setiap yield dictionary adalah item.response.follow mengikuti tautan dan menangani URL relatif secara otomatis.concurrent_requests, concurrent_requests_per_domain, dan download_delay mengendalikan kesopanan.sid) dan response.meta untuk kedalaman membangun crawl hybrid yang terkendali.Di episode 12 kita membahas pertahanan di lingkungan yang tidak bersahabat: proxy rotation dan anti-blocking — memakai proxy HTTP dan residential, rotasi otomatis, serta pengelolaan header dan fingerprint agar request sulit diblokir. Sampai jumpa!