简体   繁体   English

如何在 selenium 中的 python 中访问具有相同 xpath 的第二个元素

[英]How do I access the 2nd element with the same xpath in python in selenium

What I mean is that the website I'm using has 2 dropmenus named province with the exact same id, so how do I tell python which dropmenu in particular I wanna select.我的意思是我正在使用的网站有 2 个名为省的下拉菜单,具有完全相同的 id,那么我如何告诉 python 我特别想选择哪个下拉菜单。 Of course this is assuming that the issue is that python always picks the first id it sees当然,这是假设问题在于 python 总是选择它看到的第一个 id

   from selenium import webdriver
   from selenium.webdriver.support.ui import Select

   # There are two dropmenu with the same xpath. first time it works fine 
   # 2nd time it throws an error about element not interactable 

   Prov = Select(web.find_element_by_xpath('//*[@id="province"]'))
   Prov.select_by_index(2)

def Start():
    # once opened it will fill in the confirm your age
    Day = Select(web.find_element_by_xpath('//*[@id="bday_day"]'))
    Day.select_by_index(2)
    Month = Select(web.find_element_by_xpath('//*[@id="bday_month"]'))
    Month.select_by_index(4)
    Month = Select(web.find_element_by_xpath('//*[@id="bday_year"]'))
    Month.select_by_index(24)
    Prov = Select(web.find_element_by_xpath('//*[@id="province"]'))
    Prov.select_by_index(5)
    Button = web.find_element_by_xpath('//*[@id="popup-subscribe"]/button')
    Button.click()

# have to go through select your birthday
Start()
# 2 seconds is enough for the website to load
time.sleep(2)
# this throws and error. 
Prov = Select(web.find_element_by_xpath('//*[@id="province"]'))
Prov.select_by_index(5)

Selenium has functions硒有功能

  • find_element_by_... without s in word element to get only first element find_element_by_...在 word element没有s只获取第一个元素
  • find_elements_by_... with s in word elements to get all elements find_elements_by_...在单词elements使用s来获取所有元素

Selenium doc: 4. Locating Elements¶ Selenium 文档: 4. 定位元素¶

So you can get all elements as list (even if there is only one element in HTML)因此,您可以将所有元素作为列表(即使 HTML 中只有一个元素)
(if there is no elements then you get empty list) (如果没有元素,那么你会得到空列表)

elements = web.find_elements_by_xpath('//*[@id="province"]')

and later slice it然后切片

first  = elements[0] 
second = elements[1] 

last   = elements[-1]

list_first_and_second = elements[:1] 

EDIT:编辑:

You can also try to slice directly in xpath like您也可以尝试直接在 xpath 中切片,例如
(it starts counting at one, not zero) (它从一开始计数,而不是零)

'//*[@id="province"][2]'

or maybe或者可能

'(//*[@id="province"])[2]'

but I never used it to confirm if it will work.但我从未用它来确认它是否有效。


BTW:顺便提一句:

All ID should have unique names - you shouldn't duplicate IDs.所有ID都应该有唯一的名称 - 您不应该重复 ID。

If you check documentation 4. Locating Elements¶ then you see that there is find_element_by_id without char s in word element - to get first and the only element with some ID - but there is no find_elements_by_id with char s in word elements - to get more then one element with some ID.如果您查看文档4. 定位元素find_element_by_id然后您会看到在 word element中有没有 char s find_element_by_id - 获取第一个也是唯一具有某些 ID 的元素 - 但没有find_elements_by_id在 word elements有 char s - 以获得更多然后一个元素有一些 ID。


EDIT:编辑:

Minimal working code with example HTML in code代码中带有示例 HTML 的最少工作代码

from selenium import webdriver
from selenium.webdriver.support.ui import Select

html = '''
<select id="province">
<option value="value_A">A</options>
<option value="value_B">B</options>
</select>
<select id="province">
<option value="value_1">1</options>
<option value="value_2">2</options>
</select>
'''

driver = webdriver.Firefox()
driver.get("data:text/html;charset=utf-8," + html)

all_elements = driver.find_elements_by_xpath('//*[@id="province"]')

first  = all_elements[0] 
second = all_elements[1] 

prov1 = Select(first)
prov2 = Select(second)

print('--- first ---')
for item in prov1.options:
    print('option:', item.text, item.get_attribute('value'))
for item in prov1.all_selected_options:
    print('selected:', item.text, item.get_attribute('value'))
    
print('--- second ---')
for item in prov2.options:
    print('option:', item.text, item.get_attribute('value'))
for item in prov2.all_selected_options:
    print('selected:', item.text, item.get_attribute('value'))

EDIT:编辑:

There are two province .有两个province

When you use find_element in Start then you get first province in popup - and you can fill it.当您在Start使用find_element ,您会在弹出窗口中获得第一个province - 您可以填写它。 When you click button then it closes this popup but it doesn't remove first province from HTML - it only hide it.当您单击按钮时,它会关闭此弹出窗口,但不会从 HTML 中删除第一个province - 它只会隐藏它。

Later when you use find_element you get again first province in hidden popup - and this time it is not visible and it can't use it - and this gives error.稍后,当您使用find_element您将再次在隐藏弹出窗口中获得第一个province - 这次它不可见且无法使用它 - 这会产生错误。 You have to use second province like in this example.您必须像在本例中一样使用第二个province

from selenium import webdriver
from selenium.webdriver.support.ui import Select
import time

def Start():
    
    # once opened it will fill in the confirm your age
    Day = Select(web.find_element_by_xpath('//*[@id="bday_day"]'))
    Day.select_by_index(2)
    Month = Select(web.find_element_by_xpath('//*[@id="bday_month"]'))
    Month.select_by_index(4)
    Month = Select(web.find_element_by_xpath('//*[@id="bday_year"]'))
    Month.select_by_index(24)

    # it uses first `province`
    Prov = Select(web.find_element_by_xpath('//*[@id="province"]'))
    Prov.select_by_index(5)
    Button = web.find_element_by_xpath('//*[@id="popup-subscribe"]/button')
    Button.click()

web = webdriver.Firefox()
web.get('https://www.tastyrewards.com/en-ca/contest/fritolaycontest/participate')

# have to go through select your birthday
Start()

# 2 seconds is enough for the website to load
time.sleep(2)

# `find_elements` with `s` - to get second `province`
all_province = web.find_elements_by_xpath('//*[@id="province"]')
second_province = all_province[1]

Prov = Select(second_province)
Prov.select_by_index(5)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM