---
title: "CSS Selector ve XPath: Web Scraping İçin Hangisi?"
description: "CSS selector kısa ve okunaklıdır, XPath ise metne ve üst öğelere göre de seçim yapar. İki yöntemi söz dizimi, hız ve Python örnekleriyle karşılaştırıyoruz."
url: https://proxynet.io/tr/blog/css-selector-vs-xpath
date: 2026-09-13
author: "Acar Diveroli"
category: "Karşılaştırma, Web Scraping"
lang: tr
---

# CSS Selector ve XPath: Web Scraping İçin Hangisi?

Bir sayfayı indirdikten sonra scraping'in asıl işi başlar: yüzlerce etiketin arasından ürün adını, fiyatı ve bağlantıyı bulup çıkarmak. Bunun için sayfanın hangi öğesini istediğinizi bir **seçici** ile tarif edersiniz. İki yaygın dil vardır: web geliştiricilerin stil dosyalarından tanıdığı **CSS selector** ve XML dünyasından gelen **XPath**. Aynı öğeyi çoğu zaman ikisiyle de seçebilirsiniz, ama biri kısa ve okunaklıyken diğeri CSS'in hiç yapamadığı bazı işleri yapar.

Bu yazıda iki dilin ne olduğunu, söz dizimlerini yan yana, XPath'in CSS'e göre fazladan yapabildiklerini ve performans farkının gerçekte önemli olup olmadığını anlatıyoruz. Ardından sayfa tasarımı değiştiğinde bozulmayan seçicilerin nasıl yazılacağını ve seçicilerin tarayıcıda nasıl test edileceğini gösteriyoruz. Yazının ortasında yer imlerinize ekleyebileceğiniz 20 satırlık bir hızlı başvuru tablosu var; tablodaki her CSS ve XPath çiftinin aynı öğeleri seçtiğini bir test sayfasında doğruladık.

> **Not: Kısa cevap**
>
> Öğeleri etiket, sınıf, kimlik ve özniteliğe göre seçiyorsanız CSS selector daha kısa, okunaklı ve her araçta desteklenir. Öğeyi içindeki metne göre bulmanız, bir öğeden üst öğesine ya da önceki kardeşine gitmeniz gerekiyorsa XPath gerekir. İki dil arasındaki hız farkı, ağ ve sayfa yükleme süresinin yanında genellikle önemsizdir. Pratik yaklaşım: varsayılan olarak CSS, CSS'in yetmediği yerde XPath.

## CSS selector nedir?

