Lewati ke konten utama

Scraping Reddit dengan Python dan BeautifulSoup 4

Dalam tutorial ini, Anda akan mempelajari cara mengambil halaman web menggunakan requests, menganalisis halaman web di browser, dan mengekstrak informasi dari HTML mentah dengan BeautifulSoup.
Diperbarui 7 Okt 2026  · 13 mnt Baca

Jelajahi bersama AI

ChatGPTClaudePerplexity

Ilustrasi scraping reddit

Anda dapat menemukan contoh skrip lengkap yang sudah berfungsi di sini.

Apa itu Web Scraping?

Jadi, apa sebenarnya web scraping itu? Sesuai namanya, ini adalah metode untuk ‘mengikis’ atau mengekstrak data dari halaman web. Apa pun yang dapat Anda lihat di internet melalui browser Anda, termasuk tutorial ini, dapat di-scrape ke hard drive lokal Anda.

Ada banyak kegunaan web scraping. Untuk analisis data apa pun, langkah pertama adalah akuisisi data. Internet adalah gudang besar dari seluruh sejarah dan pengetahuan umat manusia, dan Anda memiliki cara untuk mengekstrak apa pun yang Anda inginkan dan memanfaatkan informasi tersebut sesuai kebutuhan.

Dalam tutorial ini, kita akan menggunakan Python dan paket BeautifulSoup 4 untuk mengambil informasi dari sebuah subreddit. Kita tertarik pada subreddit datascience. Kita ingin mengambil 1000 posting pertama di subreddit tersebut dan mengekspornya ke file CSV. Kita ingin tahu siapa yang mempostingnya, serta berapa banyak likes dan komentar yang dimilikinya.

Topik yang akan kita bahas dalam tutorial:

  • Mengambil halaman web menggunakan requests
  • Menganalisis halaman web di browser untuk mendapatkan informasi
  • Mengekstrak informasi dari HTML mentah dengan BeautifulSoup

Catatan: Kita akan menggunakan versi lama situs Reddit karena lebih ringan untuk dimuat, sehingga lebih tidak membebani mesin Anda.

Prasyarat

Tutorial ini mengasumsikan Anda mengetahui hal-hal berikut:

  • Menjalankan skrip Python di komputer Anda
  • Pengetahuan dasar struktur HTML

Anda dapat mempelajari keterampilan di atas dalam kursus Python untuk pemula dari DataCamp. Meski begitu, konsep yang digunakan di sini sangat minimal, dan Anda bisa mengikuti meski hanya dengan sedikit pengetahuan Python.

Sekarang setelah itu beres, kita bisa lanjut ke bagian pertama membuat web scraper. Faktanya, bagian pertama saat menulis skrip Python apa pun: import.

Dalam scraper kita, kita akan menggunakan paket-paket berikut:

  • requests
  • beautifulsoup4

Anda tentu dapat memasang paket-paket ini dengan pip, seperti berikut:

pip install package_name

Setelah selesai mengunduh paket, silakan impor ke dalam kode Anda.

import requests
import csv
import time
from bs4 import BeautifulSoup4

Kita akan menggunakan modul bawaan Python csv untuk menulis hasil ke file CSV. Anda mungkin memperhatikan sesuatu yang agak unik pada cuplikan di atas. Yaitu, kita mengunduh paket bernama beautifulsoup4, tetapi mengimpor dari modul bernama bs4. Ini sah dalam Python, dan meskipun umumnya kurang disukai, ini tidak melanggar aturan apa pun.

Catatan Penting tentang Kebijakan Platform

Sebelum menggunakan teknik scraping yang akan saya tunjukkan di langkah berikutnya, pastikan untuk memeriksa syarat layanan terbaru Reddit atau situs lain mana pun yang Anda rencanakan untuk scrape. Kebijakan situs web dapat berubah seiring waktu. Perjanjian Pengguna Reddit per September 2024 melarang scraping tanpa persetujuan tertulis sebelumnya (lihat bagian 7). Selalu pastikan Anda mematuhi pedoman penggunaan terbaru situs sebelum melanjutkan.

