Я собираюсь поддержать непопулярное мнение тегов SO selenium о том, что 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, какой из двух выбрать для повышения производительности? Ответ прост - выбирайте локацию по id .
Короче говоря, если идентификатор элемента уникален (как и должно быть в соответствии со спецификациями), его значение играет важную роль во внутреннем представлении 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, если я знаю, что он отлично справится со своей работой.