Как вставить ссылку на элемент в строку xpath?

Учитывая ссылку на элемент пользовательского интерфейса, как мне «добавить» к нему строку, чтобы я мог найти ее следующий родственный элемент типа XCUIElementTypeStaticText?

Фреймворк, который я использую, содержит файл driver_helper.py.

В этом файле находятся методы find_element и find_elements, определенные как:

def find_element(self, locator: tuple) -> WebElement:
return self.driver.find_element(*locator)
def find_elements(self, locator: tuple) -> list[WebElement]:
return self.driver.find_elements(*locator)

Существует также файл selector_const.py, содержащий объявления для различных типов селекторов. Тот, который я использую специально для этого вопроса:

BY_XPATH = MobileBy.XPATH

В объектном файле экрана/страницы, над которым я работаю, я определяю кортеж self.CHECKBOXES = (sc.BY_XPATH, '//XCUIElementTypeButton[@name = "Square"]')

который я затем использую для создания этой переменной: checkboxes = self.driver_helper.find_elements(self.CHECKBOXES)

Я хочу найти родственный элемент для одного из флажков, но этот фрагмент кода:

checkboxes = self.driver_helper.find_elements(self.CHECKBOXES)
sibling = (
            sc.BY_XPATH,
            f'{checkboxes[0]}/following-sibling::XCUIElementTypeStaticText',
        )
test = self.driver_helper.find_element(sibling)
print("checkbox 0 sibling element text: " + str(test))

терпит неудачу с NoSuchElementError: An element could not be located on the page using the given search parameters. Я включил скриншот домена экрана, чтобы показать, что флажки действительно существуют и что рядом с ними есть XCUIElementTypeStaticText.

Домен экрана приложения iOS:

<XCUIElementTypeButton type = "XCUIElementTypeButton" name = "Square" label = "Square" enabled = "true" visible = "true" accessible = "true" x = "15" y = "428" width = "20" height = "21" index = "22"/>
<XCUIElementTypeStaticText type = "XCUIElementTypeStaticText" value = "checkbox 1 text" name = "checkbox 1 text" label = "checkbox 1 text" enabled = "true" visible = "true" accessible = "true" x = "43" y = "428" width = "308" height = "18" index = "23"/>
<XCUIElementTypeButton type = "XCUIElementTypeButton" name = "Square" label = "Square" enabled = "true" visible = "true" accessible = "true" x = "15" y = "478" width = "20" height = "21" index = "24"/>
<XCUIElementTypeStaticText type = "XCUIElementTypeStaticText" value = "checkbox 2 text" name = "checkbox 2 text" label = "checkbox 2 text" enabled = "true" visible = "true" accessible = "true" x = "43" y = "478" width = "260" height = "35" index = "25"/>
<XCUIElementTypeButton type = "XCUIElementTypeButton" name = "Square" label = "Square" enabled = "true" visible = "true" accessible = "true" x = "15" y = "542" width = "20" height = "21" index = "26"/>
<XCUIElementTypeStaticText type = "XCUIElementTypeStaticText" value = "checkbox 3 text" name = "checkbox 3 text" label = "checkbox 3 text" enabled = "true" visible = "true" accessible = "true" x = "43" y = "542" width = "333" height = "86" index = "27"/>
<XCUIElementTypeButton type = "XCUIElementTypeButton" name = "Square" label = "Square" enabled = "true" visible = "true" accessible = "true" x = "15" y = "657" width = "20" height = "21" index = "28"/>
<XCUIElementTypeStaticText type = "XCUIElementTypeStaticText" value = "checkbox 4 text" name = "checkbox 4 text" label = "checkbox 4 text" enabled = "true" visible = "true" accessible = "true" x = "43" y = "657" width = "320" height = "52" index = "29"/>
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
0
109
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Сохраните весь XPath в переменной:

main_element = "//*[@id = "submenu1"]/a[2]"

element = driver.find_element(By.XPATH, main_element)


siblingElement = main_element + "/following-sibling::td"

element2 = driver.find_element(By.XPATH, siblingElement)

