Geonode logo
Geonode Team

Geonode Team

Dikemas kini: 7 Oktober 2026

Diterbitkan: 2 September 2026

XPath vs Selektor CSS: Panduan dengan Contoh

Selektor CSS lebih ringkas dan lebih mudah dibaca. XPath lebih mumpuni. Ringkasan tersebut akurat namun tidak berguna jika dilihat secara terpisah, karena selisih kemampuan kini lebih tipis daripada sebelumnya, sedangkan selisih keterbacaan tidak. Yang penting adalah hal-hal spesifik apa saja yang tidak dapat dilakukan oleh masing-masing, dan hanya ada sekitar empat hal di setiap sisi. Panduan ini berisi daftar tersebut, ditambah bagaimana kemunculan `:has()` mengubah perhitungan dan apa yang tidak berubah.

Kepentingan kami di sini memang kecil, tapi tetap layak disebutkan: kami adalah Geonode dan kami menjual proxy kepada orang-orang yang melakukan pekerjaan ekstraksi data, sehingga topik selektor sering muncul dalam percakapan dukungan. Hal yang perlu disampaikan sebelum perbandingan ini adalah bahwa kedua pilihan tersebut tidak memengaruhi apakah Anda akan diblokir atau tidak. Pertanyaan tentang selektor dan pertanyaan tentang jaringan terlihat sama dari kejauhan — keduanya menghasilkan keluhan "scraper saya berhenti mengembalikan data" — namun keduanya tidak memiliki kesamaan sama sekali. Jika halaman tiba tanpa kerusakan dan ekspresi Anda tidak cocok dengan apa pun, ini adalah masalah selektor dan tidak ada keputusan infrastruktur yang dapat mengatasinya.

Ringkasan

CSSXPath
Memilih berdasarkan kelas, id, atributYa, dengan rapiYa, agak rumit
Hubungan keturunan dan anakYaYa
Memilih berdasarkan isi teksTidakYa
Menavigasi ke induk atau leluhurSebagian, melalui :has()Ya, langsung
Menavigasi ke saudara sebelumnyaSebagian, melalui :has()Ya, langsung
Pemilihan berdasarkan posisiKeluarga ":nth-child()""position()", "last()", predikat
Fungsi stringTidakYa
Kueri XML dengan namespaceTidakYa
KeterbacaanLebih baikLebih buruk
Dukungan alat dan browserUniversalUniversal untuk versi 1.0

Dua baris ini memegang peranan paling penting. CSS sama sekali tidak dapat melakukan seleksi berdasarkan konten teks, sehingga tidak dapat digunakan untuk pola ekstraksi yang paling umum — menemukan nilai berdasarkan label di sebelahnya. Dan XPath lebih sulit dibaca, yang lebih penting daripada yang diakui orang ketika seorang rekan kerja harus memelihara kode Anda setahun kemudian.

Keunggulan CSS

Pemilihan kelas dan atribut, dan perbedaannya sangat jauh.

div.product-card
a[href^="https://"]
input[type="checkbox"]:checked
ul > li:first-child
section.content p:not(.footnote)

Ekivalen XPath-nya lebih panjang dan, untuk kelas, benar-benar merepotkan:

//div[contains(concat(' ', normalize-space(@class), ' '), ' product-card ')]
//a[starts-with(@href, 'https://')]
//ul/li[1]

Yang pertama itu adalah idiom pencocokan kelas, dan hal ini ada karena @class

merupakan string tunggal yang dipisahkan spasi, sedangkan XPath tidak mengenal konsep token di dalamnya. contains(@class, 'product-card')

yang sederhana juga akan mencocokkan product-card-large

dan old-product-card

, sehingga versi yang diisi spasi adalah yang benar. Panjangnya juga empat kali lipat dari div.product-card

dan jauh lebih sulit untuk dipindai.

Jika kriteria pemilihan Anda adalah kelas, ID, atribut, dan hubungan struktural, gunakan CSS. Hal ini mencakup sebagian besar pekerjaan pemilihan yang sebenarnya, dan memilih XPath untuk hal tersebut berarti mengorbankan keterbacaan demi kemampuan yang tidak Anda gunakan.