Langkah Pertama untuk Merayapi Reddit

Lingkungan kita sudah siap. Selanjutnya, kita membutuhkan URL untuk halaman web yang ingin kita scrape. Untuk tutorial ini, kita menggunakan subreddit ‘datascience’ di Reddit. Sebelum mulai menulis skrip, ada sedikit pekerjaan awal yang perlu dilakukan. Buka browser web, dan pergi ke subreddit yang dimaksud.

Perhatikan bahwa kita akan menggunakan versi lama subreddit untuk scraper kita. Versi baru menyembunyikan beberapa informasi krusial di balik struktur halaman. Memang memungkinkan mengekstrak informasi ini dari situs baru juga, tetapi demi kesederhanaan, kita akan menggunakan versi lama yang menyajikan semuanya secara terang benderang.

Saat membuka tautan, Anda akan disambut oleh banjir informasi. Apa yang sebenarnya kita butuhkan di semua ini? Setelah menelusuri semua tautan, Anda akan menemukan bahwa posting Reddit ada dua jenis:

  • Inbound
  • Outbound

Tautan inbound adalah tautan yang mengarah ke konten di Reddit itu sendiri, dan outbound adalah kebalikannya. Ini penting karena kita hanya menginginkan tautan inbound. Postingan yang berisi teks yang ditulis pengguna, bukan sekadar tautan ke situs lain.

Jadi, kita tahu apa yang kita inginkan. Bagaimana cara mengekstraknya? Jika Anda melihat judul posting, Anda dapat melihat bahwa judul diikuti oleh teks dalam tanda kurung. Postingan yang kita minati diikuti oleh ‘(self.datascience)’. Secara logis, kita bisa mengasumsikan bahwa ‘self’ mengacu pada direktori root Reddit, dan ‘.datascience’ mengacu pada subreddit.

Bagus, jadi kita punya cara untuk mengidentifikasi mana posting yang inbound dan mana yang outbound. Sekarang kita perlu mengidentifikasikannya di struktur DOM. Bisakah kita menemukan penanda ini di DOM dengan mencari tag, class, atau id di struktur DOM? Tentu saja!

Di browser web Anda, klik kanan pada tautan ‘self.datascience’ mana pun dan klik ‘inspect element’. Sebagian besar browser modern memiliki alat hebat ini yang memungkinkan pengembang web menelusuri bagian bermakna dari kode sumber halaman web secara dinamis. Jika Anda menggunakan Safari, pastikan alat pengembang diaktifkan di preferensi Safari. Anda akan melihat panel yang menggulir ke bagian kode sumber yang bertanggung jawab atas penanda ‘(self.datascience)’ tersebut.

Di panel, Anda dapat melihat bahwa penanda tersebut sebenarnya dimuat oleh tag anchor.

<a href="/r/datascience">self.datascience</a>

Namun ini dibungkus oleh tag span.

<span class="domain">
"("
<a href="/r/datascience">self.datascience</a>
")"
</span>

Tag span inilah yang memuat teks yang kita lihat di halaman, yaitu ‘(self.datascience)’. Seperti yang Anda lihat, ia ditandai dengan class ‘domain’. Anda dapat memeriksa semua tautan lain untuk melihat apakah mereka mengikuti format yang sama, dan memang; sama.

Mengambil Halaman dengan BeautifulSoup

Kita tahu apa yang kita inginkan di halaman, itu bagus, tetapi bagaimana kita menggunakan Python untuk membaca konten halaman? Caranya kurang lebih sama seperti manusia membaca konten halaman melalui browser web.

Pertama, kita perlu meminta halaman web menggunakan library ‘requests’.

url = "https://old.reddit.com/r/datascience"
# Headers to mimic a browser visit
headers = {'User-Agent': 'Mozilla/5.0'}

# Returns a requests.models.Response object
page = requests.get(url, headers=headers)

