26 minute read

Sebagaimana kita ketahui bersama, beberapa saat lalu terjadi kekisruhan di kalangan pejabat terkait data tenaga kesehatan (khususnya dokter) yang ada di Indonesia.

Memangnya di mana sih kita bisa mendapatkan data update terkait banyaknya tenaga kesehatan di Indonesia?

Salah satu sumber terpercaya yang bisa kita percaya adalah situs Badan PPSDM Kemenkes.

Keterangan gambar: Data provinsi bisa di- drill down sampai level kabupaten dan kota.


Kalau kita perhatikan baik-baik, bentuk data yang disajikan dalam website tersebut sudah berbentuk tabel. Walaupun kita bisa dengan mudah men-download datanya dalam bentuk Ms. Excel, tapi akan sangat menguntungkan jika kita melakukan web scraping dengan R.

Lho kok malah begitu?

Jika kita ingin melakukan scraping secara otomatis untuk semua data yang ada di sana (termasuk data kota dan kabupaten), membuat algoritma scraping dan menggabungkan semua datanya adalah langkah yang paling cepat dan tepat.


Langkah Web Scraping dengan R

Web scraping dengan menggunakan R setidaknya bisa dilakukan dengan 2 cara, yakni:

  1. Menggunakan library(rvest), menargetkan isi css dari html doc suatu webpages.
  2. Menggunakan library(Rselenium), menggunakan prinsip mimic apa yang kita lakukan di web browser.

Sekarang, saya akan gunakan prinsip library(rvest) untuk mengambil website berisi tabel. Caranya sangatlah mudah, cukup dengan menggunakan html_table() saja.

Kira-kira begini workflow-nya:


Web Scrape untuk Informasi Provinsi

Saya akan tunjukkan cara melakukan web scraping pada situs informasi provinsi sebagai berikut:

# tahap 1
# load libraries yang dibutuhkan
library(rvest)
library(dplyr)

# tahap 2
# simpan url target
url = "http://bppsdmk.kemkes.go.id/info_sdmk/info/index?rumpun=101"

# tahap 3
# lakukan scrape tabel
data = read_html(url) %>% html_table(fill = T)

Data tabel sudah berhasil kita scrape. Mari kita lihat dulu struktur dari data tersebut:

str(data)
## List of 1
##  $ :'data.frame':    36 obs. of  9 variables:
##   ..$ No.                  : chr [1:36] "No." "1" "2" "3" ...
##   ..$ Nama Provinsi        : chr [1:36] "Nama Provinsi" "ACEH" "SUMATERA UTARA" "SUMATERA BARAT" ...
##   ..$ Jumlah Unit          : chr [1:36] "Jumlah Unit" "447" "827" "426" ...
##   ..$ Jumlah Tenaga Medis  : chr [1:36] "Dokter Umum" "1556" "3097" "1279" ...
##   ..$ Jumlah Tenaga Medis  : chr [1:36] "Jumlah Tenaga Medis" "375" "768" "446" ...
##   ..$ Jumlah Tenaga Medis  : chr [1:36] "Dokter Gigi" "806" "1817" "838" ...
##   ..$ Jumlah Tenaga Medis  : chr [1:36] "Dokter Spesialis" "16" "59" "14" ...
##   ..$ Jumlah Tenaga Medis  : chr [1:36] "Dokter Sub Spesialis" "22" "51" "20" ...
##   ..$ Jumlah (Per Provinsi): chr [1:36] "Dokter Gigi Spesialis & Dokter Gigi Sub Spesialis" "2775" "5792" "2597" ...

Ternyata data berbentuk list berisi satu element saja berbentuk data.frame. Kita cukup mengambil element pertama dari list tersebut.

data = data[[1]]

Kita cek kembali struktur datanya:

str(data)
## 'data.frame':    36 obs. of  9 variables:
##  $ No.                  : chr  "No." "1" "2" "3" ...
##  $ Nama Provinsi        : chr  "Nama Provinsi" "ACEH" "SUMATERA UTARA" "SUMATERA BARAT" ...
##  $ Jumlah Unit          : chr  "Jumlah Unit" "447" "827" "426" ...
##  $ Jumlah Tenaga Medis  : chr  "Dokter Umum" "1556" "3097" "1279" ...
##  $ Jumlah Tenaga Medis  : chr  "Jumlah Tenaga Medis" "375" "768" "446" ...
##  $ Jumlah Tenaga Medis  : chr  "Dokter Gigi" "806" "1817" "838" ...
##  $ Jumlah Tenaga Medis  : chr  "Dokter Spesialis" "16" "59" "14" ...
##  $ Jumlah Tenaga Medis  : chr  "Dokter Sub Spesialis" "22" "51" "20" ...
##  $ Jumlah (Per Provinsi): chr  "Dokter Gigi Spesialis & Dokter Gigi Sub Spesialis" "2775" "5792" "2597" ...

Nah, sekarang data kita sudah berbentuk data.frame. Mari kita lihat bagaimana isinya:

No. Nama Provinsi Jumlah Unit Jumlah Tenaga Medis Jumlah Tenaga Medis Jumlah Tenaga Medis Jumlah Tenaga Medis Jumlah Tenaga Medis Jumlah (Per Provinsi)
No. Nama Provinsi Jumlah Unit Dokter Umum Jumlah Tenaga Medis Dokter Gigi Dokter Spesialis Dokter Sub Spesialis Dokter Gigi Spesialis & Dokter Gigi Sub Spesialis
1 ACEH 447 1556 375 806 16 22 2775
2 SUMATERA UTARA 827 3097 768 1817 59 51 5792
3 SUMATERA BARAT 426 1279 446 838 14 20 2597
4 RIAU 402 1452 428 622 23 15 2540
5 JAMBI 615 892 234 382 5 21 1534
6 SUMATERA SELATAN 463 1239 280 792 48 34 2393
7 BENGKULU 332 454 134 208 0 7 803
8 LAMPUNG 493 1346 197 691 7 15 2256
9 KEPULAUAN BANGKA BELITUNG 280 532 105 202 2 13 854
10 KEPULAUAN RIAU 185 620 162 361 5 27 1175
11 DKI JAKARTA 3193 6602 1972 6620 545 781 16520
12 JAWA BARAT 4645 5917 1519 3573 49 228 11286
13 JAWA TENGAH 3912 6642 1476 4567 91 209 12985
14 DI YOGYAKARTA 537 1559 432 1363 23 177 3554
15 JAWA TIMUR 5437 6541 1975 5323 54 365 14258
16 BANTEN 658 2119 578 1475 42 91 4305
17 BALI 451 1584 513 1317 48 36 3498
18 NUSA TENGGARA BARAT 314 874 165 394 6 18 1457
19 NUSA TENGGARA TIMUR 449 602 139 139 1 1 882
20 KALIMANTAN BARAT 358 699 137 285 2 15 1138
21 KALIMANTAN TENGAH 267 546 103 227 0 10 886
22 KALIMANTAN SELATAN 389 820 241 489 2 31 1583
23 KALIMANTAN TIMUR 290 887 262 482 6 36 1673
24 KALIMANTAN UTARA 87 255 46 104 1 5 411
25 SULAWESI UTARA 281 961 134 516 13 8 1632
26 SULAWESI TENGAH 275 507 139 254 0 4 904
27 SULAWESI SELATAN 1009 1484 695 1146 10 84 3419
28 SULAWESI TENGGARA 356 571 180 211 3 4 969
29 GORONTALO 158 278 66 143 0 3 490
30 SULAWESI BARAT 150 229 91 86 1 7 414
31 MALUKU 259 314 53 95 6 3 471
32 MALUKU UTARA 180 245 48 91 2 4 390
33 PAPUA BARAT 207 222 40 93 3 1 359
34 PAPUA 422 585 78 139 0 2 804
Total Total 28754 53510 14211 35851 1087 2348 107007

Ternyata didapati colnames(data) kurang tepat dan isi baris pertama sebenarnya tidak diperlukan. Oke, sekarang kita akan membersihkan data di atas dengan prinsip tidy.

  • judul_kolom dari data sebenarnya adalah isi baris (minus kolom kelima) ditambah colnames(data) element ke-9.
baris_1 = t(data[1,])

judul_kolom = c(baris_1[-5],colnames(data)[9])
  • Ganti colnames(data) dengan judul_kolom lalu hapus data baris pertama.
colnames(data) = judul_kolom
data = data[-1,]
  • Hapus baris berisi total.