CSS juga memiliki dukungan alat yang lebih baik. Inspektor elemen di setiap browser menghasilkan selektor CSS secara bawaan, sebagian besar kerangka kerja pengujian menggunakannya secara default, dan document.querySelectorAll

tersedia di mana-mana tanpa perlu alat bantu.

Keunggulan XPath

Pencocokan teks, yang sama sekali tidak dapat dilakukan oleh CSS:

//button[normalize-space()='Continue']
//a[contains(., 'Download')]
//dt[normalize-space()='Price']/following-sibling::dd[1]

Pola terakhir itu — temukan label, ambil nilai yang berdekatan — merupakan tulang punggung ekstraksi halaman terstruktur, dan tidak ada ekspresi CSS untuk hal tersebut karena CSS tidak memiliki akses ke konten teks. Kemampuan tunggal inilah yang menjadi alasan mengapa XPath tetap digunakan dalam penggalian basis kode yang sebaliknya sepenuhnya menggunakan CSS.

Navigasi leluhur:

//span[@class='price']/ancestor::div[contains(@class,'card')][1]

Menelusuri ke atas dari suatu nilai menuju wadah yang menampungnya. :has()

memberikan CSS bentuk dari kemampuan ini, dengan batasan-batasan yang dibahas di bawah ini.

Logika posisi relatif terhadap konten:

//h2[normalize-space()='Specifications']/following-sibling::table[1]

Tabel pertama setelah judul tertentu. :nth-child()

menghitung posisi di antara elemen-elemen sekelompok; ia tidak dapat mengekspresikan "setelah elemen yang teksnya adalah X".

Fungsi string. normalize-space()

, substring-before()

, translate()

, dan yang lainnya memungkinkan Anda melakukan pemrosesan di dalam ekspresi. normalize-space()

khususnya hampir menjadi keharusan, karena HTML asli ditata rapi dan perbandingan teks yang tepat terhadap "\n In stock\n"

akan gagal.

XML dengan namespace. Jika Anda melakukan kueri terhadap XML alih-alih HTML — seperti peta situs, umpan RSS, atau respons SOAP — CSS bukanlah alat yang tepat. XPath dirancang untuk tujuan tersebut, dan penanganan namespace merupakan bagian dari desainnya.

Bagaimana :has() Mengubah Segalanya

Perkembangan paling signifikan dalam perbandingan ini, dan banyak artikel yang diterbitkan sebelum itu.

Dokumentasi MDN menjelaskan bahwa :has() mewakili "sebuah elemen jika salah satu selektor relatif yang diberikan sebagai argumen cocok dengan setidaknya satu elemen saat diikat terhadap elemen ini", sehingga menyediakan "cara untuk memilih elemen induk atau elemen saudara sebelumnya relatif terhadap elemen referensi". Status dasarnya adalah "tersedia secara luas", didukung di berbagai peramban sejak Desember 2023.

Jadi, CSS kini dapat mengekspresikan hal-hal yang sebelumnya tidak dapat dilakukan:

div.card:has(span.sold-out)        /* a card containing a sold-out marker */
h1:has(+ p)                        /* an h1 immediately followed by a p */
li:has(~ li.active)                /* an li with a later active sibling */
tr:has(td.error)                   /* a row containing an error cell */

Hal ini mencakup sebagian besar kebutuhan yang sebelumnya memerlukan XPath — pemilihan elemen induk, dan pengkondisian berdasarkan elemen saudara.

Terdapat tiga batasan yang didokumentasikan dan perlu diketahui. :has() "tidak dapat disarangkan di dalam :has() lainnya". Pseudo-elemen "bukanlah selektor yang valid di dalam :has()" dan bukan jangkar yang valid untuknya. Selain itu, spesifisitasnya adalah "spesifisitas selektor paling spesifik di antara argumen-argumennya", sesuai dengan cara kerja :is() dan :not().

