Scraping KBBI Daring Menggunakan NodeJS

Sepertinya belum ada kata Bahasa Indonesia yang baku sebagai padanan kata scraping (atau lengkapnya; web scraping). Sederhananya, (web) scraping bisa diartikan sebagai memanen, mengurai atau mengambil data dari suatu situs web.

Jika situsnya milik pribadi tentu tidak menjadi masalah, namun bagaimana jika situsnya milik pihak lain? Di sinilah kejelasan web scraping mulai memudar menjadi abu-abu.
Namun dalam kesempatan kali ini, kita biarkan hal tersebut menjadi kajian para ahli hukum. Saya hanya akan sedikit menuliskan cara bagaimana memanen data dari situs KBBI.

Mengapa mesti mengambil data Kamus Besar Bahasa Iindonesia Daring dengan cara scraping?
Ini bermula dari keisengan mengoprek bot Telegram. Berawal dari niat menambah fungsi kamus Bahasa indonesia dari KBBI, ternyata saya menemukan kendala mendapatkan sumber data yang mudah diakses.
Saya bisa dengan relatif mudah mendapat sumber data untuk bahasa Inggris dari oxforddictionaries.com, atau alat terjemah dari Yandex. Tapi tidak untuk Bahasa Indonesia.

Kini bot Telegram yang saya oprek tersebut telah tewas. Dan didasari keinginan agar pengetahuan dibaliknya tidak ikut menghilang, maka ditulislah artikel ini.
Jika Anda hendak mengikuti cara scraping sesuai yang saya akan tulis di bawah ini, patut diingat bahwasanya saya berlepas diri dari segala yang Anda lakukan.

Mungkin benak Anda bertanya, mengapa NodeJS?
Tidak ada alasan selain karena pengetahuan scraping ini saya peroleh kala membuat bot Telegram yang berdasar NodeJS. Jadi bukan karena alasan keunggulan teknis, kemudahan atau lainnya.

Sesuai judul, kita akan melakukan scraping web kbbi.kemdikbud.go.id untuk mencari arti suatu kata bahasa Indonesia. Proses scraping dilakukan otomatis dengan bantuan pustaka node-scrapy di NodeJS. node-scrapy ini sendiri merupakan antarmuka yang lebih "manusiawi" untuk pustaka request dan cheerio. Jadi request yang meminta data, dan cheerio yang memanen data.

Dan karena cheerio tidak bisa memanen data dari situs dinamis yang berdasar javascript, begitu pula node-scrapy. Untuk menguji apakah kita bisa memanen data dari sebuah situs dengan menggunakan cheerio, coba matikan javascript pada situs tersebut. Jika data yang diinginkan masih tetap tampil walau javascript telah dimatikan, maka kita bisa menggunakan cheerio untuk memanen data dari situs tersebut.
Dan untungnya kbbi.kemdikbud.go.id masuk dalam kategori scrapable.

Baiklah kita mulai saja.

Memulai

Seperti biasanya tiap kali memulai proyek NodeJS:

  1. Buat folder untuk proyek. Misalnya nama folder tersebut kbbi.
    mkdir kbbi
    
  2. Masuk ke dalam folder tersebut.
    cd kbbi
    
  3. Buat berkas package.json. Dengan cara:

    • Menggunakan npm init kemudian memasang paket node-scrapy menggunakan perintah npm i node-scrapy.
    • Menulis berkas package.json secara manual kemudian menjalankan perintah npm install untuk memasang paket yang diperlukan. Berikut contoh package.json-nya:
      {
        "name": "kbbi",
        "version": "0.0.1",
        "description": "Mencari arti kata di KBBI Daring",
        "main": "kbbi.js",
        "author": "Sahri Riza Umami",
        "dependencies": {
          "node-scrapy": "latest"
        }
      }
      

Membuat skrip

