Bagaimana menemukan elemen HTML yang ada dengan python-selenium di halaman jupyterhub?
Saya memiliki konstruksi berikut di halaman HTML dan saya ingin memilih li
elemen (dengan python-selenium):
<li class="p-Menu-item p-mod-disabled" data-type="command" data-command="notebook:run-all-below">
<div class="p-Menu-itemIcon"></div>
<div class="p-Menu-itemLabel" style="">Run Selected Cell and All Below</div>
<div class="p-Menu-itemShortcut" style=""></div>
<div class="p-Menu-itemSubmenuIcon"></div>
</li>
Saya menggunakan xpath berikut:
//li[@data-command='notebook:run-all-below']
Namun unsur tersebut sepertinya tidak ditemukan.
Lengkap, kode contoh kerja minimal:
import time
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
driver = webdriver.Firefox()
driver.get("https://mybinder.org/v2/gh/jupyterlab/jupyterlab-demo/master?urlpath=lab/tree/demo")
# Wait for the page to be loaded
xpath = "//button[@title='Save the notebook contents and create checkpoint']"
element = WebDriverWait(driver, 600).until(
EC.presence_of_element_located((By.XPATH, xpath))
)
time.sleep(10)
print("Page loaded")
# Find and click on menu "Run"
xpath_run = "//div[text()='Run']"
element = WebDriverWait(driver, 60).until(
EC.element_to_be_clickable((By.XPATH, xpath_run))
)
element.click()
print("Clicked on 'Run'")
# Find and click on menu entry "Run Selected Cell and All Below"
xpath_runall = "//li[@data-command='notebook:run-all-below']"
element = WebDriverWait(driver, 600).until(
EC.element_to_be_clickable((By.XPATH, xpath_runall))
)
print("Found element 'Run Selected Cell and All Below'")
element.click()
print("Clicked on 'Run Selected Cell and All Below'")
driver.close()
Lingkungan Hidup:
- MacOS Mojave (10.14.6)
- python 3.8.6
- selenium 3.8.0
- geckodriver 0.26.0
Tambahan
Saya telah mencoba merekam langkah-langkah dengan add-on Firefox "Selenium IDE" yang memberikan langkah-langkah berikut untuk python:
sdriver.get("https://hub.gke2.mybinder.org/user/jupyterlab-jupyterlab-demo-y0bp97e4/lab/tree/demo")
driver.set_window_size(1650, 916)
driver.execute_script("window.scrollTo(0,0)")
driver.find_element(By.CSS_SELECTOR, ".lm-mod-active > .lm-MenuBar-itemLabel").click()
yang, tentu saja, juga tidak berfungsi. Dengan baris kode itu saya mendapatkan kesalahan
selenium.common.exceptions.NoSuchElementException: Message: Unable to locate element: .lm-mod-active > .lm-MenuBar-itemLabel
Jawaban
Anda cukup dekat. Faktanya, seluruh program Anda hanya memiliki satu masalah sebagai berikut:
- The
xpath_runall = "//li[@data-command='notebook:run-all-below']"
tidak mengidentifikasi elemen yang terlihat dengan teks sebagai Jalankan Sel yang Dipilih dan Semua di Bawah secara unik karena elemen pertama yang cocok adalah elemen tersembunyi .
Pertimbangan tambahan
Beberapa pengoptimalan lagi:
Unsur diidentifikasi sebagai
xpath = "//button[@title='Save the notebook contents and create checkpoint']"
adalah diklik elemen. Jadi bukan EC sepertipresence_of_element_located()
yang bisa Anda gunakanelement_to_be_clickable()
Setelah elemen dikembalikan melalui EC karena
element_to_be_clickable()
Anda dapat memanggilclick()
di baris yang sama.The XPath untuk mengidentifikasi elemen dengan teks sebagai Run Dipilih Sel dan Semua Di bawah akan menjadi:
//li[@data-command='notebook:run-all-below']//div[@class='lm-Menu-itemLabel p-Menu-itemLabel' and text()='Run Selected Cell and All Below']
Karena aplikasi ini dibangun melalui JavaScript, Anda perlu menggunakan ActionChains .
Larutan
Solusi Anda yang dioptimalkan adalah:
Blok Kode:
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")
Keluaran Konsol:
Page loaded Clicked on Run Clicked on Run Selected Cell and All Below
Ini berhasil untuk saya. Saya menemukan item menu tingkat atas menggunakan xpath penuh dan kemudian mengkliknya. Saya menunggu sedikit waktu untuk memastikan bahwa menu popup telah muncul dan kemudian menggunakan offset dari item menu asli yang telah saya tentukan sebelumnya, saya memindahkan mouse ke offset tersebut dan mengklik apa yang saya tahu sebagai sub- item menu. Pada kode di bawah ini, pertama-tama saya memberi diri saya kesempatan untuk memilih sel:
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()
Pembaruan: Solusi yang Lebih Optimal
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()
Sepertinya ada dua elemen li dengan atribut yang mirip. Anda perlu mengidentifikasi elemen yang benar untuk diklik.Gunakan yang berikut ini xpath
untuk mengklik elemen yang benar.
xpath_runall = "//ul[@class='lm-Menu-content p-Menu-content']//li[@data-command='notebook:run-all-below']"
element = WebDriverWait(driver, 10).until(
EC.element_to_be_clickable((By.XPATH, xpath_runall))
)
elementText=element.text
print("Found element '{}'".format(elementText))
element.click()
print("Clicked on '{}'".format(elementText))
Keluaran konsol:
Page loaded
Clicked on 'Run'
Found element 'Run Selected Cell and All Below'
Clicked on 'Run Selected Cell and All Below'