Batasan yang paling penting untuk ekstraksi tidak tercantum dalam daftar tersebut: :has() masih tidak dapat mencocokkan teks. div:has(span) berfungsi; div:has(span:contains('Price')) tidak ada, karena :contains() bukanlah selektor CSS standar. Selektor tersebut pernah diusulkan namun kemudian dibatalkan, dan browser tidak mengimplementasikannya. Jadi, pola label-nilai tetap menjadi wilayah XPath terlepas dari :has().

Terjemahan Berdampingan

Cara tercepat untuk memahami pertimbangannya adalah dengan melihat maksud yang sama diekspresikan dalam kedua cara tersebut.

MaksudCSSXPath
Elemen dengan kelasdiv.card//div[contains(concat(' ',normalize-space(@class),' '),' card ')]
Elemen dengan id#main//*[@id='main']
Atribut adaa[href]//a[@href]
Atribut dimulai dengana[href^="/docs"]//a[starts-with(@href,'/docs')]
Atribut berisia[href*="pdf"]//a[contains(@href,'pdf')]
Anak langsungul > li//ul/li
Keturunan apa pundiv p//div//p
Anak pertamali:first-child//li[1]
Anak terakhirli:last-child//li[last()]
Anak ke-nli:nth-child(3)//li[3]
Saudara berikutnyah2 + p//h2/following-sibling::p[1]
Saudara mana pun yang lebih mudah2 ~ p//h2/following-sibling::p
Negasip:not(.footnote)//p[not(contains(@class,'footnote'))]
Orang tua dari hasil pencocokandiv:has(> span.price)//span[contains(@class,'price')]/..
Mengandung tekstidak mungkin//p[contains(., 'Price')]
Teks persistidak mungkin//p[normalize-space()='Price']
Nilai di samping labeltidak mungkin//dt[normalize-space()='Price']/following-sibling::dd[1]

Jika kita membaca tabel tersebut dari atas ke bawah, polanya jelas. Untuk semua baris di atas baris induk, CSS lebih singkat dan lebih jelas, dan memilih XPath berarti memilih kerumitan tanpa keuntungan apa pun. Untuk tiga baris di bagian bawah, kolom CSS sama sekali tidak ada.

Dua terjemahan layak ditinjau kembali. Baris kelas menunjukkan kontras paling mencolok dalam perbandingan ini — sembilan karakter berbanding tujuh puluh-an — dan versi XPath tidak sekadar membengkakkan kode, karena bentuk singkat contains(@class,'card') benar-benar lebih tepat daripada card-large dan discard. Dan baris “anak pertama” menyembunyikan jebakan: li:first-child dan //li[1] sama di sini, tetapi //li[1] adalah predikat yang diterapkan per induk, sehingga memilih li pertama di bawah setiap daftar dalam dokumen. CSS-nya tidak ambigu; XPath memerlukan (//li)[1] jika Anda bermaksud hanya satu.

Contoh Campuran yang Realistis

Begini tampilannya dalam praktiknya, saat mengekstrak halaman produk.

# CSS for the structural work — clear and adequate
cards = tree.cssselect('div.product-grid > article.product-card')

for card in cards:
    name  = card.cssselect('h3.product-name')[0].text_content().strip()
    image = card.cssselect('img.product-image')[0].get('src')

    # XPath for the label-value pairs, which CSS cannot express
    price = card.xpath(
        ".//dt[normalize-space()='Price']/following-sibling::dd[1]"
    )[0].text_content().strip()

    stock = card.xpath(
        ".//span[contains(., 'in stock') or contains(., 'out of stock')]"
    )

Ada tiga hal di sana yang patut ditiru.

Penggunaan . di awal setiap ekspresi XPath. .//dt mencari di dalam kartu saat ini; //dt akan mencari seluruh dokumen mulai dari akar, mengembalikan label pertama yang cocok di halaman untuk setiap kartu. Ini adalah salah satu bug paling umum dalam kode ekstraksi campuran, dan menghasilkan nilai yang sama untuk setiap catatan — masuk akal, seragam, dan salah.

Gunakan CSS jika CSS sudah cukup. Pemilihan grid dan kartu, judul, serta gambar. Menulisnya dalam XPath akan menambah panjang kode dan mengurangi kejelasan.