Dalam package.json di atas, saya contohkan main script adalah kbbi.js. Gunakan penyunting teks andalan Anda untuk membuat dan menyunting berkas kbbi.js sebagai tempat kita menempatkan skrip scraper.

Sunting skrip kbbi.js untuk mengisikan baris-baris berikut:

  • Muat pustaka node-scrapy.
    const scrapy = require('node-scrapy')
    
  • Buat variabel untuk laman kbbi.
    const url = 'https://kbbi.kemdikbud.go.id/entri/'
    

  • Buat variabel untuk kata yang akan kita cari artinya.
    const kata = process.argv.slice(2).join(' ')
    

    Rencananya, kita akan mencari arti kata dengan cara mengetik perintah node kbbi.js <kata_yang_dicari>.
    NodeJS akan mengumpulkan perintah ke dalam array. Misal perintah node kbbi.js aku akan disusun menjadi ['node', 'kbbi.js', 'aku'], dengan 0 = node, 1 = kbbi.js dan 2 = aku.
    Nah, .slice(2) akan mengiris bagian depan array dan mengambil mulai dari nilai ketiga (karena NodeJS menghitung mulai dari 0) hingga akhir.
    Bagaimana jika kita mencari arti kata yang majemuk? Misal "kaki tangan"? Ini gunanya .join(' '). Ia akan menggabungkan kata jamak dan memberi spasi diantaranya.

  • Situs kbbi.kemdikbud.go.id tidaklah rumit. Namun penampilan arti katanya saya dapati tidaklah teratur. Karenanya kita perlu membuat sebuah model data untuk menampung hasil scraping.
    const model = {
      lema: ,
      arti: 
    }
    

    lema adalah tempat menampung kata yang kita cari artinya, dan arti adalah penampungan dari arti-arti kata yang berhasil kita scrap. Untuk memberi gambaran awal apa yang akan kita isi di model-model tersebut, silakan lihat contoh-contoh di repo node-scrapy.

    node-scrapy memanen data dengan cara menelusuri DOM dari sebuah halaman web. Karenanya kini kita perlu menyediakan elemen apa saja yang patut dikumpulkan oleh node-scrapy.
    Hampir semua peramban web modern telah memiliki fitur web development, namun di sini saya hanya akan mencontohkan menggunakan Firefox.
    Silakan jalankan Firefox dan buka laman https://kbbi.kemdikbud.go.id kemudian ketikkan suatu kata untuk dicari artinya. Misal kita ketik kata "apa". Setelah hasil pencarian muncul, klik kanan pada tulisan "apa" dan pilih Inspect Element (Q). Hasilnya akan tampak seperti berikut:

    Gambar jendela Firefox ketika melakukan inspect element pada tulisan di laman kbbi.kemdikbud.go.id

    Bisa kita lihat lema selalu ditulis dalam tag <h2>. Masukkan tag ini ke dalam model data.

    const model = {
      lema: 'h2',
      arti: 
    }
    

    Sekarang telaah elemen pada bagian arti kata. Ternyata kita mendapati dua hasil:

    1. Kata "apa" di bagian atas memiliki banyak arti yang disusun menggunakan tag <ol>. Jadi elemen untuk arti "apa" di bagian ini adalah ol li, yang artinya node-scrapy akan mengambil data tag <ol> yang memiliki child <li>.

      Gambar jendela Firefox ketika melakukan inspect element pada tulisan di laman kbbi.kemdikbud.go.id
    2. Sementara kata "apa" di bagian bawah hanya memiliki satu arti yang ditulis dalam tag <ul>. Namun kita tidak bisa langsung menuliskan elemen ini ke model data karena dalam halaman terdapat banyak tag ul > li. Untungnya, tag ul untuk arti lema memiliki sebuah class bernama adjusted-par.
      Jadi elemen untuk arti kata "apa" yang kedua ini bisa kita tulis sebagai ul.adjusted-par, yang artinya node-scrapy hanya akan mengambil data pada tag ul jika ia memiliki class adjusted-par.

      Gambar jendela Firefox ketika melakukan inspect element pada tulisan di laman kbbi.kemdikbud.go.id

    Akhirnya, model data selengkapnya kita dapati sebagai berikut:

    const model = {
      lema: 'h2',
      arti: ['ol li', 'ul.adjusted-par']
    }
    

  • Saatnya untuk membuat logika untuk meminta dan memanen data.
    scrapy.scrape(url + encodeURIComponent(kata), model, (err, data) => {
      if (err) return console.log(err)
      console.log(data)
    })
    

    node-scrapy akan meminta data dari url + encodeURIComponent(kata) dan kemudian memanen data berdasar model. Hasil scrap akan disimpan dalam data dan jika ternyata mendapati galat akan disampaikan dalam err.
    Baris if (err) return console.log(err) berarti jika skrip mendapati galat, hentikan skrip dan tampilkan error.
    Sementara baris console.log(data) artinya jika proses lancar, tampilkan data hasil scraping ke konsol.

