DataLens

Memilih elemen (selector, get_by_role / get_by_text)

Temukan tepat elemen yang kamu inginkan dengan CSS selector dan locator berorientasi pengguna milik Playwright, persempit dengan filter, dan pahami strict mode.

Level: Dasar · 9 menit baca

Latihan modul ini

Soal-soal untuk pelajaran ini berjalan di browser-mu dan langsung mengecek jawabanmu.

Idenya

Setiap scraper pada intinya terdiri dari dua langkah: temukan elemen, lalu baca elemen itu. Menemukan adalah bagian yang rapuh: kalau selector-mu rusak saat situsnya mengganti sebuah class CSS, scraper-nya ikut rusak. Playwright memberimu dua jenis locator:

Locator itu resep, bukan hasil

Untuk mengambil apa pun dari sebuah halaman, kamu harus menunjuknya lebih dulu: "kartu-kartu produk", "harga di dalam kartu ini". Di Playwright, kamu melakukannya dengan locator. Ini satu locator untuk setiap kartu produk di halaman daftar:

from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.launch()
    page = browser.new_page()
    page.goto("https://nusantara-gadget.test/products")

    cards = page.locator(".product-card")
    print(cards)
    print(cards.count())
    browser.close()
<Locator locator(".product-card")>
12

page.locator(...) belum mencari apa pun; ia adalah resep untuk menemukan elemen. Pencarian terjadi saat kamu bertindak terhadapnya (count(), inner_text(), click()), dan Playwright menjalankannya ulang setiap kali, jadi locator tidak pernah basi saat halamannya berubah.

CSS selector yang benar-benar akan kamu pakai

Markup kartu di halaman produk terlihat seperti ini:

<article class="product-card" data-id="1" data-category="phones">
  <h3 class="title"><a href="/product/1">Galaxy A55 5G</a></h3>
  <p class="brand">Samsung</p>
  <p class="price" data-price="5999000">Rp 5.999.000</p>
  ...
  <span class="stock in-stock">In stock</span>
</article>
with sync_playwright() as p:
    browser = p.chromium.launch()
    page = browser.new_page()
    page.goto("https://nusantara-gadget.test/products")

    print(page.locator(".product-card .title").first.inner_text())     # descendant
    print(page.locator('[data-category="laptops"]').count())          # attribute
    print(page.locator(".product-card:has(.sold-out)").count())       # has a child
    print(page.locator("#product-list > article").count())            # id + direct child
    print(page.locator('.product-card[data-id="3"] .price').inner_text())
    browser.close()
Galaxy A55 5G
4
2
12
Rp 13.999.000
SelectorMencocokkan
.priceelemen dengan class price
#product-listelemen dengan id product-list
.card .price.price di mana saja di dalam .card
ul > lili yang merupakan anak langsung dari ul
[data-id="3"]atribut yang sama dengan sebuah nilai
.card:has(.sold-out)kartu yang berisi elemen .sold-out

Utamakan pengait yang stabil: id, atribut data-*, dan nama class yang bermakna (.price) lebih tahan terhadap redesain daripada path panjang seperti div > div:nth-child(3) > p.

Locator berorientasi pengguna

Locator ini menemukan elemen dengan cara manusia (atau screen reader) mendeskripsikannya, sehingga tetap berfungsi saat HTML-nya disusun ulang:

with sync_playwright() as p:
    browser = p.chromium.launch()
    page = browser.new_page()
    page.goto("https://nusantara-gadget.test/products")

    print(page.get_by_role("heading", level=1).inner_text())
    print(page.get_by_role("link", name="Next").get_attribute("href"))
    print(page.get_by_placeholder("Search products").count())
    print(page.get_by_text("Sold out").count())
    print(page.get_by_role("link", name="iPhone 15").get_attribute("href"))
    browser.close()
All products
/products?page=2
1
2
/product/3

Mempersempit: filter, nth, chaining

Sering kali sebuah selector mencocokkan terlalu banyak. Kamu hanya ingin produk Apple, atau harga di dalam satu kartu tertentu, atau hanya hasil pertama. Locator bisa dipersempit langkah demi langkah:

with sync_playwright() as p:
    browser = p.chromium.launch()
    page = browser.new_page()
    page.goto("https://nusantara-gadget.test/products")

    cards = page.locator(".product-card")
    apple = cards.filter(has_text="Apple")
    print(apple.count())
    print(apple.locator(".title").all_inner_texts())
    print(cards.filter(has=page.locator(".sold-out")).locator(".title").all_inner_texts())
    print(cards.nth(2).locator(".title").inner_text(), "|", cards.last.locator(".title").inner_text())
    browser.close()
2
['iPhone 15', 'MacBook Air M3']
['Redmi Note 13 Pro', 'Vivo V30']
iPhone 15 | Swift Go 14

Strict mode

Aksi yang butuh satu elemen (inner_text, click, fill) menolak menebak saat sebuah locator cocok dengan beberapa elemen:

with sync_playwright() as p:
    browser = p.chromium.launch()
    page = browser.new_page()
    page.goto("https://nusantara-gadget.test/products")
    page.locator(".price").inner_text()
Error: strict mode violation: locator(".price") resolved to 12 elements. Make the locator more specific, or use .first, .nth(i) or .all().

Error itu adalah fitur: ia mencegah scraper-mu diam-diam membaca harga yang salah. Buat locator-nya lebih spesifik, atau gunakan .first, .nth(i), atau method yang bekerja untuk banyak elemen (count(), all_inner_texts(), all()).

Ide utama

Utamakan locator berorientasi pengguna (get_by_role, get_by_text, get_by_label) dan pengait CSS yang stabil (id, data-*, class yang bermakna). Persempit dengan filter, chaining, dan nth. Strict mode melindungimu dari kecocokan yang ambigu.

Mengapa ini penting untuk kode yang bersih

Selector adalah kontrak antara scraper-mu dan situs yang tidak kamu kendalikan. Simpan di satu tempat (dict berisi selector bernama di bagian atas file), buat mereka mendeskripsikan makna alih-alih layout, dan redesain pun cukup diperbaiki dengan dua baris alih-alih perburuan di seluruh kode.

Rangkuman

Latihan modul ini

Soal-soal untuk pelajaran ini berjalan di browser-mu dan langsung mengecek jawabanmu.

Berikutnya: Mengambil teks dan atribut →