Вы не можете вставить WebElement объект/ссылку в строку XPath, потому что выражение Xpath должно быть строкой, как вы сами упомянули.
Что вы можете сделать, так это найти другой элемент на основе существующего элемента.
Например, если вы хотите найти /following-sibling::td на основе существующего элемента, вы можете сделать это следующим образом:

element = driver.find_element(By.XPATH, '//*[@id = "submenu1"]/a[2]')
siblingElement = element.find_element(By.XPATH, './following-sibling::td')
  1. Во второй строке я применяю метод find_element к объекту element, а не к объекту driver.
  2. Выражение XPath начинается с точки ., чтобы уведомить, что этот относительный XPath связан с текущим узлом.
  3. find_element(By.XPATH, используется сейчас, а find_element_by_xpath устарело.
    UPD
    Если вы хотите найти родственные элементы списка элементов, вы можете сделать что-то вроде этого:
base_elements = driver.find_elements(By.XPATH, 'the_xpath_locator')
for element in base_elements:
    siblingElement = element.find_element(By.XPATH, './following-sibling::td')

Что, если я использую вызов findelements для хранения массива ссылок в переменной?

kevin 31.10.2022 06:03

В этом случае вам нужно будет перебрать список объектов, применяя подход, который я упомянул для каждого элемента в списке.

Prophet 31.10.2022 08:13

Я попытался передать жестко закодированное значение для целей тестирования, но до сих пор не нашел элемент. Я добавил более конкретную информацию к вопросу для большего контекста.

kevin 31.10.2022 19:53

В вашем обновленном вопросе не то, что я имел в виду. Пожалуйста, смотрите мой обновленный ответ

Prophet 31.10.2022 20:06

Спасибо вам за помощь. К сожалению, это тоже не сработало.

kevin 01.11.2022 00:48

Пожалуйста, поделитесь XML/HTML этого экрана (я понимаю, что это мобильное приложение), чтобы мы могли выполнить базовую отладку.

Prophet 01.11.2022 08:22

Хорошо, добавил XML/HTML экрана

kevin 01.11.2022 18:58
Ответ принят как подходящий

Если вы можете добавить методы в driver_helper.py, вы можете реализовать там метод, используя решение, представленное в этом ответе
Но если вы не можете этого сделать, вам нужно изменить код вашей переменной sibling. Теперь вы пытаетесь поместить элемент в XPATH, и это не может работать, поскольку вы помещаете объект в строку. Таким образом, обходной путь состоит в том, чтобы поместить туда строку XPATH, которую вы используете для поиска родительского элемента. Когда вы соберете все флажки в список, вы можете пройтись по ним и получить братьев и сестер следующим образом:

for i in range(len(checkboxes)):
    sibling = (sc.BY_XPATH, f'(//XCUIElementTypeButton[@name = "Square"])[{i+1}]/following-sibling::XCUIElementTypeStaticText')
    test = self.driver_helper.find_element(sibling)
    print(f"checkbox {i+1} sibling element text: {test.text}")

Те же результаты. Я попытался изменить как [{i+1}], так и [{i}] в качестве переданного в индексе, и оба потерпели неудачу. ============== для i в диапазоне (len (флажки)): sibling = (sc.BY_XPATH, f'(//XCUIElementTypeButton[@name = "Square"])[{i +1}]/XCUIEleme‌​ntTypeStaticText') test = self.driver_helper.find_element(sibling) print(f"checkbox {i+1} sibling element text: {test.text}")

kevin 01.11.2022 18:28

Извините, я забыл о важной части кода: following-sibling::. Сейчас я отредактировал код. Можешь попробовать еще раз?

Eugeny Okulik 01.11.2022 20:13

Это сработало. Тай очень! Я заметил, что вы пропустили этот небольшой фрагмент ранее (часть next-sibling::), но по какой-то причине, когда я попытался добавить его самостоятельно, он все еще терпел неудачу. При этом я скопировал ваш недавно отредактированный ответ, и это было успешно. Я награжу тебя наградой, как только смогу. Еще раз спасибо.

kevin 01.11.2022 22:18

Другие вопросы по теме