Gunakan XPath hanya jika diperlukan. Harga diidentifikasi berdasarkan labelnya, dan status stok berdasarkan teksnya. Keduanya tidak dapat diekspresikan dalam CSS, dan keduanya adalah alasan mengapa XPath ada dalam berkas tersebut.

Hasilnya adalah scraper di mana setiap ekspresi sesingkat mungkin, dan pembaca dapat melihat sekilas bagian mana yang bergantung pada struktur dan bagian mana yang bergantung pada konten — yang juga merupakan peta bagian mana yang akan rusak ketika situs berubah.

Kinerja

Biasanya tidak relevan, terkadang menentukan.

CSS umumnya lebih cepat di peramban, karena mesin peramban mengoptimalkan proses pencocokan selektor secara intensif — hal ini berada di jalur kritis proses rendering. XPath menggunakan model evaluasi yang lebih umum.

Perbedaan ini jarang berpengaruh pada skala yang biasa digunakan kebanyakan orang. Memilih elemen dari satu halaman beberapa ratus kali tidak akan terasa perbedaannya; permintaan jaringan jauh lebih dominan.

Di mana hal ini berpengaruh:

Aksis preceding dan following benar-benar memakan sumber daya. Keduanya memindai seluruh dokumen sebelum atau setelah node konteks. Di dalam loop yang mencakup banyak node, hal ini menjadi kuadratik. Jika ekspresi XPath terasa sangat lambat, periksa apakah ekspresi tersebut menggunakan salah satu dari keduanya — preceding-sibling dan following-sibling dibatasi oleh jumlah saudara dan tidak menjadi masalah.

// di awal ekspresi bersarang akan melakukan pencarian ulang dari akar. //div//span lebih mahal daripada yang terlihat, dan .//span di dalam loop yang menjelajahi elemen div biasanya adalah yang Anda maksud.

:has() dapat memakan sumber daya pada dokumen besar, karena mesin harus mengevaluasi selektor dalam untuk setiap kandidat. Cocok untuk ekstraksi; hal ini perlu diperhatikan dalam lembar gaya yang diterapkan pada halaman besar.

Untuk penguraian di sisi server dengan lxml atau sejenisnya, perbedaannya cukup kecil sehingga keterbacaan seharusnya menjadi pertimbangan utama.

Masalah Ketersediaan dan Versi

Masalah yang menyebabkan situasi "berfungsi di penguji daring, tapi tidak di kode saya".

Browser mengimplementasikan XPath 1.0 melalui document.evaluate, dan Selenium menggunakan mesin browser tersebut. Fitur-fitur XPath 2.0 dan 3.1 — matches(), replace(), lower-case(), ends-with(), urutan — tidak tersedia di sana. Potongan kode yang menggunakan salah satu fitur tersebut akan gagal.

lxml mengimplementasikan XPath 1.0 untuk antarmuka pemrogramannya yang umum, ditambah ekstensi EXSLT termasuk re:test() untuk ekspresi reguler. Jadi, ekspresi berbasis regex yang berfungsi di Python tidak akan berfungsi di Selenium.

Dukungan CSS di pustaka pengurai biasanya melalui lapisan terjemahan yang secara internal mengubah CSS menjadi XPath. Hal ini berfungsi dengan baik untuk selektor umum, namun kurang baik untuk selektor yang lebih baru — dukungan :has() di pengurai sisi server sangat bervariasi, dan selektor yang berfungsi di browser mungkin tidak berfungsi di scraper Anda.

Aturan praktis: uji selektor Anda di lingkungan yang akan menjalankannya, bukan di konsol browser atau alat daring. Dua kejutan paling umum adalah fungsi XPath 2.0 yang gagal di Selenium, dan :has() yang gagal di parser Python.

Memilih dalam Praktik

Prosedur pengambilan keputusan yang dapat menyelesaikan hampir semua kasus.