Sekarang kita memiliki objek Response yang berisi teks mentah halaman web. Sampai saat ini, kita belum bisa melakukan apa pun dengannya. Yang kita punya hanyalah string besar yang berisi seluruh kode sumber file HTML. Untuk memahaminya, kita perlu menggunakan BeautifulSoup 4.

Header akan memungkinkan kita meniru kunjungan browser. Karena respons untuk bot berbeda dengan respons untuk browser, dan acuan kita adalah browser, sebaiknya kita mendapatkan respons versi browser.

BeautifulSoup memungkinkan kita menemukan tag tertentu, dengan mencari kombinasi class, id, atau nama tag apa pun. Ini dilakukan dengan membuat pohon sintaks, tetapi detailnya tidak relevan dengan tujuan kita (dan di luar cakupan tutorial ini).

Jadi mari kita buat pohon sintaks tersebut.

soup = BeautifulSoup(page.text, 'html.parser')

soup hanyalah objek BeautifulSoup yang dibuat dari string kode sumber mentah. Perlu diingat bahwa kita harus menentukan parser html. Ini karena BeautifulSoup juga dapat membuat soup dari XML.

Menemukan Tag Kita

Kita tahu tag apa yang kita inginkan (tag span dengan class ‘domain’), dan kita sudah memiliki soup. Selanjutnya adalah menelusuri soup dan menemukan semua instance dari tag tersebut. Anda mungkin akan tertawa melihat betapa mudahnya ini dengan BeautifulSoup.

domains = soup.find_all("span", class_="domain")

Apa yang baru saja kita lakukan? Kita memanggil metode ‘find_all’ pada objek soup, yang mencari di dalamnya semua tag anchor dengan parameter yang diteruskan sebagai argumen kedua. Kita hanya meneruskan satu pembatas (class harus ‘domain’), tetapi kita bisa menggabungkannya dengan banyak hal lain, atau bahkan hanya menggunakan id.

Kita menggunakan ‘class_=‘ karena 'class' adalah kata kunci yang dicadangkan oleh Python untuk mendefinisikan class dan sejenisnya

Jika Anda ingin meneruskan lebih dari satu parameter, yang perlu Anda lakukan hanyalah menjadikan parameter kedua sebagai dictionary dari argumen yang ingin Anda sertakan, seperti ini:

soup.find_all("span", {"class": "domain", "height", "100px"})

Kita memiliki semua tag span dalam daftar ‘domains’, tetapi yang kita inginkan adalah domain ‘(self.datascience)’.

for domain in domains:
    if domain != "(self.datascience)":
        continue

    print(domain.text)

Sekarang Anda seharusnya melihat daftar tipe posting di halaman dengan mengecualikan yang bukan ‘(self.datascience)’. Pada dasarnya, kita sudah memiliki semua yang kita butuhkan. Kita kini memiliki referensi ke semua posting yang inbound.

Menemukan Informasi Kita

Mencetak beberapa baris ‘(self.datascience)’ memang bagus, tetapi selanjutnya apa? Ingat kembali tujuan awal kita. Mengambil judul posting, penulis, likes, dan jumlah komentar.

Untuk ini, kita harus kembali ke browser. Jika Anda membuka inspector pada penanda kita lagi, Anda akan melihat tag span kita berada di dalam tag div … Yang juga berada di dalam tag div lain, dan seterusnya. Terus naik, dan Anda akan sampai pada div induk untuk keseluruhan posting.

<div class=" thing id-t3_8qccuv even  link self" ...>
    ...
    <div class="entry unvoted">
        <div class="top-matter">
            <p class="title">
                ...
                <span class="domain">
                ...
            </p>
        </div>
    </div>
</div>

Seperti yang Anda lihat, induk bersama berada 4 level di atasnya dalam struktur DOM. Elipsis (…) mewakili bagian yang tidak perlu. Tetapi yang kita butuhkan kini adalah referensi ke div posting untuk setiap posting dalam daftar domains kita. Kita dapat menemukan induk dari elemen apa pun dalam soup menggunakan metode BeautifulSoup.

