Ketika kamu sudah nyaman melakukan web scraping dengan BeautifulSoup, kamu mungkin mulai menyadari batasannya: setiap kali struktur halaman berubah kamu harus menulis ulang banyak kode, dan scraping ratusan halaman terasa lambat serta sulit dirawat. Di sinilah Scrapy hadir. Scrapy adalah framework web crawling paling populer di Python yang dirancang khusus untuk scraping berskala besar — lengkap dengan sistem spider, selector bawaan, pipeline pemrosesan data, hingga penanganan permintaan asinkron. Dalam tutorial ini kamu akan membangun spider Scrapy pertamamu dari nol dan memahami cara kerjanya secara menyeluruh.

Apa Itu Scrapy dan Kapan Memakainya?

Scrapy bukan sekadar library — ia adalah framework lengkap dengan struktur proyek, mesin crawling asinkron berbasis Twisted, dan ekosistem ekstensi. Berbeda dengan pendekatan manual, Scrapy memisahkan tanggung jawab ke dalam beberapa komponen:

  • Spider: kelas yang menentukan halaman mana yang diambil dan data apa yang diekstrak.
  • Item: struktur data yang mendefinisikan hasil scraping.
  • Item Pipeline: tahapan untuk membersihkan, memvalidasi, dan menyimpan data.
  • Middleware & Settings: tempat mengatur user-agent, jeda antar permintaan, dan proxy.

Kamu sebaiknya memilih Scrapy ketika target scraping mencapai puluhan hingga jutaan halaman, atau ketika kamu butuh alur crawling yang terstruktur dan mudah diuji. Untuk kasus satu halaman sederhana, BeautifulSoup sudah cukup; untuk halaman yang merender konten lewat JavaScript, gunakan Playwright. Scrapy duduk di antara keduanya: cepat, asinkron, dan kuat untuk crawling situs statis dalam skala besar.

Persiapan: Install Scrapy

bash
python -m venv venv
source venv/bin/activate  # Windows: venv\Scripts\activate
pip install scrapy

# Cek versi
scrapy version

Membuat Proyek Scrapy Pertama

Semua proyek Scrapy diawali dengan satu perintah. Jalankan perintah berikut di direktori kerja kamu:

bash
scrapy startproject tokoscraper
cd tokoscraper

# Struktur yang dihasilkan:
# tokoscraper/
# ├── scrapy.cfg
# └── tokoscraper/
#     ├── items.py
#     ├── middlewares.py
#     ├── pipelines.py
#     ├── settings.py
#     └── spiders/

Perintah ini membuat kerangka proyek lengkap. File items.py untuk mendefinisikan struktur data, pipelines.py untuk memproses hasil, settings.py untuk konfigurasi global, dan folder spiders/ untuk menaruh spider kamu.

Mari kita buat spider untuk mengambil judul, harga, dan rating buku dari situs latihan books.toscrape.com (situs demo yang memang disediakan untuk belajar scraping). Buat file baru tokoscraper/spiders/books.py:

python
import scrapy


class BooksSpider(scrapy.Spider):
    name = "books"
    start_urls = ["https://books.toscrape.com/"]

    def parse(self, response):
        for book in response.css("article.product_pod"):
            yield {
                "title": book.css("h3 a::attr(title)").get(),
                "price": book.css("p.price_color::text").get(),
                "rating": book.css("p.star-rating::attr(class)").get(),
            }

Penjelasan singkat:

  • name adalah identitas spider saat dijalankan via CLI.
  • start_urls adalah daftar URL awal yang akan di-request.
  • Metode parse() menerima objek response dan harus meng-yield dictionary item atau request lanjutan.
  • Selektor response.css() memakai sintaks CSS; ::text mengambil teks, sedangkan ::attr(title) mengambil nilai atribut HTML.

Menjalankan Spider dan Menyimpan Hasil

Jalankan spider dengan perintah crawl dan simpan hasilnya ke JSON:

bash
scrapy crawl books -o books.json

# Atau lihat langsung di terminal
scrapy crawl books

Flag -o books.json akan menulis seluruh hasil ke file JSON secara otomatis — tanpa perlu menulis kode tambahan. Scrapy juga mendukung format csv dan jsonl dengan cara yang sama.

Memahami Selector CSS dan XPath

Scrapy punya dua cara menyeleksi elemen: CSS (lebih ringkas) dan XPath (lebih fleksibel). Keduanya bisa dipakai bersamaan. Cobalah bereksperimen lewat Scrapy Shell yang interaktif:

bash
scrapy shell "https://books.toscrape.com/"