Mulailah dengan CSS. CSS lebih mudah dibaca, didukung oleh alat yang lebih baik, dan memadai untuk pemilihan berdasarkan kelas, id, atribut, serta struktur — yang mencakup sebagian besar kasus pemilihan.

Beralihlah ke XPath saat Anda perlu mencocokkan teks. Inilah alasan utamanya dan sangat menentukan: tidak ada konstruksi CSS yang membaca konten teks.

Beralihlah ke XPath untuk navigasi leluhur di luar cakupan :has(), terutama saat Anda memerlukan leluhur tertentu beberapa tingkat di atas daripada pencocokan bersyarat pada induk yang diketahui.

Beralihlah ke XPath untuk XML. Ruang nama dan operasi urutan dokumen adalah tujuan utama pembuatannya.

Gunakan keduanya dalam satu basis kode. Ini adalah hal yang wajar dan masuk akal, bukan sekadar kompromi. Sebuah scraper yang menggunakan CSS untuk 90% kasus yang sederhana dan XPath untuk 10% kasus yang sulit lebih mudah dipelihara daripada yang hanya mengandalkan salah satunya.

Dan kebiasaan yang lebih berharga daripada kedua pilihan tersebut: periksa apakah ada data terstruktur yang tertanam sebelum menulis selektor sama sekali. Banyak halaman menyertakan JSON-LD dalam blok <script type="application/ld+json"> karena hal itu mendukung fitur pencarian, dan mengurai data tersebut jauh lebih stabil daripada mengurai markup yang telah dirender. Data tersebut tetap berfungsi meskipun terjadi perombakan desain yang merusak semua selektor di halaman tersebut.

Apa yang Tidak Dapat Dipecahkan oleh Keduanya

Keduanya sama-sama rentan, dan inilah bagian yang menghabiskan waktu nyata.

Selektor struktural bisa gagal tanpa peringatan. Seseorang menambahkan kolom, dan td[3] malah mencocokkan sel yang berbeda. Tidak ada kesalahan yang muncul; data Anda diam-diam menjadi salah. Gunakan teks atau pengenal sebagai acuan jika memungkinkan, dan pastikan bentuk data yang Anda ekstrak — jika harga seharusnya terlihat seperti harga, periksa kembali.

Keduanya tidak menangani konten yang dirender oleh klien. Jika markup disusun oleh JavaScript setelah dimuat, keduanya tidak menemukan apa pun dalam HTML awal. Itu adalah masalah pengambilan data yang memerlukan browser atau API yang mendasarinya, bukan masalah selektor.

Keduanya tidak dapat bertahan sendiri saat terjadi perombakan desain. Solusinya adalah menyimpan selektor di satu tempat, sehingga pembaruan setelah perubahan hanya memakan waktu satu jam, bukan satu hari, serta menyimpan HTML yang telah Anda parsing agar dapat membandingkan versi lama dengan yang baru saat terjadi kesalahan.

Dan keduanya tidak terpengaruh oleh cara halaman tersebut diambil. Di sinilah kita masuk: jika dokumen utuh dan ekspresi Anda tidak cocok dengan apa pun, tidak ada perubahan infrastruktur apa pun yang akan mengubah hasilnya.

Pertanyaan Lainnya

Apakah XPath lebih baik daripada selektor CSS?

Secara umum, keduanya sama-sama baik. XPath memiliki kemampuan yang lebih luas — dapat mencocokkan teks, menelusuri elemen induk, dan menggunakan fungsi string. CSS lebih mudah dibaca dan didukung dengan lebih baik oleh berbagai alat bantu. Gunakan CSS sebagai pilihan default, dan gunakan XPath untuk hal-hal spesifik yang tidak dapat diekspresikan oleh CSS.

Apakah selektor CSS dapat memilih berdasarkan teks?

Tidak. Tidak ada selektor CSS standar untuk konten teks — :contains() pernah diusulkan namun tidak pernah diadopsi, dan browser tidak mengimplementasikannya. Inilah kesenjangan kemampuan terbesar dan alasan utama mengapa XPath tetap digunakan dalam pekerjaan ekstraksi.

Apakah :has() menggantikan XPath?