data = 
  data %>% 
  filter(No. != "Total")

Mari kita lihat hasilnya:

No. Nama Provinsi Jumlah Unit Dokter Umum Dokter Gigi Dokter Spesialis Dokter Sub Spesialis Dokter Gigi Spesialis & Dokter Gigi Sub Spesialis Jumlah (Per Provinsi)
1 ACEH 447 1556 375 806 16 22 2775
2 SUMATERA UTARA 827 3097 768 1817 59 51 5792
3 SUMATERA BARAT 426 1279 446 838 14 20 2597
4 RIAU 402 1452 428 622 23 15 2540
5 JAMBI 615 892 234 382 5 21 1534
6 SUMATERA SELATAN 463 1239 280 792 48 34 2393
7 BENGKULU 332 454 134 208 0 7 803
8 LAMPUNG 493 1346 197 691 7 15 2256
9 KEPULAUAN BANGKA BELITUNG 280 532 105 202 2 13 854
10 KEPULAUAN RIAU 185 620 162 361 5 27 1175
11 DKI JAKARTA 3193 6602 1972 6620 545 781 16520
12 JAWA BARAT 4645 5917 1519 3573 49 228 11286
13 JAWA TENGAH 3912 6642 1476 4567 91 209 12985
14 DI YOGYAKARTA 537 1559 432 1363 23 177 3554
15 JAWA TIMUR 5437 6541 1975 5323 54 365 14258
16 BANTEN 658 2119 578 1475 42 91 4305
17 BALI 451 1584 513 1317 48 36 3498
18 NUSA TENGGARA BARAT 314 874 165 394 6 18 1457
19 NUSA TENGGARA TIMUR 449 602 139 139 1 1 882
20 KALIMANTAN BARAT 358 699 137 285 2 15 1138
21 KALIMANTAN TENGAH 267 546 103 227 0 10 886
22 KALIMANTAN SELATAN 389 820 241 489 2 31 1583
23 KALIMANTAN TIMUR 290 887 262 482 6 36 1673
24 KALIMANTAN UTARA 87 255 46 104 1 5 411
25 SULAWESI UTARA 281 961 134 516 13 8 1632
26 SULAWESI TENGAH 275 507 139 254 0 4 904
27 SULAWESI SELATAN 1009 1484 695 1146 10 84 3419
28 SULAWESI TENGGARA 356 571 180 211 3 4 969
29 GORONTALO 158 278 66 143 0 3 490
30 SULAWESI BARAT 150 229 91 86 1 7 414
31 MALUKU 259 314 53 95 6 3 471
32 MALUKU UTARA 180 245 48 91 2 4 390
33 PAPUA BARAT 207 222 40 93 3 1 359
34 PAPUA 422 585 78 139 0 2 804

Apakah sudah selesai? Mari kita lihat kembali struktur data kembali:

str(data)
## 'data.frame':    34 obs. of  9 variables:
##  $ No.                                              : chr  "1" "2" "3" "4" ...
##  $ Nama Provinsi                                    : chr  "ACEH" "SUMATERA UTARA" "SUMATERA BARAT" "RIAU" ...
##  $ Jumlah Unit                                      : chr  "447" "827" "426" "402" ...
##  $ Dokter Umum                                      : chr  "1556" "3097" "1279" "1452" ...
##  $ Dokter Gigi                                      : chr  "375" "768" "446" "428" ...
##  $ Dokter Spesialis                                 : chr  "806" "1817" "838" "622" ...
##  $ Dokter Sub Spesialis                             : chr  "16" "59" "14" "23" ...
##  $ Dokter Gigi Spesialis & Dokter Gigi Sub Spesialis: chr  "22" "51" "20" "15" ...
##  $ Jumlah (Per Provinsi)                            : chr  "2775" "5792" "2597" "2540" ...

Ternyata, variabel-variabel penting malah memiliki tipe character bukan numeric. Jadi langkah final kita tinggal mengkonversi variabel-variabel tersebut menjadi numeric. Ada banyak cara untuk bisa melakukannya, tapi saya akan gunakan cara simpel dengan flow sebagai berikut:

prov = data$`Nama Provinsi`

data = 
  data %>% 
  select(-`Nama Provinsi`) %>% 
  mutate_all(as.numeric)