Tampilan skrip kbbi.js selengkapnya adalah seperti berikut:

const scrapy = require('node-scrapy')
const url = 'https://kbbi.kemdikbud.go.id/entri/'
const kata = process.argv.slice(2).join(' ')
const model = {
  lema: 'h2',
  arti: ['ol li', 'ul.adjusted-par']
}

scrapy.scrape(url + encodeURIComponent(kata), model, (err, data) => {
  if (err) return console.log(err)
  console.log(data)
})

Menjalankan skrip

Untuk menjalankan skrip, gunakan pola perintah berikut: node kbbi.js KATA-YANG-AKAN-DICARI-ARTINYA.
Misal untuk mencari arti kata "apa":

$ node kbbi.js apa
{ lema: [ 'apa1', 'apa2' ],
  arti: 
   { '0': 
      [ 'pron kata tanya untuk menanyakan nama (jenis, sifat) sesuatu: ular -- ini?; pohon -- yang kautanam?',
        'pron kata tanya untuk pengganti sesuatu: -- yang dimaksudkan orang itu tadi?',
        'pron kata tanya untuk menanyakan pertalian kekeluargaan: (pernah) --mu anak itu?',
        'pron pengganti sesuatu yang kurang terang; pengganti barang sesuatu: ia tidak tahu -- isi kotak itu',
        'p hor untuk menghaluskan permintaan: sudi --lah kiranya Bapak mengabulkan permohonan kami',
        'p cak untuk mendahului kalimat tanya: -- besok ada ulangan? -- tamu itu pamanmu?',
        'p cak atau: mau minum teh -- kopi; jadi berangkat hari ini -- besok' ],
     '1': 'n Mdr buah tanaman sirih' } }

Atau mencari arti "kaki tangan":

$ node kbbi.js kaki tangan
{ lema: 'kaki1 ยป kaki tangan',
  arti: 
   { '0': 
      [ 'kaki dan tangan',
        'ki orang yang diperalat orang lain untuk membantu' ],
     '1': null } }

Keluaran skrip ini memang belum sepenuhnya "manusiawi" namun pastinya telah mudah untuk dicerna. Kini kembali ke kreativitas kita untuk mengolah data ini menjadi bentuk yang diinginkan.

Demikian bagaimana menggunakan pustaka node-scrapy di NodeJS untuk scraping laman web kbbi.kemdikbud.go.id guna mencari arti kata Bahasa Indonesia.
Kesulitan yang saya rasakan dalam melakukan scraping seperti di atas adalah bagaimana menelusuri DOM dan menemukan elemen yang tepat untuk data yang diinginkan. Namun itu pastinya karena saya bukanlah web developer, bagi Anda yang berpengetahuan di bidang ini pastilah tidak akan merasakan kerumitan yang sama.

Akhir kata, happy scraping dan bijaklah dalam melakukannya.
Semoga bermanfaat.