rvest:
Web Scraping 101




Alfa Nugraha Pradana

Prodi Statistika dan Sains Data IPB University

Outline


  • HTML
  • CSS Selector
  • Ekstraksi Data
  • Atribut
  • Tabel
  • GitHub Actions
  • YAML

HTML

singkatan dari HyperText Markup Language


<html>
<head>
  <title>Page title</title>
</head>
<body>
  <h1 id='first'>A heading</h1>
  <p>Some text &amp; <b>some bold text.</b></p>
  <img src='myimg.png' width='100' height='100'>
</body>


HTML memiliki struktur hirarki yang dengan disusun oleh berbagai macam elemen yang diawali dengan:

  • tag pembuka (<tag>),
  • atribut (id="first"),
  • diakhir dengan tag penutup (</tag>),
  • dan konten yang diisi di antara tag pembuka dan penutup

Membaca HTML dengan rvest


Scraping proses diawal dengan read_html(). Nilai kembalian dari perintah tersebut adalah objek dalam bentuk dokumen XML yang nanti akan dimanipulasi dengan fungsi pada rvest

library(rvest)
library(dplyr)
html <- read_html("http://rvest.tidyverse.org/")
class(html)
[1] "xml_document" "xml_node"    


rvest juga menyediakan fungsi untuk membuat dokumen XML dari suatu HTML

