¿Cómo esperar a que se procese una lista desplegable antes de pasar a la siguiente?

Tener un problema con los menús desplegables en mi selenium (python). En esta página, lo que sucede es que al seleccionar una opción desplegable, procesará la selección, haciendo que las otras opciones no se puedan seleccionar hasta que el proceso haya finalizado. Estoy tratando de decir en mi script que espere hasta que una lista desplegable haya procesado su opción antes de pasar a la siguiente, pero simplemente está colgando. ¿Cómo puedo hacer que espere a que la opción se procese en un menú desplegable antes de pasar al siguiente menú desplegable?

A continuación es lo que he intentado:

#Meal details try: pax_one_ob_meal = Select(driver.find_element_by_id("ctl00_MainContent_InFlightMeal_PassengerGridView_ctl02_mealsDropDown")) pax_one_ob_meal.select_by_index(0) wait.until(EC.element_to_be_clickable((By.ID, "ctl00_MainContent_InFlightMeal_PassengerGridView_ctl02_mealsDropDownIn"))) pax_one_ib_meal = Select(driver.find_element_by_id("ctl00_MainContent_InFlightMeal_PassengerGridView_ctl02_mealsDropDownIn")) pax_one_ib_meal.select_by_index(2) wait.until(EC.element_to_be_clickable((By.ID, "ctl00_MainContent_InFlightMeal_PassengerGridView_ctl03_mealsDropDown"))) pax_two_ob_meal = Select(driver.find_element_by_id("ctl00_MainContent_InFlightMeal_PassengerGridView_ctl03_mealsDropDown")) pax_two_ob_meal.select_by_index(1) wait.until(EC.element_to_be_clickable((By.ID, "ctl00_MainContent_InFlightMeal_PassengerGridView_ctl03_mealsDropDownIn"))) pax_two_ib_meal = Select(driver.find_element_by_id("ctl00_MainContent_InFlightMeal_PassengerGridView_ctl03_mealsDropDownIn")) pax_two_ib_meal.select_by_index(1) wait.until(EC.element_to_be_clickable((By.ID, "ctl00_MainContent_InFlightMeal_PassengerGridView_ctl04_mealsDropDown"))) pax_three_ob_meal = Select(driver.find_element_by_id("ctl00_MainContent_InFlightMeal_PassengerGridView_ctl04_mealsDropDownt")) pax_three_ob_meal.select_by_index(2) wait.until(EC.element_to_be_clickable((By.ID, "ctl00_MainContent_InFlightMeal_PassengerGridView_ctl04_mealsDropDownIn"))) pax_three_ib_meal = Select(driver.find_element_by_id("ctl00_MainContent_InFlightMeal_PassengerGridView_ctl04_mealsDropDownIn")) pax_three_ib_meal.select_by_index(1) wait.until(EC.element_to_be_clickable((By.ID, "ctl00_MainContent_InFlightMeal_PassengerGridView_ctl05_mealsDropDown"))) pax_four_ob_meal = Select(driver.find_element_by_id("ctl00_MainContent_InFlightMeal_PassengerGridView_ctl05_mealsDropDown")) pax_four_ob_meal.select_by_index(0) wait.until(EC.element_to_be_clickable((By.ID, "ctl00_MainContent_InFlightMeal_PassengerGridView_ctl05_mealsDropDownIn"))) pax_four_ib_meal = Select(driver.find_element_by_id("ctl00_MainContent_InFlightMeal_PassengerGridView_ctl05_mealsDropDownIn")) pax_four_ib_meal.select_by_index(1) 

