Python >> Tutoriel Python >  >> Python Tag >> JuPyter

Comment trouver un élément HTML existant avec python-selenium dans une page jupyterhub ?

Tu étais assez proche. En fait, l'ensemble de votre programme n'avait qu'un seul problème, comme suit :

  • Le xpath_runall = "//li[@data-command='notebook:run-all-below']" n'identifie pas l'élément visible avec le texte comme Exécuter la cellule sélectionnée et tout en dessous uniquement car le premier élément correspondant est un élément masqué élément.

Considérations supplémentaires

Quelques optimisations supplémentaires :

  • L'élément identifié comme xpath = "//button[@title='Save the notebook contents and create checkpoint']" est cliquable élément. Donc au lieu de EC comme presence_of_element_located() vous pouvez utiliser element_to_be_clickable()

  • Une fois l'élément renvoyé via EC comme element_to_be_clickable() vous pouvez invoquer le click() sur la même ligne.

  • Le xpath pour identifier l'élément avec le texte comme Exécuter la cellule sélectionnée et tout en dessous serait :

    //li[@data-command='notebook:run-all-below']//div[@class='lm-Menu-itemLabel p-Menu-itemLabel' and text()='Run Selected Cell and All Below']
    
  • Comme l'application est construite via JavaScript, vous devez utiliser ActionChains.

Solution

Votre solution optimisée sera :

  • Bloc de code :

    from selenium import webdriver
    from selenium.webdriver.support.ui import WebDriverWait
    from selenium.webdriver.common.by import By
    from selenium.webdriver.support import expected_conditions as EC
    from selenium.webdriver.common.action_chains import ActionChains
    
    driver = webdriver.Firefox(executable_path=r'C:\WebDrivers\geckodriver.exe')
    driver.get("https://mybinder.org/v2/gh/jupyterlab/jupyterlab-demo/master?urlpath=lab/tree/demo")
    WebDriverWait(driver, 60).until(EC.element_to_be_clickable((By.XPATH, "//button[@title='Save the notebook contents and create checkpoint']")))
    print("Page loaded")
    WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//div[text()='Run']"))).click()
    print("Clicked on Run")
    element = WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//li[@data-command='notebook:run-all-below']//div[@class='lm-Menu-itemLabel p-Menu-itemLabel' and text()='Run Selected Cell and All Below']")))
    ActionChains(driver).move_to_element(element).click(element).perform()
    print("Clicked on Run Selected Cell and All Below")
    
  • Sortie console :

    Page loaded
    Clicked on Run
    Clicked on Run Selected Cell and All Below
    

Cela a fonctionné pour moi. Je trouve l'élément de menu de niveau supérieur en utilisant xpath complet, puis je clique dessus. J'attends un peu de temps pour m'assurer que le menu contextuel est apparu, puis en utilisant un décalage par rapport à l'élément de menu d'origine que j'ai prédéterminé, je déplace la souris vers ce décalage et clique sur ce que je sais être le bon sous- élément du menu. Dans le code ci-dessous, je me donne d'abord la possibilité de sélectionner une cellule :

driver.implicitly_wait(300) # wait up to 300 seconds before calls to find elements time out
driver.get('https://mybinder.org/v2/gh/jupyterlab/jupyterlab-demo/master?urlpath=lab/tree/demo')
driver.execute_script("scroll(0, 0);")
elem = driver.find_element_by_xpath('//div[text()="Run"]')
elem.click() # click on top-level menu item
time.sleep(.2) # wait for sub-menu to appear
action = webdriver.common.action_chains.ActionChains(driver)
action.move_to_element_with_offset(elem, 224, 182)
# click on sub-menu item:
action.click()
action.perform()

Mise à jour :une solution plus optimale

driver.implicitly_wait(300) # wait up to 300 seconds before calls to find elements time out
driver.get('https://mybinder.org/v2/gh/jupyterlab/jupyterlab-demo/master?urlpath=lab/tree/demo')
driver.execute_script("scroll(0, 0);")
elem = driver.find_element_by_xpath('//div[text()="Run"]')
elem.click()
driver.implicitly_wait(.2)
elem2 = driver.find_element_by_xpath('//*[contains(text(),"Run Selected Cell and All Below")]')
driver.execute_script("arguments[0].click();", elem2) # sub-menu, however, stays open
# to close the sub-menu menu:
elem.click()