Продолжение перевода неофициальной документации Selenium для Python.
Перевод сделан с разрешения автора Baiju Muthukadan.
Оригинал можно найти .
1. Установка
2. Первые Шаги
3. Навигация
4. Поиск Элементов
5. Ожидания
6. Объекты Страницы
7. WebDriver API
8. Приложение: Часто Задаваемые Вопросы
Помимо общедоступных (public) методов, перечисленных выше, существует два приватных (private) метода, которые при знании указателей объектов страницы могут быть очень полезны: find_element and find_elements.
Пример использования:
From selenium.webdriver.common.by import By
driver.find_element(By.XPATH, "//button")
driver.find_elements(By.XPATH, "//button")
Для класса By доступны следующие атрибуты:
ID = "id" XPATH = "xpath" LINK_TEXT = "link text" PARTIAL_LINK_TEXT = "partial link text" NAME = "name" TAG_NAME = "tag name" CLASS_NAME = "class name" CSS_SELECTOR = "css selector"
Login_form = driver.find_element_by_id("loginForm")
Для примера, рассмотрим следующий исходный код страницы:
Username = driver.find_element_by_name("username")
password = driver.find_element_by_name("password")
Следующий код получит кнопку “Login”, находящуюся перед кнопкой “Clear”:
Continue = driver.find_element_by_name("continue")
Одно из веских оснований использовать XPath заключено в наличии ситуаций, когда вы не можете похвастать пригодными в качестве указателей атрибутами, такими как id или name, для элемента, который вы хотите получить. Вы можете использовать XPath для поиска элемента как по абсолютному пути (не рекомендуется), так и по относительному (для элементов с заданными id или name). XPath указатели в том числе могут быть использованы для определения элементов с помощью атрибутов отличных от id и name.
Абсолютный путь XPath содержит в себе все узлы дерева от корня (html) до необходимого элемента, и, как следствие, подвержен ошибкам в результате малейших корректировок исходного кода страницы. Если найти ближайщий элемент с атрибутами id или name (в идеале один из элементов-родителей), можно определить искомый элемент, используя связь «родитель-подчиненный». Эти связи будут куда стабильнее и сделают ваши тесты устойчивыми к изменениям в исходном коде страницы.
Для примера, рассмотрим следующий исходный код страницы:
Login_form = driver.find_element_by_xpath("/html/body/form") login_form = driver.find_element_by_xpath("//form") login_form = driver.find_element_by_xpath("//form[@id="loginForm"]")
Username = driver.find_element_by_xpath("//form") username = driver.find_element_by_xpath("//form[@id="loginForm"]/input") username = driver.find_element_by_xpath("//input[@name="username"]")
Clear_button = driver.find_element_by_xpath("//input[@name="continue"][@type="button"]") clear_button = driver.find_element_by_xpath("//form[@id="loginForm"]/input")
Для примера, рассмотрим следующий исходный код страницы:
Are you sure you want to do this?
Continue CancelContinue_link = driver.find_element_by_link_text("Continue") continue_link = driver.find_element_by_partial_link_text("Conti")
Для примера, рассмотрим следующий исходный код страницы:
Site content goes here.
Heading1 = driver.find_element_by_tag_name("h1")
Для примера, рассмотрим следующий исходный код страницы:
Site content goes here.
Content = driver.find_element_by_class_name("content")
Для примера, рассмотрим следующий исходный код страницы:
Site content goes here.
Content = driver.find_element_by_css_selector("p.content")
На Sauce Labs есть
XPath является одним из ключевых моментов на дороге к пониманию XSLT. И на первых порах хочется получить какой-нибудь простой способ поэкспериментировать с ним, чтобы в деталях разобраться, как он работает. Способа такого, впрочем, не наблюдается. Приходится или качать совсем не бесплатные XML/XSLT редакторы, или довольствоваться статичными картинками с zvon.org . Может быть, я плохо искал. Но с моей колокольни все обстоит именно так. И когда передо мной в очередной раз встала задача «Объяснить XSLT», в голове и родилась идея крохотного сервиса. После того, как все заработало, было решено выкатить его для всеобщего пользования: наверняка не я один сталкивался с похожими проблемами.
Впрочем, чего разглядывать картинки, можно пойти и пощупать это все живьем .
Сервис, впрочем, может пригодиться не только в образовательных целях. Заковыристые запросы очень часто бывает удобно наблюдать визуально. Со своей задачей сервис справился. Буду рад, если поможет кому-нибудь еще.
XML имеет древовидную структуру. В документе всегда имеется корневой элемент (инструкция к дереву отношения не имеет). У элемента дерева всегда существуют потомки и предки, кроме корневого элемента, у которого предков нет, а также тупиковых элементов (листьев дерева), у которых нет потомков. Каждый элемент дерева находится на определенном уровне вложенности (далее - «уровень»). У элементов на одном уровне бывают предыдущие и следующие элементы.
Это очень похоже на организацию каталогов в файловой системе, и строки XPath, фактически, - пути к «файлам» - элементам.
Например, рассмотрим XHTML документ:
<html > <body > <div > Первый слой <span > блок текста в первом слое</ span > </ div > <div > Второй слой</ div > <div > Третий слой <span class = "text" > первый блок в третьем слое</ span > <span class = "text" > второй блок в третьем слое</ span > <span > третий блок в третьем слое</ span > </ div > <img / > </ body > </ html >
XPath-путь /html/body/*/span[@class] (полный синтаксис имеет вид /child::html/child::body/child::*/child::span ) будет соответствовать в нём двум элементам исходного документа - первый блок в третьем слое и второй блок в третьем слое .
Путь делится на шаги адресации, которые разделяются символом «косая черта» / . Каждый шаг адресации состоит из трех частей:
Анализ ведется слева направо. Если первый символ это / , то путь адресации считается абсолютным (то есть от корня документа). При этом за узел контекста на первом шаге берется корневой элемент (html). Контекст - это некая точка отсчета, относительно которой рассчитывается следующий шаг адресации. Поэтому на каждом шаге адресации мы получаем новый набор узлов документа, и этот набор становится контекстом для следующего шага адресации.
На втором шаге адресации (child::body) контекстом становится html элемент. Ось child:: говорит о том, что необходимо найти все непосредственные потомки элемента html, а условие проверки body говорит о том, что в формируемый набор элементов нужно включить все узлы с именем body. В ходе второго шага адресации получаем набор узлов, состоящий всего из одного элемента body, который и становится элементом контекста для третьего шага.
Третий шаг адресации: child::* . Ось child:: собирает все непосредственные потомки элемента body, а условие проверки * говорит о том, что в формируемый набор нужно включить элементы основного типа с любым именем. В ходе этого шага получаем набор узлов, состоящий из трех элементов div и одного элемента img.
Четвёртый шаг адресации: child::span . Теперь контекстом является набор из четырёх элементов. И следующий набор узлов создается в четыре прохода (за четыре итерации). При первой итерации узлом контекста становится первый div. Согласно заданной оси child:: и правилу проверки span, в набор включаются непосредственные потомки div-а, имя которых равно span. При второй итерации в набор ничего добавлено не будет, так как у второго div нет потомков. Третья итерация добавит в набор сразу три элемента span, а четвёртая ничего не добавит, так как у элемента img нет потомков. Итак, в ходе проверки получен набор узлов, состоящий из четырёх элементов span. Это и будет контекстом для последующей обработки.
Следующего шага нет, поэтому будет производиться фильтрация отобранного набора. В этом и состоит отличие предикатов от шагов адресации. На каждом шаге адресации получаем новый набор, отталкиваясь от контекста, полученного на предыдущем шаге. В ходе же обработки предиката новый набор получается из текущего методом фильтрации, когда из набора исключаются узлы, не прошедшие условие проверки. В данном случае ось attribute:: говорит о необходимости проверить, если ли у узлов контекста атрибуты, а условие class требует оставить лишь те узлы, у которых задан атрибут с именем class. Фильтрация происходит за четыре итерации, но в окончательный набор попадают только два элемента span.
Оси - это база языка XPath.
Существуют сокращения для некоторых осей, например:
Дополнением к базе является набор функций, которые делятся на 5 групп:
Стандарты Консорциума Всемирной паутины | |
---|---|
Рекомендации |
Canonical XML CDF CSS DOM Geolocation API HTML ITS MathML OWL P3P PLS RDF (Schema) SISR SKOS SMIL SOAP SRGS SSML SVG SPARQL Timed Text VoiceXML WSDL XForms XHTML XHTML+RDFa XInclude XLink XML (Base Encryption Events Information Set namespace Schema Signature) XPath / 1.0 / 2.0 XPointer XProc XQuery XSL XSL-FO XSLT (элементы) XUP |
Примечания |
XAdES XHTML+SMIL |
Рабочие проекты | |
Guidelines |
Web Content Accessibility Guidelines |
Initiative |
Multimodal Interaction Activity Markup Validation Service Web Accessibility Initiative |
Сегодня мы плотно рассмотрим тему использования XPath вместе с PHP. Вы увидите на примерах, как XPath значительно сокращает количество кода. Рассмотрим использование запросов и функций в XPath.
В начале, предоставлю вам два типа документов: DTD и XML, на примере которых мы рассмотрим функционирование PHP DOM XPath. Вот как они выглядят:
Простой синтаксис XPath позволяет обращаться к элементам XML документа. Наиболее простым способом, можно прописать путь к желаемому элементу. Используя XML документ, поданный выше, следующий XPath запрос возвратит коллекцию текущих элементов, находящихся в элементе book:
//library/book
Вот так! Два слеша впереди определяют корневой элемент документа, а один слеш производит переход к дочернему элементу book. Это просто и быстро, не так ли?
Но что, если вы хотите выбрать определенный элемент book из множества? Давайте предположим, что вам нужны книги «Определенного автора». XPath запрос для этого будет следующим:
//library/book/author/..
Вы можете использовать text() в квадратных скобках для сравнения значения узла. Также «/..» означает, что мы хотим использовать родительский элемент (т. е. возвращаемся на один узел выше).
XPath запросы осуществляются с помощью одной или двух функций: query() и evaluate() . Обе формируют запрос, но разница в возвращаемом результате. query() всегда будет возвращать DOMNodeList , в отличии evaluate() будет возвращать текстовый результат, если это возможно. Для примера, если ваш XPath запрос будет возвращать количество книг написанных определенным автором, тогда query() возвратит пустой DOMNodeList, evaluate() просто возвратит число, вы можете использовать это непосредственно для получения данных из узла.
Давайте рассмотрим простой пример, который будет возвращать количество книг написанных конкретным автором. Первый метод мы рассмотрим так, как мы всегда делаем, без использования XPath. Сейчас вы поймете, как это делается без XPath и насколько это проще делать с XPath.
domDocument->getElementsByTagName("author"); foreach ($elements as $element) { if ($element->nodeValue == $author) { $total++; } } return $number; }
Следующий метод возвращает такой же результат, но используется XPath для выбора тех книг, которые написанные определенным автором.
domDocument); $result = $xpath->query($query); return $result->length; }
Заметьте, нам не нужно повторно проверять значение каждого элемента, чтобы определить, каким автором написана каждая книга. Но мы можем более упростить код, используя XPath функцию count() , чтобы подсчитать содержимое элементов этого пути.
domDocument); return $xpath->evaluate($query); }
Мы можем получить информацию, которую нам нужно, с помощью одной строки XPath запроса. Нет необходимости создавать множество PHP фильтров. Это наиболее простой и быстрый способ написать этот функционал!
Заметьте, что evaluate() использовался в последнем примере. Это потому что функция count() возвращает текстовый результат. Используя query(), возвратиться DOMNodeList, но он будет пустым.
XPath стоит использовать, не только потому что это делает ваш PHP код проще, это также дает преимущество в скорости выполнения кода. Я заметил, что первая версия была на 30% быстрее в среднем, по сравнению со второй. Но третья на 10% быстрее первой. Конечно же, это зависит от вашего сервера и запросов, которые используете. Использование XPath в его чистом виде, дает величайшие результаты в скорости и простоте написания кода.
Вот несколько функций, которые могут использоваться с XPath. Также вы найдете множество ресурсов, которые детально рассматривают каждую доступную функцию. Если вам нужно вычислять DOMNodeList или сравнивать nodeValue (значение узла), можно найти подходящую XPath функцию, которая исключит использование лишнего PHP кода.
Вы уже это знаете на примере count() функции. Давайте воспользуемся функцией id(), для получение названий книг с заданными ISBN. Для этого нужно использовать следующее XPath выражение:
id("isbn1234 isbn1235")/title
Заметьте, значения, которые вы ищете не стоит заключать в скобки, только разделите их пробелами. Также не вздумайте влепить запятую:
domDocument); $result = $xpath->query($query); $books = array(); foreach ($result as $node) { $book = array("title" => $booknode->nodeValue); $books = $book; } return $books; }
Обработка сложных функций в XPath невероятно проста.
Иногда вам необходимо будет больше функциональности, которую не могут предоставить стандартные функции XPath. К счастью, PHP DOM позволяет взаимодействовать собственным функциям PHP с XPath запросами.
Давайте рассмотрим пример, который возвращает количество слов в названии книги. В этой простейшей функции, мы напишем следующее:
domDocument); $result = $xpath->query($query); $title = $result->item(0)->getElementsByTagName("title") ->item(0)->nodeValue; return str_word_count($title); }
Но, мы также можем включить функцию str_word_count() непосредственно в XPath запрос. Это можно сделать с помощью нескольких шагов. Прежде всего, нам нужно зарегистрировать namespase с XPath объектом. PHP функции в XPath запросах вызываются с помощью строки «php:functionString», после чего прописывается имя желаемой функции. Также, namespace более подробно рассматривается на http://php.net/xpath. Другие значения namespace будут выдавать ошибку. После этого нам нужно вызвать registerPHPFunctions(). Эта функция сообщает PHP, что когда идет обращение через namespace «php:», этот вызов будет обрабатывать именно PHP.
Примерный синтаксис вызова функций будет следующим:
php:functionString("nameoffunction", arg, arg...)
Давайте совместим все это вместе в следующем примере функции getNumberOfWords():
domDocument); //регистрируем php namespace $xpath->registerNamespace("php", "http://php.net/xpath"); //теперь php функции могут вызываться в xpath запросах $xpath->registerPHPFunctions(); $query = "php:functionString("str_word_count",(//library/book[@isbn = "$isbn"]/title))"; return $xpath->evaluate($query); }
Заметьте, что вам не нужно вызывать XPath функцию text() чтобы получить текст узла. Метод registerPHPFunctions() делает это автоматизированным. Хотя, следующий пример строки кода также будет валидным:
php:functionString("str_word_count",(//library/book[@isbn = "$isbn"]/title))
Регистрирование PHP функций не ограничено для функций, которые включены в PHP. Вы можете определить свои собственные функции и использовать их внутри XPath. Единственное отличие в том, что придется использовать «php:function» вместо «php:functionString».
Давайте напишем функцию, которая будет за пределами класса, для демонстрации базовой функциональности. Функция, которую мы будем использовать, возвращает книги автора «George Orwell». Она должна возвращать true для каждого узла, который вы хотите включить в запрос.
nodeValue == "George Orwell"; }
Аргумент, который передается в функцию, является массивом DOM элементов. Эта функция проходит по массиву и определяет нужные элементы, после чего включает их в DOMNodeList. В этом примере, испытываемый узел был /book, также мы использовали /author для определения нужных элементов.
Теперь мы можем создать функцию getGeorgeOrwellBooks():
domDocument); $xpath->registerNamespace("php", "http://php.net/xpath"); $xpath->registerPHPFunctions(); $query = "//library/book1"; $result = $xpath->query($query); $books = array(); foreach($result as $node) { $books = $node->getElementsByTagName("title") ->item(0)->nodeValue; } return $books; }
Если функция compare() статическая, тогда вам нужно внести поправку в XPath запрос:
//library/book
Говоря по правде, вся эта функциональность могла быть реализована с помощью чистого XPath кода. Но, пример показывает, как можно расширять XPath запросы и делать их более комплексными.
XPath - это отличный способ сократить количество кода и повысить его обработку, при работе с XML. Дополнительная функциональность PHP DOM позволяет вам расширить XPath функции. Это реально полезная штука, если вы будете ее использовать и углубляться в специфику, вам придется меньше и меньше писать кода.
я решил озадачиться статьёй про XPath. Зачем мне нужен XPath? У меня есть задача организовать препроцессинг данных: Есть, например, набор операций, описываемых XML документом. Каждая операция — это либо веб-запрос либо запрос к базе данных. Мне необходимо поля из предшествующих операций, подставлять в последующие операции… Примерно так.
Попробую выразиться иначе. XPath — это язык запросов к XML, позволяющий выбирать из XML подмножества данных: как отдельные значения тегов и атрибутов, так и целые наборы значений. XPath запрос + соотвествующий API превращают любой XML документ в подобие базы данных, из которой можно делать выборки.
В моём случае, мне нужно было выбирать из XML некоторые поля, чтобы формировать другие XML документы, содержащие указанные поля. Конечно такая задача может быть решена и без XPath. Но тогда логика будет зашита в код программы. А XPath позволяет логику поиска внутри XML документов вынести во внешние конфигурационные данные. Т.е. для моей программы входными данными являются и XML документы и XPath выражения. В таком сочетании и проявляется мощь XPath.
P.S. Впоследствии, в дополнение к теоретической части, я написал пару постов с описанием практического применения XPath на Java:
Это предисловие. Приступаем к изучению. От добра-добра не ищут. На предмет XML-технологий пока самый интересный сайт: w3schools.org. Поэтому просто перевожу XPath tutorial оттуда.
XPath используется для навигации по элементам и атрибутам XML документа. XPath занимает главенствующее место среди W3C XSLT стандартов. XQuery и XPointer — оба базируются на XPath expressions.
Что есть XPath?
XPath Path Expressions
XPath использует path expressions для выбора узлов или наборов узлов в XML документе. Path expressions сильно напоминают пути, которые вы используете при работе с традиционными компьютерными файловыми системами.
XPath Standard Functions
XPath включает более 100 встроенных функций. Эти функции для строковых значений, цифровых значений, сравнения времени и дат, манипуляции узлами и QName manipulation, манипуляции последовательностью, работы с boolean значениями и другие.