# Di dalam shell:
>>> response.css("title::text").get()
# 'All products | Books to Scrape - Sandbox'

>>> response.css("article.product_pod").xpath(".//h3/a/@title").get()
# 'A Light in the Attic'

>>> response.xpath("//a[contains(@title, 'Light')]/@href").get()
# 'a-light-in-the-attic_1000/index.html'

Tips: gunakan CSS untuk mayoritas kasus karena lebih mudah dibaca, lalu beralih ke XPath saat kamu butuh mencocokkan berdasarkan teks atau navigasi antar-elemen yang lebih rumit.

Untuk mengambil seluruh 1000 buku, spider harus mengikuti link halaman berikutnya. Kita modifikasi parse():

python
import scrapy


class BooksSpider(scrapy.Spider):
    name = "books"
    start_urls = ["https://books.toscrape.com/"]

    def parse(self, response):
        for book in response.css("article.product_pod"):
            yield {
                "title": book.css("h3 a::attr(title)").get(),
                "price": book.css("p.price_color::text").get(),
                "rating": book.css("p.star-rating::attr(class)").get(),
            }

        next_page = response.css("li.next a::attr(href)").get()
        if next_page is not None:
            yield response.follow(next_page, callback=self.parse)

response.follow() membangun request baru secara otomatis (termasuk menangani URL relatif) dan memanggil parse() lagi untuk halaman berikutnya. Inilah kekuatan utama Scrapy: mengikuti ribuan link hanya dengan beberapa baris kode, semuanya berjalan secara asinkron.

Membersihkan Data dengan Item Pipeline

Data mentah sering kali kotor. Rating dari p.star-rating misalnya bernilai star-rating Three, dan harga masih berupa string £51.77. Kita definisikan Item lalu bersihkan lewat pipeline. Pertama, definisikan item di items.py:

python
import scrapy


class BookItem(scrapy.Item):
    title = scrapy.Field()
    price = scrapy.Field()
    rating = scrapy.Field()

Lalu daftarkan pipeline di settings.py dan tulis logika pembersihannya di pipelines.py:

python
# settings.py
ITEM_PIPELINES = {
    "tokoscraper.pipelines.PricePipeline": 300,
}


# pipelines.py
class PricePipeline:
    def process_item(self, item, spider):
        # Bersihkan harga: "£51.77" -> 51.77
        raw = (item.get("price") or "").replace("£", "").strip()
        item["price"] = float(raw)

        # Rating: "star-rating Three" -> "Three"
        item["rating"] = (item.get("rating") or "").replace("star-rating ", "")
        return item

Setiap item yang di-yield oleh spider akan melewati pipeline secara berurutan. Di sinilah kamu bisa membersihkan data, membuang item duplikat, atau menyimpannya ke database.

Penting — Etika Scraping: Selalu hormati robots.txt dan aturan situs target. Jangan membanjiri server dengan permintaan, dan pastikan aktivitas scraping kamu sesuai hukum serta Terms of Service situs tersebut. Scrapy menyediakan ROBOTSTXT_OBEY = True untuk otomatis mematuhi robots.txt.

Menghindari Block: User-Agent dan Download Delay

Banyak situs memblokir bot berdasarkan user-agent bawaan Scrapy. Atur konfigurasi di settings.py agar spider kamu lebih sopan dan sulit dikenali sebagai bot:

python
# settings.py
ROBOTSTXT_OBEY = True
DOWNLOAD_DELAY = 1          # jeda 1 detik antar permintaan
USER_AGENT = "Mozilla/5.0 (compatible; TokoScraperBot/1.0; +https://example.com/bot)"
CONCURRENT_REQUESTS = 8    # batasi jumlah permintaan paralel

DOWNLOAD_DELAY dan CONCURRENT_REQUESTS adalah dua kunci agar kamu tidak membebani server target. Untuk kebutuhan lebih lanjut seperti rotasi proxy atau user-agent acak, kamu bisa menambahkan middleware pihak ketiga seperti scrapy-user-agents.

Kesimpulan

Scrapy memberimu kerangka kerja lengkap untuk web scraping skala besar: spider yang terstruktur, selector CSS/XPath, pipeline data, dan kontrol penuh atas kecepatan crawling. Kamu kini bisa mengambil ribuan halaman dengan kode yang rapi dan mudah dirawat. Jika target kamu sederhana, mulailah dengan BeautifulSoup; jika halamannya membutuhkan JavaScript, beralihlah ke Playwright. Selamat mencoba, dan jangan lupa untuk selalu scraping secara bertanggung jawab!