for domain in soup.find_all("span", class_="domain"):
    if domain != "(self.datascience)":
        continue

    parent_div = domain.parent.parent.parent.parent
    print(parent_div.text)

Menjalankan skrip akan mencetak semua teks dari semua posting inbound. Namun Anda mungkin berpikir bahwa kode ini terlihat buruk. Anda benar. Tidak pernah aman untuk hanya mengandalkan integritas struktural DOM. Ini semacam solusi tambal-sulam yang butuh pembaruan konstan dan setara dengan bom waktu dalam kode.

Sebagai gantinya, mari kita lihat div induk untuk setiap posting dan lihat apakah kita dapat memisahkan tautan inbound dan outbound dari induknya. Setiap div induk memiliki atribut bernama ‘data-domain’, yang nilainya persis yang kita inginkan! Semua posting inbound memiliki data-domain yang disetel ke ‘self.datascience’.

Seperti telah disebutkan sebelumnya, kita dapat mencari tag dengan kombinasi atribut menggunakan BeautifulSoup. Beruntung bagi kita, Reddit memberi class ‘thing’ pada div induk tiap posting.

attrs = {'class': 'thing', 'data-domain': 'self.datascience'}

for post in soup.find_all('div', attrs=attrs):
    print(post.attrs['data-domain'])

Variabel ‘attrs’ adalah dictionary yang berisi atribut yang ingin kita cari beserta nilainya. Ini adalah pendekatan yang jauh lebih aman untuk menemukan posting karena melibatkan lebih sedikit bagian yang bergerak. Karena kita sudah menambahkan ‘self.datascience’ sebagai argumen saat mencari, kita tidak perlu menggunakan pernyataan if untuk melewati iterasi apa pun karena kita dijamin hanya menerima posting dengan atribut data-domain ‘self.datascience’.

Sekarang setelah kita memiliki semua informasi yang kita inginkan, yang tersisa hanyalah mengekstrak informasi dari anak-anaknya. Yang ternyata sesederhana yang Anda bayangkan.

Mengekstrak Informasi Kita dari Reddit

Untuk setiap posting, kita membutuhkan 4 potong informasi.

  • Judul
  • Penulis
  • Likes
  • Komentar

Jika kita melihat struktur div posting, kita dapat menemukan semua informasi ini.

Judul

Ini yang paling sederhana. Dalam setiap div posting, ada tag paragraf yang berada di bawah beberapa lapis div. Ini sangat mudah ditemukan karena memiliki class ‘title’.

title = post.find('p', class_="title").text

Objek post berada dalam for loop kita sebelumnya. Ini juga objek BeautifulSoup, tetapi hanya berisi struktur DOM dalam div posting. Metode ‘find’ hanya mengembalikan satu objek, berbeda dengan 'find_all' yang mengembalikan daftar objek yang memenuhi kriteria. Setelah menemukan tag, kita hanya menginginkan string yang berisi judul, jadi kita gunakan properti text untuk membacanya. Kita juga dapat membaca atribut lain dengan menggunakan ‘object.attrs[‘attribute’]’.

Penulis

Ini juga relatif sederhana, buka inspector pada nama penulis mana pun di bawah judul posting. Anda akan melihat bahwa nama penulis berada dalam tag anchor dengan class ‘author’.

author = post.find('a', class_='author').text

Komentar

Yang ini butuh sedikit kerja ekstra tetapi tetap sederhana. Kita dapat menemukan komentar dengan cara yang sama seperti kita menemukan judul dan penulis.

comments = post.find('a', class_='comments').text

Ketika Anda menjalankannya, Anda akan mendapatkan sesuatu seperti “49 comments”. Ini baik, tetapi akan lebih baik jika kita hanya mendapatkan angkanya. Untuk melakukan ini, kita perlu menggunakan sedikit Python lagi.

