Я збираюся дотримуватися непопулярної думки щодо SO селену, що XPath є кращим, ніж CSS, у довгостроковій перспективі.
Цей довгий допис має два розділи - спочатку я докажу, що різниця в продуктивності між ними становить 0,1-0,3 мілісекунди (так; це 100 мікросекунд ) , а потім поділюсь своєю думкою, чому XPath є потужнішим.
Різниця в продуктивності
Давайте спочатку вирішимо "слона в кімнаті" - xpath повільніший за css.
При поточній потужності процесора (читайте: все, що x86 випускається з 2013 року) , навіть у віртуальних машинах browserstack / saucelabs / aws, і розвитку браузерів (читайте: усіх популярних за останні 5 років), що навряд чи це так. Двигуни браузера розроблені, підтримка xpath рівномірна, IE відсутній (сподіваємось, для більшості з нас) . Це порівняння в іншій відповіді наводиться повсюдно, але воно дуже контекстуальне - скільки працює - або турбується про - автоматизацію проти IE8?
Якщо є різниця, вона становить частку мілісекунди .
Тим не менше, більшість фреймворків вищого рівня в будь-якому випадку додають принаймні 1 мс накладних витрат над необробленим викликом селену (обгортки, обробники, збереження стану тощо); моя особиста обрана зброя - RobotFramework - додає щонайменше 2 мс, якими я з радістю пожертвую заради того, що вона пропонує. Зворотний зв’язок мережі з AWS us-east-1 до концентратора BrowserStack зазвичай становить 11 мілісекунд .
Тож із віддаленими браузерами, якщо є різниця між xpath та css, це затьмарюється усім іншим, на порядки.
Вимірювання
Публічних порівнянь не так багато (я справді бачив лише цитоване) , отже - ось груба одинична, фіктивна та проста.
Він знайде елемент за двома стратегіями X разів і порівняє середній час для цього.
Ціль - цільова сторінка BrowserStack та її кнопка «Зареєструватися»; скріншот HTML-коду під час написання цього повідомлення:
Ось тестовий код (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 - він відкриває сторінку та знаходить елемент - спочатку за допомогою локатора css, потім за допомогою xpath; операція пошуку повторюється 1000 разів. Результатом є загальний час у секундах для 1000 повторень та середній час для однієї знахідки в мілісекундах.
Локаторами є:
- для xpath - "елемент div, що має саме це значення класу, десь у DOM";
- css схожий - "елемент div з цим класом, десь у DOM".
Навмисно вибраний, щоб не перенастроюватися; також, селектор класу вказаний для css як "другий за швидкістю після ідентифікатора".
Середовище - Chrome v66.0.3359.139, chromedriver v2.38, процесор: ULV Core M-5Y10, як правило, працює на частоті 1,5 ГГц (так, "текстовий", навіть не звичайний звір i7) .
Ось результат:
css total time 1000 repeats: 8.84s, per find: 8.84ms
xpath total time for 1000 repeats: 8.52s, per find: 8.52ms
Очевидно, що час знаходження досить близький; різниця становить 0,32 мілісекунди . Не стрибайте "xpath швидший" - іноді це так, іноді це css.
Давайте спробуємо з іншим набором локаторів, дещо складнішим - атрибутом, що має підрядок (загальноприйнятий принаймні для мене підхід, що йде за класом елемента, коли його частина має функціональне значення) :
xpath_locator = '//div[contains(@class, "button-section")]'
css_locator = 'div[class~=button-section]'
Два локатори знову семантично однакові - "знайти елемент div, що має у своєму класі атрибут цього підрядка".
Ось результати:
css total time 1000 repeats: 8.60s, per find: 8.60ms
xpath total time for 1000 repeats: 8.75s, per find: 8.75ms
Різниця 0,15 мс .
Як вправа - той самий тест, що й у зв’язаному блозі в коментарях / іншій відповіді - сторінка тесту є загальнодоступною, а також код тестування .
Вони роблять кілька речей у коді - клацають стовпець, щоб відсортувати за ним, потім отримують значення та перевіряють правильність сортування інтерфейсу.
Я виріжу це - просто дістаньте локатори, врешті-решт - це кореневий тест, так?
Той самий код, що і вище, з цими змінами в:
css_locator = '#table2 tbody .dues'
xpath_locator = "//table[@id='table2']//tr/td[contains(@class,'dues')]"
І ось результат:
css total time 1000 repeats: 8.24s, per find: 8.24ms
xpath total time for 1000 repeats: 8.45s, per find: 8.45ms
Різниця 0,2 мілісекунди.
"Пошук елементів шляхом обходу":
css_locator = '#table1 tbody tr td:nth-of-type(4)'
xpath_locator = "//table[@id='table1']//tr/td[4]"
Результат:
css total time 1000 repeats: 9.29s, per find: 9.29ms
xpath total time for 1000 repeats: 8.79s, per find: 8.79ms
Цього разу це 0,5 мс (у зворотному напрямку xpath тут виявився "швидшим").
Отже, 5 років потому (кращі браузерні двигуни) і зосередившись лише на продуктивності локаторів (жодних дій, таких як сортування в інтерфейсі тощо), той самий тестовий стенд - практично немає різниці між CSS та XPath.
Отже, з xpath та css, кого з них вибрати для виконання? Відповідь проста - виберіть розташування за ідентифікатором .
Коротше кажучи, якщо ідентифікатор елемента унікальний (як це передбачається згідно специфікацій), його значення відіграє важливу роль у внутрішньому представленні DOM браузера, і, отже, зазвичай є найшвидшим.
Проте унікальні та постійні (наприклад, не автоматично згенеровані) ідентифікатори не завжди доступні, що підводить нас до "чому XPath, якщо є CSS?"
Перевага XPath
Чому, на думку продуктивності, картина xpath краща? Просто - універсальність та потужність.
Xpath - це мова, розроблена для роботи з XML-документами; як такий, він дозволяє набагато потужніші конструкції, ніж css.
Наприклад, навігація в будь-якому напрямку дерева - знайдіть елемент, а потім перейдіть до його бабусі та дідуся та знайдіть дитину, яка має певні властивості.
Це дозволяє вбудовані логічні умови - cond1 and not(cond2 or not(cond3 and cond4))
; вбудовані селектори - "знайти div, що має ці дочірні елементи з цими атрибутами, а потім переміщатися відповідно до нього".
XPath дозволяє здійснювати пошук на основі значення вузла (його тексту) - хоч би як це не сприймали, він дуже корисний, особливо в погано структурованих документах (відсутні певні атрибути, як динамічні ідентифікатори та класи - знайдіть елемент за його текстом зміст) .
Вступити в css, безумовно, простіше - можна почати писати селектори за лічені хвилини; але через пару днів використання потужність та можливості xpath швидко долає css.
І суто суб’єктивно - складний css читати набагато важче, ніж складний вираз xpath.
Outro;)
Нарешті, знову дуже суб’єктивно - якого вибрати?
ІМО не існує правильного чи неправильного вибору - вони є різними рішеннями однієї і тієї ж проблеми, і слід вибрати все, що більше підходить для роботи.
Будучи "шанувальником" XPath, я не соромлюсь використовувати у своїх проектах поєднання обох - чорт візьмі, іноді набагато швидше просто кинути CSS, якщо я знаю, що це зробить чудову роботу.