SO selenyum etiketinde popüler olmayan, XPath'in daha uzun vadede CSS'ye tercih edilebilir olduğu görüşünü benimseyeceğim .
Bu uzun gönderinin iki bölümü var - önce peçetenin arkasına bir kanıt koyacağım, ikisi arasındaki performans farkı 0.1-0.3 milisaniye (evet; bu 100 mikro saniye) ve ardından neden fikrimi paylaşacağım XPath daha güçlüdür.
Performans farkı
İlk önce "odadaki fil" konusunu ele alalım - bu xpath css'den daha yavaştır.
Mevcut işlemci gücüyle (okuyun: 2013'ten beri üretilen x86 herhangi bir şey) , hatta browserstack / saucelabs / aws VM'lerinde ve tarayıcıların geliştirilmesiyle (okuyun: son 5 yıldaki tüm popüler olanlar) pek de öyle değil. Tarayıcının motorları gelişti, xpath desteği tek tip, IE resmin dışında (umarız çoğumuz için) . Diğer yanıttaki bu karşılaştırma her yerde alıntılanıyor, ancak çok bağlamsal - kaç kişi çalışıyor - veya IE8'e karşı otomasyonu önemsiyor?
Bir fark varsa, milisaniyenin bir kısmı içindedir .
Yine de, çoğu üst düzey çerçeve, ham selenyum çağrısı üzerine en az 1ms ek yük ekler (sarmalayıcılar, işleyiciler, durum depolaması vb.); Benim kişisel silahım - RobotFramework - en az 2 ms ekler, ki bunu sağladığı şey için feda etmekten çok mutluyum. Bir AWS us-east-1'den BrowserStack'in hub'ına bir ağ gidiş dönüşü genellikle 11 milisaniyedir .
Yani uzak tarayıcılarda xpath ve css arasında bir fark varsa, büyüklük sırasına göre diğer her şey tarafından gölgede bırakılır.
Ölçümler
Çok fazla halka açık karşılaştırma yok (gerçekten sadece alıntı yapılanı gördüm) , bu yüzden - işte kaba tek durum, sahte ve basit bir örnek.
İki strateji ile bir öğeyi X kez bulacak ve bunun için ortalama süreyi karşılaştıracaktır.
Hedef - BrowserStack'in açılış sayfası ve "Kaydol" düğmesi; bu yazıyı yazarken html'nin ekran görüntüsü:
İşte test kodu (python):
from selenium import webdriver
import timeit
if __name__ == '__main__':
xpath_locator = '//div[@class="button-section col-xs-12 row"]'
css_locator = 'div.button-section.col-xs-12.row'
repetitions = 1000
driver = webdriver.Chrome()
driver.get('https://www.browserstack.com/')
css_time = timeit.timeit("driver.find_element_by_css_selector(css_locator)",
number=repetitions, globals=globals())
xpath_time = timeit.timeit('driver.find_element_by_xpath(xpath_locator)',
number=repetitions, globals=globals())
driver.quit()
print("css total time {} repeats: {:.2f}s, per find: {:.2f}ms".
format(repetitions, css_time, (css_time/repetitions)*1000))
print("xpath total time for {} repeats: {:.2f}s, per find: {:.2f}ms".
format(repetitions, xpath_time, (xpath_time/repetitions)*1000))
Python'a aşina olmayanlar için - sayfayı açar ve öğeyi bulur - önce css bulucu ile, sonra xpath ile; bulma işlemi 1.000 defa tekrarlanır. Çıktı, 1.000 tekrar için saniye cinsinden toplam süre ve milisaniye cinsinden bir bulmanın ortalama süresidir.
Yer belirleyiciler şunlardır:
- xpath için - "DOM içinde bir yerde tam olarak bu sınıf değerine sahip bir div öğesi";
- css benzer - "DOM içinde bir yerde bu sınıfa sahip bir div öğesi".
Aşırı ayar yapılmaması için bilinçli olarak seçilmiş; ayrıca, sınıf seçici css için "bir id'den sonra en hızlı ikinci" olarak gösterilir.
Ortam - Chrome v66.0.3359.139, chromedriver v2.38, cpu: ULV Core M-5Y10 genellikle 1.5GHz'de çalışıyor (evet, bir "kelime işlemci", normal bir i7 canavarı bile değil) .
İşte çıktı:
css total time 1000 repeats: 8.84s, per find: 8.84ms
xpath total time for 1000 repeats: 8.52s, per find: 8.52ms
Açıkçası, bulma başına zamanlamalar oldukça yakındır; fark 0,32 milisaniyedir . "Xpath daha hızlıdır" atlamayın - bazen öyle, bazen css'dir.
Biraz daha karmaşık olan başka bir yer belirleyici kümesini deneyelim - bir alt dizeye sahip bir öznitelik (en azından benim için ortak yaklaşım, bir parçası işlevsel anlam taşıdığında bir öğenin sınıfının peşinden gitmek) :
xpath_locator = '//div[contains(@class, "button-section")]'
css_locator = 'div[class~=button-section]'
İki konumlandırıcı yine anlamsal olarak aynıdır - "sınıf özniteliğinde bu alt dizeye sahip bir div öğesi bulun".
Sonuçlar burada:
css total time 1000 repeats: 8.60s, per find: 8.60ms
xpath total time for 1000 repeats: 8.75s, per find: 8.75ms
Bir Diff 0.15ms .
Bir alıştırma olarak - yorumlarda / diğer cevaplarda bağlantılı blogda yapılan testin aynısı - test sayfası ve test kodu da herkese açıktır .
Kodda birkaç şey yapıyorlar - ona göre sıralamak için bir sütuna tıklamak, sonra değerleri almak ve UI sıralamasının doğru olup olmadığını kontrol etmek.
Keseceğim - sadece yer belirleyicileri al, sonuçta - bu kök testi, değil mi?
Yukarıdaki ile aynı kod, şu değişikliklerle birlikte:
css_locator = '#table2 tbody .dues'
xpath_locator = "//table[@id='table2']//tr/td[contains(@class,'dues')]"
Ve işte sonuç:
css total time 1000 repeats: 8.24s, per find: 8.24ms
xpath total time for 1000 repeats: 8.45s, per find: 8.45ms
Bir Diff 0.2 milisaniye.
"Öğeleri Gezerek Bulma":
css_locator = '#table1 tbody tr td:nth-of-type(4)'
xpath_locator = "//table[@id='table1']//tr/td[4]"
Sonuç:
css total time 1000 repeats: 9.29s, per find: 9.29ms
xpath total time for 1000 repeats: 8.79s, per find: 8.79ms
Bu sefer 0,5 ms'dir (tersine, xpath burada "daha hızlı" çıktı).
Yani 5 yıl sonra (daha iyi tarayıcı motorları) ve yalnızca konum belirleyicilerin performansına odaklanarak (kullanıcı arayüzünde sıralama gibi eylemler yok, vb.), Aynı test yatağı - CSS ve XPath arasında neredeyse hiç fark yok.
Peki, xpath ve css dışında, performans için ikisinden hangisini seçmelisiniz? Cevap basit - id ile bulmayı seçin .
Uzun lafın kısası, eğer bir öğenin kimliği benzersizse (spesifikasyonlara göre olması gerektiği gibi), değeri tarayıcının DOM'un dahili temsilinde önemli bir rol oynar ve bu nedenle genellikle en hızlısıdır.
Yine de, benzersiz ve sabit kimlikler (örneğin, otomatik olarak oluşturulmayan) her zaman mevcut değildir, bu da bizi "CSS varsa neden XPath?"
XPath avantajı
Görüntünün dışında performans varken, neden xpath'in daha iyi olduğunu düşünüyorum? Basit - çok yönlülük ve güç.
Xpath, XML belgelerle çalışmak için geliştirilmiş bir dildir; bu nedenle, css'den çok daha güçlü yapılara izin verir.
Örneğin, ağaçta her yönde gezinme - bir öğe bulun, sonra büyük ebeveynine gidin ve belirli özelliklere sahip olan bir alt öğesini arayın.
Gömülü boole koşullarına izin verir - cond1 and not(cond2 or not(cond3 and cond4))
; gömülü seçiciler - "bu özniteliklere sahip bu çocuklara sahip bir div bulun ve ardından ona göre gezinin".
XPath, bir düğümün değerine (metnine) dayalı aramaya izin verir - bu uygulama her ne kadar hoş karşılanmasa da, özellikle kötü yapılandırılmış belgelerde işe yarar (dinamik kimlikler ve sınıflar gibi adım atılacak kesin nitelikler yoktur), öğeyi metnine göre bulun içerik) .
Css'de adım atmak kesinlikle daha kolaydır - seçicileri dakikalar içinde yazmaya başlayabilirsiniz; ancak birkaç günlük kullanımdan sonra, xpath'in sağladığı güç ve olanaklar css'nin üstesinden hızla gelir.
Ve tamamen öznel - karmaşık bir CSS'yi okumak, karmaşık bir xpath ifadesinden çok daha zordur.
Outro;)
Son olarak, yine çok öznel - hangisini seçmeli?
IMO, doğru ya da yanlış seçim yoktur - bunlar aynı soruna farklı çözümler sunar ve iş için daha uygun olanı seçilmelidir.
XPath'in "hayranı" olarak, projelerimde her ikisinin karışımını kullanmaktan çekinmiyorum - heck, bazen sadece bir CSS bir tane atmak çok daha hızlı, eğer işi iyi yapacağını biliyorsam.