Puede visitar la página www.jet2.com y cargar el guión a continuación para ver lo que estoy viendo (está en la página de comidas, ya que tengo problemas con las opciones desplegables de comidas). Después de reservar sus asientos, tendrá que hacer clic manualmente en el botón “Continuar” cuando aparezca el mensaje “usted ha reservado sus asientos” cuando todavía estoy tratando de averiguar cómo hacerlo.

 from selenium import webdriver from selenium.common.exceptions import NoSuchElementException from selenium.webdriver import ActionChains from selenium.webdriver.common.by import By from selenium.webdriver.support.select import Select from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from datetime import datetime, timedelta def select_date(calendar, mininum_date=None): try: # check if "Your Date" is there your_date_elm = calendar.find_element_by_class_name("your-date") your_date = your_date_elm.get_attribute("data-date") print("Found 'Your Date': " + your_date) your_date_elm.click() # check if your_date against the minimum date if given your_date = datetime.strptime(your_date, "%Y-%m-%d") if mininum_date and your_date  p").text) try: if mininum_date: flight_date_elms = calendar.find_elements_by_class_name("flights") flight_date_elm = next(flight_date_elm for flight_date_elm in flight_date_elms if datetime.strptime(flight_date_elm.get_attribute("data-date"), "%Y-%m-%d") >= mininum_date) else: flight_date_elm = calendar.find_element_by_class_name("flights") except (StopIteration, NoSuchElementException): calendar.find_element_by_partial_link_text("Next month").click() # if found - print out the date, click and exit the loop if flight_date_elm: flight_date = flight_date_elm.get_attribute("data-date") print("Found 'Flight Date': " + flight_date) flight_date_elm.click() break return datetime.strptime(flight_date, "%Y-%m-%d") FROM = "Leeds Bradford" TO = "Antalya" PAX1_FORENAME = "Dad" PAX2_FORENAME = "Mum" PAX3_FORENAME = "Son" PAX4_FORENAME = "Daughter" PAX5_FORENAME = "Baby" PAX_SURNAME = "Test" driver = webdriver.Firefox() #driver = webdriver.Chrome() driver.get("http://www.jet2.com") driver.maximize_window() wait = WebDriverWait(driver, 20) actions = ActionChains(driver) # wait for the page to load wait.until(EC.presence_of_element_located((By.ID, "departure-airport-input"))) # fill out the form return_flight = driver.find_element_by_id('return-flight-selector').click() depart_from = driver.find_element_by_id("departure-airport-input").send_keys(FROM) wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, "#ui-id-1 .ui-menu-item"))).click() go_to = driver.find_element_by_id("destination-airport-input").send_keys(TO) wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, "#ui-id-2 .ui-menu-item"))).click() # select depart date datepicker = driver.find_element_by_id("departure-date-selector") actions.move_to_element(datepicker).click().perform() # find the calendar, month and year picker and the current date calendar = driver.find_element_by_id("departureDateContainer") month_picker = Select(calendar.find_element_by_class_name("ui-datepicker-month")) year_picker = Select(calendar.find_element_by_class_name("ui-datepicker-year")) current_date = calendar.find_element_by_class_name("ui-datepicker-current-day") # printing out current date month = month_picker.first_selected_option.text year = year_picker.first_selected_option.text print("Current departure date: {day} {month} {year}".format(day=current_date.text, month=month, year=year)) # see if we have an available date in this month try: next_available_date = current_date.find_element_by_xpath("following::td[@data-handler='selectDay' and ancestor::div/@id='departureDateContainer']") print("Found an available departure date: {day} {month} {year}".format(day=next_available_date.text, month=month, year=year)) next_available_date.click() except NoSuchElementException: # looping over until the next available date found while True: # click next, if not found, select the next year try: calendar.find_element_by_class_name("ui-datepicker-next").click() except NoSuchElementException: # select next year year = Select(calendar.find_element_by_class_name("ui-datepicker-year")) year.select_by_visible_text(str(int(year.first_selected_option.text) + 1)) # reporting current processed month and year month = Select(calendar.find_element_by_class_name("ui-datepicker-month")).first_selected_option.text year = Select(calendar.find_element_by_class_name("ui-datepicker-year")).first_selected_option.text print("Processing {month} {year}".format(month=month, year=year)) try: next_available_date = calendar.find_element_by_xpath(".//td[@data-handler='selectDay']") print("Found an available departure date: {day} {month} {year}".format(day=next_available_date.text, month=month, year=year)) next_available_date.click() break except NoSuchElementException: continue # select return date datepicker = driver.find_element_by_id("return-date-selector") actions.move_to_element(datepicker).click().perform() # find the calendar, month and year picker and the current date calendar = driver.find_element_by_id("returnDateContainer") month_picker = Select(calendar.find_element_by_class_name("ui-datepicker-month")) year_picker = Select(calendar.find_element_by_class_name("ui-datepicker-year")) current_date = calendar.find_element_by_class_name("ui-datepicker-current-day") # printing out current date month = month_picker.first_selected_option.text year = year_picker.first_selected_option.text print("Current return date: {day} {month} {year}".format(day=current_date.text, month=month, year=year)) # see if we have an available date in this month try: next_available_date = current_date.find_element_by_xpath("following::td[@data-handler='selectDay' and ancestor::div/@id='returnDateContainer']") print("Found an available return date: {day} {month} {year}".format(day=next_available_date.text, month=month, year=year)) next_available_date.click() except NoSuchElementException: # looping over until the next available date found while True: # click next, if not found, select the next year try: calendar.find_element_by_class_name("ui-datepicker-next").click() except NoSuchElementException: # select next year year = Select(calendar.find_element_by_class_name("ui-datepicker-year")) year.select_by_visible_text(str(int(year.first_selected_option.text) + 1)) # reporting current processed month and year month = Select(calendar.find_element_by_class_name("ui-datepicker-month")).first_selected_option.text year = Select(calendar.find_element_by_class_name("ui-datepicker-year")).first_selected_option.text print("Processing {month} {year}".format(month=month, year=year)) try: next_available_date = calendar.find_element_by_xpath(".//td[@data-handler='selectDay']") print("Found an available return date: {day} {month} {year}".format(day=next_available_date.text, month=month, year=year)) next_available_date.click() break except NoSuchElementException: continue #select adults adults = Select(driver.find_element_by_id("adults-number")) adults.select_by_visible_text("2") #select children children = Select(driver.find_element_by_id("children-number")) children.select_by_visible_text("2") #children ages child_one = Select(driver.find_element_by_id("childSelect1")) child_one.select_by_visible_text("4") child_two = Select(driver.find_element_by_id("childSelect2")) child_two.select_by_visible_text("6") confirm = driver.find_element_by_link_text("Confirm") confirm.click() #select infants infants = Select(driver.find_element_by_id("infants-number")) infants.select_by_visible_text("1") #search flights search_flight = driver.find_element_by_id("search-flights").click() # get the outbound date outbound = wait.until(EC.visibility_of_element_located((By.ID, "outboundsearchresults"))) outbound_date = select_date(outbound) # get the inbound date inbound = driver.find_element_by_id("inboundsearchresults") inbound_minimum_date = outbound_date + timedelta(days=7) inbound_date = select_date(inbound, mininum_date=inbound_minimum_date) print(outbound_date, inbound_date) # continue after flights selected proceed_to_pax = driver.find_element_by_id('navigateActionNext').click() pax_page = wait.until(EC.visibility_of_element_located((By.ID, "ctl00_MainContent_passengerList_PassengerGridView_ctl08_butAddBagsForAll"))) #select currency currency = Select(driver.find_element_by_id("ctl00_MainContent_dynamicCurrencyDropDown")) currency.select_by_value("1") #Passenger details pax_one_title = Select(driver.find_element_by_id("ctl00_MainContent_passengerList_PassengerGridView_ctl02_TitleDropDownList")) pax_one_title.select_by_visible_text("Mr") pax_one_forename = driver.find_element_by_id("ctl00_MainContent_passengerList_PassengerGridView_ctl02_ForeNameTextBox").send_keys(PAX1_FORENAME) pax_one_surname = driver.find_element_by_id("ctl00_MainContent_passengerList_PassengerGridView_ctl02_SurNameTextBox").send_keys(PAX_SURNAME) pax_two_title = Select(driver.find_element_by_id("ctl00_MainContent_passengerList_PassengerGridView_ctl03_TitleDropDownList")) pax_two_title.select_by_visible_text("Mrs") pax_two_forename = driver.find_element_by_id("ctl00_MainContent_passengerList_PassengerGridView_ctl03_ForeNameTextBox").send_keys(PAX2_FORENAME) pax_two_surname = driver.find_element_by_id("ctl00_MainContent_passengerList_PassengerGridView_ctl03_SurNameTextBox").send_keys(PAX_SURNAME) pax_three_title = Select(driver.find_element_by_id("ctl00_MainContent_passengerList_PassengerGridView_ctl04_TitleDropDownList")) pax_three_title.select_by_visible_text("Mr") pax_three_forename = driver.find_element_by_id("ctl00_MainContent_passengerList_PassengerGridView_ctl04_ForeNameTextBox").send_keys(PAX3_FORENAME) pax_three_surname = driver.find_element_by_id("ctl00_MainContent_passengerList_PassengerGridView_ctl04_SurNameTextBox").send_keys(PAX_SURNAME) pax_four_title = Select(driver.find_element_by_id("ctl00_MainContent_passengerList_PassengerGridView_ctl05_TitleDropDownList")) pax_four_title.select_by_visible_text("Ms") pax_four_forename = driver.find_element_by_id("ctl00_MainContent_passengerList_PassengerGridView_ctl05_ForeNameTextBox").send_keys(PAX4_FORENAME) pax_four_surname = driver.find_element_by_id("ctl00_MainContent_passengerList_PassengerGridView_ctl05_SurNameTextBox").send_keys(PAX_SURNAME) pax_five_title = Select(driver.find_element_by_id("ctl00_MainContent_passengerList_PassengerGridView_ctl06_TitleDropDownList")) pax_five_title.select_by_visible_text("Mstr") pax_five_forename = driver.find_element_by_id("ctl00_MainContent_passengerList_PassengerGridView_ctl06_ForeNameTextBox").send_keys(PAX5_FORENAME) pax_five_surname = driver.find_element_by_id("ctl00_MainContent_passengerList_PassengerGridView_ctl06_SurNameTextBox").send_keys(PAX_SURNAME) #pax baggage pax_one_bags = Select(driver.find_element_by_id("ctl00_MainContent_passengerList_PassengerGridView_ctl02_baggageOutDropDown")) pax_one_bags.select_by_value("0") pax_two_bags = Select(driver.find_element_by_id("ctl00_MainContent_passengerList_PassengerGridView_ctl03_baggageOutDropDown")) pax_two_bags.select_by_value("0") pax_three_bags = Select(driver.find_element_by_id("ctl00_MainContent_passengerList_PassengerGridView_ctl04_baggageOutDropDown")) pax_three_bags.select_by_value("0") pax_four_bags = Select(driver.find_element_by_id("ctl00_MainContent_passengerList_PassengerGridView_ctl05_baggageOutDropDown")) pax_four_bags.select_by_value("0") #infant carer infant_one_carer = Select(driver.find_element_by_id("ctl00_MainContent_passengerList_PassengerGridView_ctl06_InfantCarerDropDown")) infant_one_carer.select_by_visible_text("Mr Dad Test") #checkin #online = driver.find_element_by_id("ctl00_MainContent_passengerList_checkinOnline").click() airport = driver.find_element_by_id("ctl00_MainContent_passengerList_checkinAirport").click() #continue to seats continue_pax = driver.find_element_by_id("pageContinue").click() modal_outer = wait.until(EC.invisibility_of_element_located((By.ID, "ctl00_MainContent_PageTransitionDialog_messageWrapper"))) continue_again = wait.until(EC.element_to_be_clickable((By.ID, "pageContinue"))).click(); seats_page = wait.until(EC.visibility_of_element_located((By.ID, "findyourseat"))) #seats selection - outbound for outbound_passenger in driver.find_elements_by_css_selector("ol[data-flightbound='Outbound'] li[data-personid]"): outbound_passenger.click() #driver.find_elements_by_css_selector("ol.passengerlist li[data-personid]"): outbound_has_infant = outbound_passenger.get_attribute("data-hasinfant") # choose seats if outbound_has_infant: # select a non-selected infant seat outbound_seat = driver.find_element_by_css_selector(".outbound .planebody a.seat.infant:not(.reserved):not(.selected)") else: # select a non-reserved non-selected seat outbound_seat = driver.find_element_by_css_selector(".outbound .planebody a.seat:not(.reserved):not(.selected)") print("Passenger: %s, choosing seat: %s" % (outbound_passenger.text.strip(), outbound_seat.get_attribute("data-seat"))) outbound_seat.click() outbound_plan = wait.until(EC.invisibility_of_element_located((By.CLASS_NAME, "outbound"))) inbound_plan = wait.until(EC.visibility_of_element_located((By.CLASS_NAME, "inbound"))) #seats selection - inbound for inbound_passenger in driver.find_elements_by_css_selector("ol[data-flightbound='Inbound'] li[data-personid]"): inbound_passenger.click() #driver.find_elements_by_css_selector("ol.passengerlist li[data-personid]"): inbound_has_infant = inbound_passenger.get_attribute("data-hasinfant") # choose seats if inbound_has_infant: # select a non-selected infant seat inbound_seat = driver.find_element_by_css_selector(".inbound .planebody a.seat.infant:not(.reserved):not(.selected)") else: # select a non-reserved non-selected seat inbound_seat = driver.find_element_by_css_selector(".inbound .planebody a.seat:not(.reserved):not(.selected)") print("Passenger: %s, choosing seat: %s" % (inbound_passenger.text.strip(), inbound_seat.get_attribute("data-seat"))) try: inbound_seat.click() except ElementNotVisibleException: wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, "#AllInboundPassengersSeatedOk button"))).click() wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, ".submitseatselection button"))).click() meals = wait.until(EC.visibility_of_element_located((By.ID, "ctl00_MainContent_InFlightMeal_removeMealButton"))) #Meal details try: pax_one_ob_meal = Select(driver.find_element_by_id("ctl00_MainContent_InFlightMeal_PassengerGridView_ctl02_mealsDropDown")) pax_one_ob_meal.select_by_index(0) wait.until(EC.element_to_be_clickable((By.ID, "ctl00_MainContent_InFlightMeal_PassengerGridView_ctl02_mealsDropDownIn"))) pax_one_ib_meal = Select(driver.find_element_by_id("ctl00_MainContent_InFlightMeal_PassengerGridView_ctl02_mealsDropDownIn")) pax_one_ib_meal.select_by_index(2) wait.until(EC.element_to_be_clickable((By.ID, "ctl00_MainContent_InFlightMeal_PassengerGridView_ctl03_mealsDropDown"))) pax_two_ob_meal = Select(driver.find_element_by_id("ctl00_MainContent_InFlightMeal_PassengerGridView_ctl03_mealsDropDown")) pax_two_ob_meal.select_by_index(1) wait.until(EC.element_to_be_clickable((By.ID, "ctl00_MainContent_InFlightMeal_PassengerGridView_ctl03_mealsDropDownIn"))) pax_two_ib_meal = Select(driver.find_element_by_id("ctl00_MainContent_InFlightMeal_PassengerGridView_ctl03_mealsDropDownIn")) pax_two_ib_meal.select_by_index(1) wait.until(EC.element_to_be_clickable((By.ID, "ctl00_MainContent_InFlightMeal_PassengerGridView_ctl04_mealsDropDown"))) pax_three_ob_meal = Select(driver.find_element_by_id("ctl00_MainContent_InFlightMeal_PassengerGridView_ctl04_mealsDropDownt")) pax_three_ob_meal.select_by_index(2) wait.until(EC.element_to_be_clickable((By.ID, "ctl00_MainContent_InFlightMeal_PassengerGridView_ctl04_mealsDropDownIn"))) pax_three_ib_meal = Select(driver.find_element_by_id("ctl00_MainContent_InFlightMeal_PassengerGridView_ctl04_mealsDropDownIn")) pax_three_ib_meal.select_by_index(1) wait.until(EC.element_to_be_clickable((By.ID, "ctl00_MainContent_InFlightMeal_PassengerGridView_ctl05_mealsDropDown"))) pax_four_ob_meal = Select(driver.find_element_by_id("ctl00_MainContent_InFlightMeal_PassengerGridView_ctl05_mealsDropDown")) pax_four_ob_meal.select_by_index(0) wait.until(EC.element_to_be_clickable((By.ID, "ctl00_MainContent_InFlightMeal_PassengerGridView_ctl05_mealsDropDownIn"))) pax_four_ib_meal = Select(driver.find_element_by_id("ctl00_MainContent_InFlightMeal_PassengerGridView_ctl05_mealsDropDownIn")) pax_four_ib_meal.select_by_index(1) 

La lógica es un poco diferente: cuando selecciona un elemento del menú desplegable, este menú desplegable se deshabilita hasta que se recalcula el precio; vea el atributo disabled aparece en el elemento select después de seleccionar una opción.

Entonces, seleccione una opción y espere a que se pueda hacer clic / habilitar el menú desplegable:

 pax_one_ob_meal = Select(driver.find_element_by_id("ctl00_MainContent_InFlightMeal_PassengerGridView_ctl02_mealsDropDown")) pax_one_ob_meal.select_by_index(0) # wait for the dropdown to be clickable/enabled again wait.until(EC.element_to_be_clickable((By.ID, "ctl00_MainContent_InFlightMeal_PassengerGridView_ctl02_mealsDropDown"))) # proceed to the next dropdown 

Use el localizador xpath o css para ubicar el elemento y luego use el menú desplegable de selección usando el índice. En este caso, es bueno usar la espera de Fluent.

Veo dos problemas 🙂

El primer tema es:

 //locator is incorrect it has at in the end pax_three_ob_meal = Select(driver.find_element_by_id("ctl00_MainContent_InFlightMeal_PassengerGridView_ctl04_mealsDropDownt")) // it should be ctl00_MainContent_InFlightMeal_PassengerGridView_ctl04_mealsDropDown 

y el segundo problema es con el cuadro de diálogo modal en el que nos vemos obligados a hacer clic manualmente en el botón “continuar”. En realidad, parece ser parte de un iframe y puede evitarlo cambiando a través de los iframes. Esta es una forma muy burda, pero el código siguiente funciona aunque puede optimizarse (así que agregue el siguiente código “selección de comidas”)

  framecount = driver.find_elements_by_tag_name("iframe") for frame in framecount: driver.switch_to.frame(frame) try: wait.until(EC.element_to_be_clickable((By.XPATH, ".//*[@id='AllInboundPassengersSeatedOk']/div[2]/p[2]/button"))).click() driver.switch_to.default_content() break except TimeoutException: driver.switch_to.default_content() print "Not found in the frame" // i could not understand why but until you loop thorugh the iframes the below element is not visiable wait.until(EC.element_to_be_clickable((By.XPATH, ".//*[@id='AllInboundPassengersSeatedOk']/div[2]/p[2]/button"))).click() //Start of meals section meals = wait.until(EC.visibility_of_element_located((By.ID, "ctl00_MainContent_InFlightMeal_removeMealButton"))) 

Después de los cambios anteriores, el script funcionó bien para mí 🙂