data$`Nama Provinsi` = prov

Kita lihat kembali hasil finalnya:

## 'data.frame':    34 obs. of  9 variables:
##  $ No.                                              : num  1 2 3 4 5 6 7 8 9 10 ...
##  $ Jumlah Unit                                      : num  447 827 426 402 615 463 332 493 280 185 ...
##  $ Dokter Umum                                      : num  1556 3097 1279 1452 892 ...
##  $ Dokter Gigi                                      : num  375 768 446 428 234 280 134 197 105 162 ...
##  $ Dokter Spesialis                                 : num  806 1817 838 622 382 ...
##  $ Dokter Sub Spesialis                             : num  16 59 14 23 5 48 0 7 2 5 ...
##  $ Dokter Gigi Spesialis & Dokter Gigi Sub Spesialis: num  22 51 20 15 21 34 7 15 13 27 ...
##  $ Jumlah (Per Provinsi)                            : num  2775 5792 2597 2540 1534 ...
##  $ Nama Provinsi                                    : chr  "ACEH" "SUMATERA UTARA" "SUMATERA BARAT" "RIAU" ...
No. Jumlah Unit Dokter Umum Dokter Gigi Dokter Spesialis Dokter Sub Spesialis Dokter Gigi Spesialis & Dokter Gigi Sub Spesialis Jumlah (Per Provinsi) Nama Provinsi
1 447 1556 375 806 16 22 2775 ACEH
2 827 3097 768 1817 59 51 5792 SUMATERA UTARA
3 426 1279 446 838 14 20 2597 SUMATERA BARAT
4 402 1452 428 622 23 15 2540 RIAU
5 615 892 234 382 5 21 1534 JAMBI
6 463 1239 280 792 48 34 2393 SUMATERA SELATAN
7 332 454 134 208 0 7 803 BENGKULU
8 493 1346 197 691 7 15 2256 LAMPUNG
9 280 532 105 202 2 13 854 KEPULAUAN BANGKA BELITUNG
10 185 620 162 361 5 27 1175 KEPULAUAN RIAU
11 3193 6602 1972 6620 545 781 16520 DKI JAKARTA
12 4645 5917 1519 3573 49 228 11286 JAWA BARAT
13 3912 6642 1476 4567 91 209 12985 JAWA TENGAH
14 537 1559 432 1363 23 177 3554 DI YOGYAKARTA
15 5437 6541 1975 5323 54 365 14258 JAWA TIMUR
16 658 2119 578 1475 42 91 4305 BANTEN
17 451 1584 513 1317 48 36 3498 BALI
18 314 874 165 394 6 18 1457 NUSA TENGGARA BARAT
19 449 602 139 139 1 1 882 NUSA TENGGARA TIMUR
20 358 699 137 285 2 15 1138 KALIMANTAN BARAT
21 267 546 103 227 0 10 886 KALIMANTAN TENGAH
22 389 820 241 489 2 31 1583 KALIMANTAN SELATAN
23 290 887 262 482 6 36 1673 KALIMANTAN TIMUR
24 87 255 46 104 1 5 411 KALIMANTAN UTARA
25 281 961 134 516 13 8 1632 SULAWESI UTARA
26 275 507 139 254 0 4 904 SULAWESI TENGAH
27 1009 1484 695 1146 10 84 3419 SULAWESI SELATAN
28 356 571 180 211 3 4 969 SULAWESI TENGGARA
29 158 278 66 143 0 3 490 GORONTALO
30 150 229 91 86 1 7 414 SULAWESI BARAT
31 259 314 53 95 6 3 471 MALUKU
32 180 245 48 91 2 4 390 MALUKU UTARA
33 207 222 40 93 3 1 359 PAPUA BARAT
34 422 585 78 139 0 2 804 PAPUA

Bagaimana?

Mungkin ada kesan bahwa cara ini rumit yah dibandingkan save file Ms. Excel langsung dari website. Tapi kalau kalian ingin scrape semua detail kabupaten kota, cara ini jauh lebih cepat dibandingkan save manual satu-persatu lalu menggabungkannya di Ms. Excel.

Nantikan posting saya selanjutnya mengenai tutorial scrape data tenaga kesehatan (dokter) per kabupaten kota menggunakan R.