CSS selector, CSS stil dosyalarında hangi öğeye stil uygulanacağını belirtmek için kullanılan desen dilidir. Tarayıcılar aynı dili JavaScript'te `document.querySelector()` ve `querySelectorAll()` fonksiyonlarıyla da destekler. Dilin güncel tanımı W3C'nin [Selectors Level 4](https://www.w3.org/TR/selectors-4/) belgesidir.

CSS selector bir öğeyi şu bilgilere göre seçer:

- **Etiket:** `div`, `a`, `span`
- **Sınıf:** `.urun`
- **Kimlik:** `#liste`
- **Öznitelik:** `a[href]`, `img[src$=".webp"]`
- **Hiyerarşi:** `ul > li` (doğrudan alt öğe), `div span` (herhangi bir derinlikteki alt öğe)
- **Kardeşlik:** `h2 + p` (hemen sonraki), `h2 ~ span` (sonraki bütün kardeşler)
- **Konum:** `li:first-of-type`, `li:nth-of-type(3)`

CSS'in temel yönü **aşağı ve ileri** doğrudur: bir öğeden alt öğelerine ve sonraki kardeşlerine gidebilirsiniz. Selectors Level 4 ile gelen `:has()` sözde sınıfı bu kuralı kısmen esnetir: `div.urun:has(> span.indirim)` içinde indirim etiketi bulunan ürün kartlarını seçer. Ancak `:has()` bir öğeden yukarı "çıkmaz"; içindekilere bakarak dıştaki öğeyi seçer.

## XPath nedir?

XPath (XML Path Language), XML ve HTML belgelerinde düğümleri bir yol ifadesiyle seçen sorgu dilidir. Belgeyi bir ağaç olarak görür ve bu ağaçta her yöne hareket edebilir: aşağı, yukarı, önceki ve sonraki kardeşlere. W3C'nin güncel tanımı [XPath 3.1](https://www.w3.org/TR/xpath-31/) sürümüdür.

Pratikte önemli bir ayrıntı var: **tarayıcılar ve Python'daki lxml kütüphanesi XPath 1.0 destekler.** Sonraki sürümlerde gelen `ends-with()`, düzenli ifade fonksiyonları ve daha zengin tür sistemi bu ortamlarda kullanılamaz. Scraping için yazdığınız XPath ifadelerini 1.0 sınırları içinde tutun.

XPath'in temel parçaları:

- **`//`** belgedeki herhangi bir derinlik, **`/`** doğrudan alt düğüm: `//ul/li`
- **`[...]`** koşul (predicate): `//a[@href]`, `//li[3]`
- **`@`** öznitelik: `//img/@src`
- **`text()`** metin düğümü: `//h2/text()`
- **Eksenler** (axis): `parent::`, `ancestor::`, `following-sibling::`, `preceding-sibling::`
- **Fonksiyonlar:** `contains()`, `starts-with()`, `normalize-space()`, `last()`, `string-length()`

Tarayıcıda XPath, JavaScript'in `document.evaluate()` fonksiyonuyla çalıştırılır; kullanımı [MDN belgesinde](https://developer.mozilla.org/en-US/docs/Web/API/Document/evaluate) anlatılır.

## Söz dizimi karşılaştırması

| Ölçüt | CSS selector | XPath |
|---|---|---|
| Okunabilirlik | Kısa, web geliştiricilere tanıdık | Uzun, öğrenme eğrisi daha dik |
| Yön | Aşağı ve ileri (`:has()` ile kısmen dışa) | Her yöne: üst öğe, önceki kardeş, ata |
| Metne göre seçim | Standartta yok | Var: `text()`, `contains()` |
| Öznitelik değeri döndürme | Yok (kütüphane uzantısıyla) | Var: `/@href` |
| Metin düğümü döndürme | Yok (kütüphane uzantısıyla) | Var: `/text()` |
| Sınıf eşleştirme | `.urun` kesin ve kısa | `contains(@class, ...)` dikkat ister |
| Tarayıcı desteği | `querySelectorAll` | `document.evaluate` (XPath 1.0) |
| Python desteği | BeautifulSoup, lxml (cssselect), parsel | lxml, parsel; BeautifulSoup desteklemez |
| Headless tarayıcı | Playwright, Puppeteer, Selenium | Playwright, Puppeteer, Selenium |
| Tipik kullanım | Sınıf ve özniteliğe göre liste çıkarma | Etiket-değer tabloları, metne bağlı seçim |

## Hızlı başvuru tablosu

Aşağıdaki tabloda her satır aynı seçimin iki dildeki karşılığıdır. Karşılığı olmayan satırlarda XPath'in fazladan yapabildiği işler gösterilir.

| # | Ne seçilir? | CSS selector | XPath |
|---|---|---|---|
| 1 | Bütün `div` öğeleri | `div` | `//div` |
| 2 | Kimliğe göre | `#liste` | `//*[@id="liste"]` |
| 3 | Sınıfa göre | `.urun` | `//*[contains(concat(" ", normalize-space(@class), " "), " urun ")]` |
| 4 | Doğrudan alt öğe | `ul > li` | `//ul/li` |
| 5 | Herhangi bir derinlikteki alt öğe | `div span` | `//div//span` |
| 6 | Özniteliği olan | `a[href]` | `//a[@href]` |
| 7 | Öznitelik değeri eşit | `input[name="q"]` | `//input[@name="q"]` |
| 8 | Öznitelik şununla başlar | `a[href^="https"]` | `//a[starts-with(@href, "https")]` |
| 9 | Öznitelik şunu içerir | `a[href*="urun"]` | `//a[contains(@href, "urun")]` |
| 10 | Öznitelik şununla biter | `img[src$=".webp"]` | `//img[substring(@src, string-length(@src) - 4) = ".webp"]` |
| 11 | İlk öğe | `ul > li:first-of-type` | `//ul/li[1]` |
| 12 | Son öğe | `ul > li:last-of-type` | `//ul/li[last()]` |
| 13 | Üçüncü öğe | `ul > li:nth-of-type(3)` | `//ul/li[3]` |
| 14 | Hemen sonraki kardeş | `h2 + p` | `//h2/following-sibling::*[1][self::p]` |
| 15 | Sonraki bütün kardeşler | `h2 ~ span` | `//h2/following-sibling::span` |
| 16 | Birden fazla seçim | `h1, h2` | `//h1 \| //h2` |
| 17 | İçinde belirli öğe olan kart | `div.urun:has(> span.indirim)` | `//span[@class="indirim"]/..` |
| 18 | Metni tam eşit olan buton | Standartta yok | `//button[text()="Sepete ekle"]` |
| 19 | Bir öğenin belirli atası | Standartta yok | `//span[@class="fiyat"]/ancestor::div[@data-sku][1]` |
| 20 | Etiketin yanındaki değer | Standartta yok | `//th[normalize-space()="Stok"]/following-sibling::td[1]` |

Tablodaki birkaç ayrıntı sık hataya yol açar:

- **Satır 3:** `//*[contains(@class, "urun")]` daha kısa görünür ama `urunler` veya `eski-urun` sınıflarını da seçer. Tablodaki uzun ifade yalnızca tam `urun` sınıfını eşleştirir.
- **Satır 10:** XPath 1.0'da `ends-with()` yoktur; `substring` ile son karakterler karşılaştırılır. Sayı, aranan uzantının uzunluğundan bir eksiktir (`.webp` beş karakter, `- 4`).
- **Satır 11:** `li:first-child` ile `li:first-of-type` farklıdır. İlki, ebeveyninin ilk çocuğu olan `li`'yi seçer; ilk çocuk başka bir etiketse hiçbir şey seçmez.
- **Satır 14:** `//h2/following-sibling::p[1]` "sonraki ilk `p`" demektir ve arada başka öğeler olsa da eşleşir. CSS'teki `h2 + p` ise yalnızca `h2`'nin hemen ardından gelen öğe `p` ise eşleşir.

Öznitelik değeri ve metin düğümü döndürmek için XPath'te `//a/@href` ve `//h2/text()` kullanılır. Python'daki parsel kütüphanesi CSS'e bu işler için standart dışı `a::attr(href)` ve `h2::text` uzantılarını ekler.

## XPath'in yapabildiği, CSS'in yapamadığı

### Metne göre seçim

Bir e-ticaret sayfasında "Sepete ekle" butonu ile "Stokta yok" butonu aynı sınıfı taşıyabilir. İkisini ayıran tek şey metinleridir:

```text
//button[text()="Sepete ekle"]
//span[contains(normalize-space(.), "İndirim")]
```

`text()` yalnızca öğenin doğrudan metin düğümüne bakar; metin iç içe etiketlere bölünmüşse eşleşmez. `normalize-space(.)` ise öğenin bütün metnini birleştirir ve baştaki, sondaki boşlukları temizler; bu yüzden genellikle daha güvenilirdir.

Standart CSS'te metne göre seçim yoktur. Bazı araçlar kendi uzantılarını sunar: Playwright'ta `has_text` seçeneği ve `:has-text()`, BeautifulSoup'ta `:-soup-contains()`. Bu uzantılar yalnızca o araçta çalışır.

### Üst öğeye ve önceki kardeşe çıkma

Bir ürün kartında yalnızca fiyat alanı kararlı bir sınıfa sahipse, fiyattan başlayıp kartın tamamına ulaşmak gerekir:

```text
//span[@class="fiyat"]/..
//span[@class="fiyat"]/ancestor::div[@data-sku][1]
```

`..` doğrudan ebeveyni, `ancestor::` herhangi bir üst düzeydeki atayı seçer. `[1]` en yakın atayı alır.

### Etiket-değer yapıları

Ürün özellik tabloları ve tanım listeleri scraping'in en sık karşılaştığı yapılardandır. Hangi satırın hangi sırada geleceği ürüne göre değişir; sabit olan, etiketin metnidir:

```text
//th[normalize-space()="Stok"]/following-sibling::td[1]
//dt[normalize-space()="Garanti"]/following-sibling::dd[1]
```

Bu ifadeler "Stok" başlığı tablonun kaçıncı satırında olursa olsun yanındaki değeri bulur. CSS ile aynı işi yapmak için bütün satırları çekip Python'da döngüyle aramanız gerekir.

## Python'da CSS ve XPath kullanımı

Python'da üç yaygın kütüphane vardır ve seçici desteği birbirinden farklıdır.

**BeautifulSoup** yalnızca CSS selector destekler (`select` ve `select_one`); XPath desteği yoktur:

```python
from bs4 import BeautifulSoup

soup = BeautifulSoup(html, "html.parser")
urunler = []
for kart in soup.select("div.urun"):
    urunler.append({
        "sku": kart.get("data-sku"),
        "ad": kart.select_one("h2").get_text(strip=True),
        "fiyat": kart.select_one(".fiyat").get_text(strip=True),
        "link": kart.select_one("a[href]")["href"],
    })
```

**lxml** XPath 1.0'ı doğrudan çalıştırır ve `string()` gibi fonksiyonlarla sonucu metin olarak döndürebilir:

```python
from lxml import html as lxml_html

agac = lxml_html.fromstring(html)
stok = agac.xpath('string(//th[normalize-space()="Stok"]/following-sibling::td[1])')
indirimli_sku = agac.xpath('//span[@class="indirim"]/ancestor::div[@data-sku][1]/@data-sku')
```

**parsel** (Scrapy'nin seçici kütüphanesi) iki dili aynı nesnede, birbirine zincirlenebilir biçimde sunar. CSS ile kartları bulup kartın içinde XPath kullanmak mümkündür:

```python
from parsel import Selector

sayfa = Selector(text=html)
for kart in sayfa.css("div.urun"):
    ad = kart.css("h2::text").get()
    link = kart.css("a::attr(href)").get()
    satilabilir = kart.xpath('.//button[text()="Sepete ekle"]').get() is not None
    print(ad, link, satilabilir)
```

Zincirlemede dikkat edilecek nokta, kartın içinde çalışan XPath ifadesinin **`.//`** ile başlamasıdır. `//button` yazarsanız arama kartın içinde değil, bütün belgede yapılır ve her kart için ilk butonu bulursunuz.

Hangi dilde ve hangi kütüphaneyle çalışacağınıza karar vermek için [Web Kazıma: JavaScript mi Python mu?](/tr/blog/web-scraping-javascript-vs-python) yazımıza bakabilirsiniz. BeautifulSoup'ta `find_all`, sınıfa göre seçim ve `get_text` ayrıntıları için [BeautifulSoup rehberimize](/tr/blog/beautifulsoup-tutorial) göz atın.

## Headless tarayıcılarda seçiciler

İçeriği JavaScript ile yüklenen sayfalarda seçiciler bir tarayıcı otomasyon aracının içinde kullanılır. Playwright iki dili de destekler ve `//` ile başlayan ifadeyi otomatik olarak XPath kabul eder:

```python
from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    tarayici = p.chromium.launch()
    sayfa = tarayici.new_page()
    sayfa.goto("https://ornek.com/kampanyalar")

    fiyatlar = sayfa.locator("div.urun .fiyat").all_inner_texts()
    stok = sayfa.locator('xpath=//th[normalize-space()="Stok"]/following-sibling::td[1]').inner_text()
    sepete_eklenebilir = sayfa.locator("div.urun", has_text="Sepete ekle")

    print(fiyatlar, stok, sepete_eklenebilir.count())
    tarayici.close()
```

Selenium'da aynı işler `By.CSS_SELECTOR` ve `By.XPATH` ile yapılır; kurulumu ve proxy ayarını [Selenium ile Proxy Kullanımı](/tr/blog/selenium) ve [SeleniumBase ile Proxy](/tr/blog/seleniumbase-ile-proxy) yazılarımızda anlattık. Bir sayfanın gerçekten tarayıcı gerektirip gerektirmediğini anlamak için [Statik ve Dinamik Sayfalar](/tr/blog/static-vs-dynamic-pages) yazımıza bakabilirsiniz.

## Performans farkı gerçekten önemli mi?

İnternette "CSS selector XPath'ten hızlıdır" ifadesi sık geçer. Durum ortama göre değişir:

- **Tarayıcıda** `querySelectorAll` doğrudan tarayıcı motorunun optimize edilmiş seçici eşleştiricisini kullanır; `document.evaluate` ile çalışan XPath genellikle daha yavaştır. Fark, çok büyük sayfalarda ve binlerce kez tekrarlanan sorgularda hissedilir.
- **Python'da lxml ve parsel ile** CSS selector'lar çoğunlukla arka planda XPath'e çevrilip çalıştırılır. Yani iki dil aynı motoru kullanır ve fark büyük ölçüde ortadan kalkar.
- **BeautifulSoup'ta** seçim hızını seçici dilinden çok kullanılan ayrıştırıcı (`html.parser` veya `lxml`) belirler.

Asıl belirleyici olan ise seçicinin **nasıl yazıldığıdır**. Belgenin tamamını tarayan `//*[contains(@class, "fiyat")]`, önce kartı sonra kartın içindeki fiyatı arayan bir ifadeden çok daha fazla iş yapar. Ve bütün bunlar, sayfayı ağdan indirmek ya da bir headless tarayıcıda yüklemek için geçen sürenin yanında genellikle küçük kalır. Bir scraper'ın gerçek darboğazını [Concurrency ve Parallelism](/tr/blog/concurrency-vs-parallelism) yazımızda ele aldık.

## Kırılgan seçici nasıl önlenir?

Scraper'ların en sık bozulma nedeni engellenme değil, sitenin tasarımının değişmesidir. Seçicinin sayfadaki küçük değişikliklere dayanıklı olması için:

- **Otomatik üretilmiş sınıf adlarından kaçının.** `css-1x9k2ab` veya `sc-bdVaJa` gibi sınıflar her sürümde değişebilir.
- **Mutlak yol yazmayın.** Tarayıcıdan kopyalanan `/html/body/div[3]/div[2]/ul/li[4]/span` ifadesi, sayfaya tek bir banner eklendiğinde bozulur.
- **Konuma değil anlama bağlanın.** "Üçüncü `span`" yerine "`fiyat` sınıflı `span`" ya da "Stok başlığının yanındaki hücre".
- **Kararlı öznitelikleri tercih edin.** `data-sku`, `data-testid`, `itemprop`, `aria-label` gibi öznitelikler görsel tasarımdan bağımsız olduğu için daha az değişir.
- **Önce yapılandırılmış veriye bakın.** Birçok ürün sayfası `<script type="application/ld+json">` içinde ürün adı, fiyat ve stok bilgisini schema.org biçiminde taşır. Bu veriyi okumak, görsel HTML'i ayrıştırmaktan çok daha dayanıklıdır. Bu alanları doğru türde değerlere çevirmek ayrı bir adımdır; [Veri Ayrıştırma (Parsing) Nedir? Parser Türleri ve Hataları](/tr/blog/what-is-data-parsing) yazısında anlattık.
- **Önce kapsayıcıyı, sonra alanı seçin.** Kartı bir kez bulup alanları kartın içinde aramak, alanlar arasında karışıklığı önler.
- **Boş sonucu hata olarak ele alın.** Seçici hiçbir şey bulamadığında sessizce boş değer yazmak yerine kaydedip uyarı verin; tasarım değişikliğini ilk gün fark edersiniz.

Seçicilerin boş dönmesi her zaman tasarım değişikliği değildir; bazen bot korumasının döndürdüğü farklı bir sayfa, bazen de JavaScript ile sonradan yüklenen içerik yüzündendir. Teşhis için [Web Scraping'de Engellenmeden Veri Toplama Yöntemleri](/tr/blog/web-scraping-without-getting-blocked) yazımızdaki listeye bakabilirsiniz.

## Tarayıcıda seçici nasıl test edilir?

Seçiciyi koda yazmadan önce tarayıcıda denemek zaman kazandırır. Chrome, Edge ve Firefox'un geliştirici araçlarında (F12):

- **Konsolda `$$("div.urun .fiyat")`** CSS selector ile eşleşen bütün öğeleri dizi olarak döndürür.
- **Konsolda `$x('//th[normalize-space()="Stok"]/following-sibling::td[1]')`** XPath ifadesini çalıştırır.
- **Elements panelinde `Ctrl + F`** arama kutusu hem düz metin hem CSS selector hem XPath kabul eder ve eşleşen öğeleri tek tek vurgular.

İki uyarı: tarayıcıda gördüğünüz sayfa JavaScript çalıştıktan sonraki hâlidir. Scraper'ınız bir HTTP istemcisiyle yalnızca sunucunun döndürdüğü HTML'i alıyorsa, tarayıcıda çalışan seçici kodda boş dönebilir; kaynağı görüntüleyerek (`Ctrl + U`) kontrol edin. İkincisi, tarayıcının "XPath'i kopyala" özelliği genellikle mutlak ve kırılgan yollar üretir; bunları başlangıç noktası olarak kullanıp sadeleştirin.

## Kullanım senaryoları

- **Fiyat takibi:** Ürün kartları CSS ile, "Stok" gibi etiket-değer alanları XPath ile. Kurgusu [fiyat takibi çözümü](/tr/price-monitoring) sayfamızda.
- **Katalog toplama:** Önce JSON-LD, yoksa kararlı `data-*` öznitelikleriyle CSS selector. Genel veri toplama kurgusu [veri kazıma çözümü](/tr/data-scraping) sayfamızda.
- **Karşılaştırma siteleri:** Farklı sitelerin farklı yapıları için site başına seçici tanım dosyası; metne bağlı alanlar için XPath.
- **Test otomasyonu:** Kendi uygulamanızda `data-testid` öznitelikleriyle CSS selector; tasarım değişikliklerinden etkilenmeyen testler.
- **Çok sayıda sayfada düzenli çekim:** Seçiciler sabit kaldığı sürece iş, istek dağıtımına dönüşür; tek adres üzerinden farklı çıkış IP'leri için [Rotating Proxy](https://proxynet.io/tr/rotating-proxy) kullanılabilir.

## Karar rehberi

| İhtiyacınız | Öneri |
|---|---|
| Sınıf, kimlik veya özniteliğe göre seçim | CSS selector |
| BeautifulSoup kullanıyorsunuz | CSS selector (XPath desteği yok) |
| Öğeyi metnine göre bulmak | XPath |
| Bir öğeden üst öğeye veya önceki kardeşe gitmek | XPath |
| Etiket-değer tabloları ve tanım listeleri | XPath |
| Öznitelik değerini doğrudan döndürmek | XPath `/@attr` veya parsel `::attr()` |
| Aynı projede ikisi birden | parsel |
| Headless tarayıcı | Playwright locator, CSS öncelikli |
| Tasarım değişikliğine dayanıklılık | `data-*` öznitelikleri veya JSON-LD |

## Sık sorulan sorular

### CSS selector mı XPath mi öğrenmeliyim?

Önce CSS selector öğrenin; daha kısa, daha yaygın ve web geliştirmede de işinize yarar. Scraping'de metne göre seçim ve üst öğeye çıkma ihtiyacı doğduğunda XPath'in eksenlerini ve fonksiyonlarını öğrenmek yeterlidir. İkisini birlikte kullanan parsel gibi kütüphanelerle geçiş kolaydır.

### BeautifulSoup XPath destekliyor mu?

Hayır. BeautifulSoup yalnızca CSS selector destekler. XPath gerekiyorsa aynı HTML'i lxml veya parsel ile ayrıştırabilirsiniz.

### CSS'te metne göre seçim yapılabilir mi?

Standart CSS'te yapılamaz. Bazı araçlar kendi uzantılarını sunar: Playwright'ta `has_text` ve `:has-text()`, BeautifulSoup'ta `:-soup-contains()`. Bu uzantılar yalnızca ilgili araçta çalışır, taşınabilir değildir.

### Tarayıcıdan kopyalanan XPath neden çalışmıyor?

Tarayıcının ürettiği yol genellikle mutlaktır ve JavaScript çalıştıktan sonraki sayfaya göre oluşturulur. Sunucunun ilk döndürdüğü HTML'de o yapı olmayabilir ya da küçük bir tasarım değişikliği yolu bozabilir. Yolu kararlı bir sınıf, kimlik veya öznitelikten başlayacak şekilde sadeleştirin.

### `text()` ile `normalize-space()` arasındaki fark nedir?

`text()` öğenin doğrudan metin düğümlerini döndürür ve boşlukları olduğu gibi bırakır. `normalize-space(.)` öğenin iç içe etiketler dahil bütün metnini birleştirir, baştaki ve sondaki boşlukları siler, aradaki boşlukları teke indirir. Metin karşılaştırmalarında genellikle `normalize-space()` daha güvenilirdir.

### Seçicilerim neden bazen boş dönüyor?

En sık üç neden vardır: sayfa tasarımı değişmiştir, içerik JavaScript ile sonradan yüklenmektedir ya da site size beklediğiniz sayfa yerine bir doğrulama veya hata sayfası döndürmektedir. Yanıtın HTML'ini bir dosyaya kaydedip seçiciyi o dosya üzerinde denemek, üç nedeni birbirinden ayırmanın en hızlı yoludur.

## Özetle

CSS selector kısa, okunaklı ve her araçta desteklenir; etiket, sınıf, kimlik ve özniteliğe göre seçimde varsayılan tercih olmalıdır. XPath ise metne göre seçim, üst öğeye ve önceki kardeşe çıkma ve etiket-değer yapıları gibi CSS'in yapamadığı işler için gerekir; tarayıcılarda ve lxml'de 1.0 sürümüyle sınırlıdır. Performans farkı çoğu scraping işinde ağ süresinin yanında önemsizdir; asıl önemli olan, tasarım değişikliklerine dayanıklı seçici yazmaktır. Veri toplama işleriniz için uygun proxy türlerini [proxy hizmetlerimizde](/tr/proxy) bulabilirsiniz.