Jika kita menggunakan fungsi Python ‘str.split()’, fungsi ini akan mengembalikan array semua elemen dalam string yang dipisahkan oleh spasi. Dalam kasus kita, kita akan mendapatkan daftar ‘[“49", “comments”]’. Bagus! Sekarang, yang perlu kita lakukan hanyalah mengambil elemen pertama dan menyimpannya. Kita tinggal menambahkan fungsi tersebut ke baris kita.

comments = post.find('a', class_='comments').text.split()[0]

Tapi kita masih belum selesai karena terkadang, kita tidak mendapatkan angka. Kita mendapatkan ‘comment’. Ini terjadi ketika tidak ada komentar pada sebuah posting. Karena kita tahu ini, yang perlu kita lakukan adalah memeriksa apakah hasilnya ‘comments’ dan menggantinya dengan ‘0’.

if comments == "comment":
    comments = 0

Likes

Menemukan jumlah likes sangat mudah, dan sejalan dengan logika yang kita gunakan di atas.

likes = post.find("div", attrs={"class": "score likes"}).text

Di sini Anda mungkin memperhatikan bahwa kita menggunakan kombinasi dua class. Ini karena ada beberapa div lain dengan class ‘score’ atau ‘likes’, tetapi hanya satu dengan kombinasi ‘score’ dan ‘likes’.

Jika jumlah likes adalah 0, kita mendapatkan 0. Tetapi sesuatu yang aneh terjadi jika posting masih sangat baru sehingga belum memiliki likes. Kita mendapatkan “•”. Mari kita ganti ini dengan “None” agar tidak menimbulkan kebingungan dalam hasil akhir.

if likes == "•":
    likes = "None"

Sejauh ini, kita memiliki loop yang mengekstrak judul, penulis, likes, dan komentar untuk setiap posting di halaman web. Python memiliki modul bawaan yang bagus untuk menulis dan membaca file CSV bernama ‘csv’, mengikuti filosofi Python: tetap sederhana. Yang perlu kita lakukan hanyalah menambahkan satu baris di akhir blok loop yang menambahkan detail posting ke file CSV.

counter = 1
for post in posts:
    ...
    post_line = [counter, title, author, likes, comments]
    with open('output.csv', 'a') as f:
        writer = csv.writer(f)
        writer.writerow(post_line)

    counter += 1

Cukup lugas, bukan? post_line digunakan untuk membuat array yang menyimpan elemen-elemen yang perlu dipisahkan dengan koma. Variabel counter digunakan untuk melacak berapa banyak posting yang telah kita catat.

Berpindah ke Halaman Berikutnya

Karena kita menghitung jumlah posting yang kita simpan, yang perlu kita lakukan hanyalah membungkus seluruh logika kita dalam loop lain yang meminta halaman baru hingga sejumlah posting tercatat.

counter = 1

while (counter <= 100):
    for post in posts:
        # Getting the title, author, ...
        # Writing to CSV and incrementing counter...

    next_button = soup.find("span", class_="next-button")
    next_page_link = next_button.find("a").attrs['href']
    time.sleep(2)
    page = requests.get(next_page_link, headers=headers)
    soup = BeautifulSoup(page.text, 'html.parser')

Kita baru saja melakukan beberapa hal, bukan? Mari lihat satu per satu. Pertama, kita memindahkan variabel counter ke atas satu blok, sehingga while loop dapat menggunakannya.

Selanjutnya, kita tahu apa yang dilakukan for loop, tetapi bagaimana dengan yang lain. Variabel ‘next_button' digunakan untuk menemukan dan menyimpan tombol 'next'. Setelah itu, kita dapat menemukan tag anchor di dalamnya dan mengambil atribut 'href'; yang kita simpan di 'next_page_link’.

Kita dapat menggunakan tautan ini untuk meminta halaman berikutnya dan menyimpannya kembali ke ‘page’ serta membuat soup baru dengan BeautifulSoup.

Cuplikan di atas berhenti setelah 100, tetapi Anda dapat menghentikannya setelah jumlah posting berapa pun yang Anda inginkan.

Scraping secara Bertanggung Jawab

Baris yang belum kita bahas di atas adalah ‘time.sleep(2)’. Itu karena baris tersebut pantas memiliki bagiannya sendiri. Server web mana pun memiliki sumber daya yang terbatas, jadi terserah kita untuk memastikan kita tidak menghabiskannya. Tidak hanya bisa membuat Anda diblokir jika meminta ratusan halaman dalam hitungan detik, tetapi itu juga tidak sopan.

Penting untuk diingat bahwa cukup baik hati sebuah situs web masih mengizinkan Anda melakukan scraping karena jika mereka mau, mereka bisa mendeteksi bot dalam 10 hingga 20 permintaan pertama, atau bahkan menangkap Anda berdasarkan objek permintaan yang dikirim Python. Cukup baik hati mereka mengizinkan Anda melakukan scraping tanpa perlu merotasi IP, jadi Anda sebaiknya membalasnya dengan memperlambat bot Anda.

Anda dapat menemukan kebijakan perayapan sebuah situs web dengan melihat file robots.txt mereka. Ini biasanya ditemukan di root situs web (mis. http://www.reddit.com/robots.txt).

Selanjutnya Apa?

Ya, apa pun yang Anda inginkan. Seperti yang baru saja kita buktikan, apa pun yang bisa Anda lihat di web dapat di-scrape dan disimpan secara lokal. Anda dapat menggunakan informasi yang baru saja kita peroleh untuk berbagai tujuan. Hanya dengan empat potong informasi yang kita temukan, kita bisa menarik banyak kesimpulan.

Dengan menganalisis informasi kita lebih lanjut, kita dapat mengetahui jenis posting Reddit mana yang menerima paling banyak likes, kata apa yang dikandungnya, siapa yang mempostingnya. Atau sebaliknya, kita dapat membuat kalkulator kontroversi dengan menganalisis rasio likes terhadap komentar.

Pertimbangkan sebuah posting yang menerima banyak komentar tetapi tidak ada likes. Ini kemungkinan besar berarti posting tersebut memuat sesuatu yang menggugah orang, tetapi tidak serta-merta sesuatu yang mereka sukai.

Ada banyak kemungkinan, dan terserah Anda untuk memilih bagaimana Anda akan menggunakan informasi tersebut.

Jika Anda menyukai tutorial ini, pastikan untuk melihat panduan kami tentang scraping Amazon dengan python, serta kumpulan kursus python kami.

Topik
Python

Pelajari lebih lanjut tentang Python

Kursus

Pengantar Python

4 jam
7.1M
Kuasai dasar-dasar analisis data dengan Python dalam 4 jam. Kursus online ini memperkenalkan antarmuka Python dan pustaka populer.
Lihat DetailRight Arrow
Mulai Kursus
Lihat SelengkapnyaRight Arrow
Terkait

blogs

Tutorial Korelasi di R

Dapatkan pengenalan dasar-dasar korelasi di R: pelajari lebih lanjut tentang koefisien korelasi, matriks korelasi, plotting korelasi, dan sebagainya.
David Woods's photo

David Woods

13 mnt

blogs

Spaghetti Plot dan Jalur Badai

Temukan alasan mengapa Anda sebaiknya (tidak) menggunakan spaghetti plot untuk menyampaikan ketidakpastian jalur prediksi badai serta dampaknya terhadap interpretasi.
Hugo Bowne-Anderson's photo

Hugo Bowne-Anderson

13 mnt

blogs

40 Pertanyaan Wawancara DBMS Teratas di 2026

Kuasai pertanyaan wawancara basis data, dari konsep SQL dasar hingga skenario desain sistem tingkat lanjut. Panduan mendalam ini mencakup semua yang Anda perlukan untuk sukses di wawancara DBMS dan meraih peran berikutnya.
Dario Radečić's photo

Dario Radečić

15 mnt

blogs

12 Alternatif ChatGPT Terbaik yang Bisa Anda Coba pada 2026

Artikel ini menyajikan daftar alternatif ChatGPT yang akan meningkatkan produktivitas Anda.
Javier Canales Luna's photo

Javier Canales Luna

14 mnt

Lihat SelengkapnyaLihat Selengkapnya