html <- minimal_html("
  <p>This is a paragraph<p>
  <ul>
    <li>This is a bulleted list</li>
  </ul>
")
html 
{html_document}
<html>
[1] <head>\n<meta http-equiv="Content-Type" content="text/html; charset=UTF-8 ...
[2] <body>\n<p>This is a paragraph</p>\n<p>\n  </p>\n<ul>\n<li>This is a bull ...

Selektor CSS

CSS adalah singkatan dari Cascading Style Sheets yang digunakan sebagai alat untuk mendefinisikan tampilan visual pada dokumen HTML

CSS menyediakan bahasa miniatur untuk memilih elemen pada suatu halaman web yang dikenal dengan istilah CSS selectors. Selektor ini bisa saja kompleks tetapi akan digunakan secara sederhana pada rvest. Empat hal penting pada selektor:

  • p: memilih semua elemen tag <p>
  • .title: memilih semua elemen dengan class title
  • p.special: memilih semua elemen tag <p> dengan class special
  • #title: memilih elemen dengan atribut id yang berisi title. Atribut id harus unik di dalam suatu dokumen HTML, sehingga hanya akan ada satu elemen yang terpilih

html <- minimal_html("
  <h1>This is a heading</h1>
  <p id='first'>This is a paragraph</p>
  <p class='important'>This is an important paragraph</p>
")
html %>% html_element("h1")
{html_node}
<h1>


html %>% html_elements("p")
{xml_nodeset (2)}
[1] <p id="first">This is a paragraph</p>
[2] <p class="important">This is an important paragraph</p>


html %>% html_elements(".important")
{xml_nodeset (1)}
[1] <p class="important">This is an important paragraph</p>


html %>% html_elements("#first")
{xml_nodeset (1)}
[1] <p id="first">This is a paragraph</p>

Ekstraksi Data

html <- minimal_html("
  <ol>
    <li>apple &amp; pear</li>
    <li>banana</li>
    <li>pineapple</li>
  </ol>
")
html %>% 
  html_elements("li") %>% 
  html_text2()
[1] "apple & pear" "banana"       "pineapple"   


html <- minimal_html("<body>
  <p>
  This is
  a
  paragraph.</p><p>This is another paragraph.
  
  It has two sentences.</p>
")
html %>% 
  html_element("body") %>% 
  html_text() %>% 
  cat()

  
  This is
  a
  paragraph.This is another paragraph.
  
  It has two sentences.

Atribut


Contoh atribut yang digunakan sebagai informasi destinasi suatu alamat dan gambar.

html <- minimal_html("
  <p><a href='https://en.wikipedia.org/wiki/Cat'>cats</a></p>
  <img src='https://cataas.com/cat' width='100' height='200'>
")
html %>% 
  html_elements("a") %>% 
  html_attr("href")
[1] "https://en.wikipedia.org/wiki/Cat"
html %>% 
  html_elements("img") %>% 
  html_attr("src")
[1] "https://cataas.com/cat"

Tabel

html <- minimal_html("
  <table>
    <tr>
      <th>x</th>
      <th>y</th>
    </tr>
    <tr>
      <td>1.5</td>
      <td>2.7</td>
    </tr>
    <tr>
      <td>4.9</td>
      <td>1.3</td>
    </tr>
    <tr>
      <td>7.2</td>
      <td>8.1</td>
    </tr>
  </table>
  ")
html %>% 
  html_node("table") %>% 
  html_table()
# A tibble: 3 × 2
      x     y
  <dbl> <dbl>
1   1.5   2.7
2   4.9   1.3
3   7.2   8.1

html_element vs html_elements

html <- minimal_html("
  <ul>
    <li><b>C-3PO</b> is a <i>droid</i> that weighs <span class='weight'>167 kg</span></li>
    <li><b>R2-D2</b> is a <i>droid</i> that weighs <span class='weight'>96 kg</span></li>
    <li><b>Yoda</b> weighs <span class='weight'>66 kg</span></li>
    <li><b>R4-P17</b> is a <i>droid</i></li>
  </ul>
  ")
html %>% html_elements("b") %>% html_text2()
[1] "C-3PO"  "R2-D2"  "Yoda"   "R4-P17"


characters <- html %>% html_elements("li")
characters %>% html_element("b") %>% html_text2()
[1] "C-3PO"  "R2-D2"  "Yoda"   "R4-P17"


data.frame(
  name = characters %>% html_element("b") %>% html_text2(),
  species = characters %>% html_element("i") %>% html_text2(),
  weight = characters %>% html_element(".weight") %>% html_text2()
)
    name species weight
1  C-3PO   droid 167 kg
2  R2-D2   droid  96 kg
3   Yoda    <NA>  66 kg
4 R4-P17   droid   <NA>

GitHub Actions


GitHub Actions adalah platform CI/CD (continuous integration and continuous delivery) yang memungkinkan pengguna mengotomatisasi pengembangan tools dengan membuat suatu workflow.

GitHub Actions menyediakan mesin virtual Linux, Windows, dan MacOS untuk mengeksekusi workflow tersebut.

YAML

name: Daily Scraping Covid

on:
  schedule:
    - cron: '*/7 * * * *'  # every 7 minutes


jobs:
  covid-scrape:
    runs-on: macos-latest
    env:
      ATLAS_URL: ${{ secrets.ATLAS_URL }}
      ATLAS_COLLECTION: ${{ secrets.ATLAS_COLLECTION }}
      ATLAS_DB: ${{ secrets.ATLAS_DB }}
    steps:
      - name: Start time
        run: echo "$(date) ** $(TZ=Asia/Jakarta date)"
      - uses: actions/checkout@v3
      - uses: r-lib/actions/setup-r@v2
      - name: Install mongolite package
        run: Rscript -e 'install.packages("mongolite", dependencies = TRUE)'
      - name: Install rvest package
        run: Rscript -e 'install.packages("rvest", dependencies = TRUE)'        
      - name: Scrape data 
        run: Rscript scrape.R

rvest & mongolite

library(rvest)
library(mongolite)

url <- "https://www.worldometers.info/coronavirus/country/indonesia/"
html <- read_html(url)
count <- html_text(html_nodes(html, ".maincounter-number"), trim=T)

atlas <- mongo(
  collection = Sys.getenv("ATLAS_COLLECTION"),
  db         = Sys.getenv("ATLAS_DB"),
  url        = Sys.getenv("ATLAS_URL")
)

newcovid <- data.frame(no = atlas$count() + 1, cases = count[1], deaths = count[2], recovered = count[3])
atlas$insert(newcovid)

atlas$disconnect()

Langkah Membangun Scraping Bot

  • Pada GitHub, buat repositori projek
  • Clone projek tersebut menjadi sesi projek baru pada RStudio
  • Membuat sintaks R untuk proses scraping dan storing data ke MongoDB Atlas
  • Membuat sintaks YAML untuk proses penjadwalan otomatis pada GitHub Actions
  • Push seluruh script yang dibutuhkan
  • Pada Database Deployment Atlas, pilih menu [Connect - Driver], copy string koneksi berikut

  • Kembali ke GitHub, Aktifkan Action permissions pada menu [Actions - General - Allow all actions and reusable workflows]
  • Buat respository secret yang baru pada menu Actions secrets and variabels, dan isi dengan string yang sudah dipersiapkan sebelumnya untuk nama koleksi, database, dan Atlas URL

  • Periksa secara berkala workflow yang sudah dibangun

  • Buat status badge

  • Sematkan di dalam README.md projek untuk menampilkan status otomatisasi scraping bot yang sudah aktif

  • DONE

Tugas Akhir Praktikum MDS Sesi UAS


  • Membuat scraping bot terjadwal pada situs web yang sudah dipilih sebelumnya menggunakan rvest dan GitHub Actions

  • Menyimpan hasil scraping tersebut disimpan ke dalam MongoDB Cloud Atlas

  • Membuat narasi tentang tugas yang dikerjakan pada akun GitHub

  • (Opsional) Visualisasi hasil dalam bentuk tabel, grafik, laporan di RPubs, atau ShinyApps

  • Kriteria penilaian:

    1. Teknik scraping
    2. Kompleksitas pengerjaan
    3. (Bonus) Penyajian hasil akhir
  • Projek akan dinilai pada hari Jumat, 16 Juni 2023

Pertanyaan?