Python с Selenium — не удается найти и щелкнуть этот конкретный элемент из-за рандомизации его местоположения на сайте.

Я создавал инструмент, который играет в онлайн-игру с использованием python 2.7 и селена, и очень застрял на одном конкретном элементе, который мне нужно выбрать.

Пользовательский интерфейс выглядит следующим образом:

1   2   3
a   d   g
b   e   h
c   f   i

Цифры один, два и три представляют собой выпадающее меню, при нажатии на которое открываются буквы. Каждый вариант представляет другой результат. Проблема в том, что в начале каждой игры позиции цифр и букв рандомизируются. В коде селектор css каждой кнопки помечен, например, как «#action-1 > button:nth-child(1)», как в «первой кнопке», но «первая кнопка» будет отличаться в каждой игре.

Я безуспешно пытался выполнить поиск по тексту ссылки, xpath и CSS-селектору.

Если это помогает, нажатие «копировать внешний html» дает это:

<button class="ng-binding" ng-click="subBtn($event)" ng-class="{disabled : !state.chapterStart || state.btns.indexOf(btn.action) != -1}" ng-disabled="!state.chapterStart || state.btns.indexOf(btn.action) != -1">Wait and See What They Do</button>

Часть «Подождите и посмотрите, что они делают» - это то, что говорит кнопка, и то, как вы знаете, что нажимать, но я не могу найти элемент по этому.

Копирование xpath приводит к //*[@id="action-1"]/button, что снова не очень полезно, потому что сказать ему щелкнуть, что было бы просто сказать "нажмите кнопку, которая находится в первой позиции" , и каждый раз меняется. Я добавил команды long time.sleep() для тестирования, страница определенно загружается полностью, так что это не проблема.

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


person FreshElephants    schedule 19.07.2016    source источник
comment
Не могли бы вы скинуть ссылку на онлайн-игру? Я хотел бы увидеть это... это звучит как интересная проблема.   -  person JeffC    schedule 19.07.2016
comment
К сожалению, он все еще находится в разработке и на данный момент размещен на частном сервере. Я могу дать вам конкретный фрагмент кода, если это поможет.   -  person FreshElephants    schedule 19.07.2016


Ответы (1)


Если вы хотите найти элемент по содержащемуся в нем тексту, вы можете использовать XPath. Вы заявили, что пробовали XPath, но никаких подробностей не было дано. Вы пробовали ниже? Это должно работать с учетом предоставленного вами HTML.

//button[text()='Wait and See What They Do']

Чтобы прочитать этот XPath... найдите любого потомка //, который является тегом BUTTON, который имеет атрибут [], где текст, содержащийся в элементе, равен строке поиска, text()=''.

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

//button[@class='ng-binding']

Я обнаружил (и другие тоже), что XPath обычно медленнее, чем другие методы определения местоположения. Из-за этого я обычно предпочитаю By.Id, когда он доступен, а не By.CssSelector. Оба они значительно быстрее, чем XPath. Я сохраняю XPath для таких вещей, как поиск текста в элементе или поиск относительных элементов (CSS может это делать, но он далеко не так эффективен, как XPath).

Примеры XPath

person JeffC    schedule 19.07.2016
comment
Это вернуло ошибку: InvalidSelectorError: невозможно найти элемент с выражением xpath //button[text()='Подождите и посмотрите, что они делают'] из-за следующей ошибки: SyntaxError: выражение не является допустимым выражением. Когда я пытаюсь просто скопировать xpath с chrome, он просто дает //*[@id=action-1]/button, и просто выбирает кнопку, которая оказывается в первой позиции... Я чувствую, что эта проблема будет сложнее взломать, чем я думал. - person FreshElephants; 19.07.2016
comment
Если это поможет, я использую команду browser.find_element_by_xpath(//button[text()='Подождите и посмотрите, что они делают']).click() - person FreshElephants; 19.07.2016
comment
Это действительно странно. Я думал, может быть, вы что-то опечатались, но код выглядит хорошо. Если я вставлю $x("//button[text()='Wait and See What They Do']") в консоль разработчика Chrome, это не даст мне ошибку, что это недопустимый XPath. - person JeffC; 19.07.2016
comment
Возможно ли, что вам нужно подождать? Возможно, элемент не доступен сразу, но это все равно не объясняет, почему вы получаете SyntaxError. - person JeffC; 19.07.2016
comment
Когда я использовал кнопку xpath //*[@id=action-1]/, она работала отлично, поэтому я просто предположил, что время не является проблемой. Добавление ожидания к вашему исправлению сработало отлично !!! Я не могу отблагодарить тебя в достаточной мере, черт возьми! Вы не возражаете, если я спрошу, как вы нашли этот xpath в том конкретном фрагменте кода, который я вам дал? На самом деле я не уверен, как прочитать xpath и понять это, я просто копировал все, что было доступно. Еще раз, святое дерьмо! Большое спасибо! - person FreshElephants; 19.07.2016
comment
Я давно занимаюсь автоматизацией. Совсем недавно я начал использовать Selenium и столкнулся с XPaths. Моя первая реакция была отрицательной, поэтому я держался подальше от них и использовал в основном селекторы CSS, но есть некоторые вещи, такие как этот пример поиска текста внутри элемента, который может сделать только XPath. Итак... короче говоря, я больше изучаю XPath. Я читаю статьи XPath и много гуглю. Я также задаю вопросы здесь, на SO, и вижу много всего, поэтому я учусь на ходу. Мне определенно еще многое предстоит узнать о XPaths... - person JeffC; 19.07.2016
comment
Я обновил свой ответ, чтобы дать немного больше объяснений того, как читать XPath, а также некоторые ссылки, которые вы можете проверить. - person JeffC; 19.07.2016
comment
Если вы нашли этот ответ полезным, пожалуйста, проголосуйте за него. Если это ответило на ваш вопрос, пожалуйста, примите его как ответ. Прочтите это для получения дополнительной информации о том, как и зачем голосовать и принимать ответ. - person JeffC; 19.07.2016
comment
Отметил это как ответ, видимо, у меня еще недостаточно репутации, чтобы публично проголосовать за него. Тем не менее сделал, спасибо за помощь! - person FreshElephants; 20.07.2016