Sebagian. Fitur ini menyediakan seleksi orang tua dalam CSS dan pencocokan bersyarat antar-saudara, yang sebelumnya hanya tersedia di XPath. Fitur ini tidak menambahkan pencocokan teks, sehingga pola label-nilai masih memerlukan XPath. Selain itu, fitur ini tidak dapat disarangkan, dan dukungannya di perpustakaan parsing sisi server bervariasi.

Mana yang lebih cepat, XPath atau CSS?

CSS umumnya lebih cepat di peramban karena pencocokan selektor dioptimalkan untuk rendering. Perbedaannya biasanya tidak signifikan dibandingkan dengan waktu jaringan. Bagian di mana XPath benar-benar menjadi lambat adalah sumbu preceding dan following, yang memindai seluruh dokumen.

Bisakah saya menggunakan XPath 2.0 di Selenium?

Tidak. Peramban mengimplementasikan XPath 1.0 melalui document.evaluate, dan Selenium menggunakan mesin peramban tersebut. Fungsi seperti matches(), lower-case(), dan ends-with() tidak tersedia. Inilah alasan umum mengapa potongan kode (snippet) berfungsi di penguji daring (online tester) tetapi gagal di rangkaian pengujian (test suite).

Bagaimana cara memilih elemen induk?

Dalam XPath, gunakan parent:: atau ... Dalam CSS, :has() menyediakan bentuk bersyarat — div:has(> span.price) memilih elemen div, bukan span. Untuk memilih leluhur spesifik beberapa tingkat di atas, sumbu ancestor:: dalam XPath lebih langsung.

Haruskah saya menggunakan CSS atau XPath untuk web scraping?

Keduanya, dalam basis kode yang sama. Gunakan CSS untuk pemilihan kelas, id, dan atribut, yang mencakup sebagian besar kasus. Gunakan XPath saat Anda perlu mencocokkan teks — menemukan nilai berdasarkan labelnya adalah kasus klasik dan tidak memiliki padanan dalam CSS.

Mana yang lebih stabil saat situs berubah?

Secara inheren, tidak ada yang lebih stabil — stabilitas bergantung pada apa yang Anda jadikan acuan, bukan bahasa pemrograman yang Anda gunakan. Mengacu pada teks atau atribut data-* akan tetap berfungsi setelah perombakan desain; mengacu pada posisi tidak akan bertahan sama sekali. Kedua bahasa tersebut memungkinkan Anda melakukan keduanya.

Kesimpulan

Perbandingan ini pada dasarnya menyempit menjadi dua perbedaan mendasar. CSS tidak dapat “membaca” teks, sedangkan XPath lebih sulit dibaca. Selebihnya hanyalah detail.

Hal itu membuat aturan kerjanya menjadi sederhana: gunakan CSS sebagai default, karena sebagian besar pemilihan dilakukan berdasarkan kelas, id, atau atribut, dan CSS mengekspresikannya dengan rapi. Gunakan XPath pada titik spesifik di mana Anda membutuhkan sesuatu yang hanya ditawarkan olehnya — terutama pencocokan teks, kemudian navigasi leluhur, dan fungsi string. Menggabungkan keduanya adalah hal yang wajar, dan basis kode yang memanfaatkan masing-masing sesuai keunggulannya lebih mudah dipelihara daripada yang hanya memilih salah satu.

:has() benar-benar telah mempersempit kesenjangan dan layak diterapkan di tempat yang sesuai: pemilihan orang tua dan kondisi saudara dalam CSS biasa, yang telah tersedia secara luas sejak akhir 2023. Perlu dicatat bahwa fitur ini tidak menangani teks, dan dukungan parser sisi server untuknya kurang seragam dibandingkan dukungan browser.

Kemudian, periksa lingkungan Anda sebelum mempercayai ekspresi apa pun. XPath 1.0 di peramban dan Selenium, fitur tambahan EXSLT di lxml, dukungan variabel :has() di pustaka pengurai — kejutan selektor yang paling umum bukanlah kesalahan sintaksis, melainkan fitur yang ada di tempat lain selain tempat Anda menjalankannya.