Используйте селен для записи и запуска кода в jupyterlab - PullRequest
3 голосов
/ 23 октября 2019

Я хотел бы протестировать исправленную реализацию juptyerlab. Я надеялся использовать селен для выполнения "hello world" в ячейке кода. Пока я могу войти и создать новую записную книжку:

from selenium import webdriver

driver = webdriver.Firefox()
# assume jupyterlab is running and serving on localhost at port 8888
driver.get("http://localhost:8888")
elem = driver.find_element_by_id("password_input")
password = ""
elem.send_keys(password)
elem = driver.find_element_by_id("login_submit")
elem.click()
elem = driver.find_element_by_css_selector(".jp-Launcher-cwd+ .jp-Launcher-section .jp-LauncherCard")
elem.click()

Это создает новую записную книжку, но теперь я застрял в точке ввода некоторого кода в ячейку и его запуска. Если я просматриваю исходный код страницы, я не вижу html-элементов для ячеек. Но если я введу print("test") в ячейку, то driver.page_source содержит это (оно довольно вложено в другие вещи, которые я тоже пропустил):

<code>                                <div class="CodeMirror cm-s-jupyter CodeMirror-wrap jp-mod-readOnly">
                                    <div style="overflow: hidden; position: relative; width: 3px; height: 0px; top: 0px; left: 0px;">
                                        <textarea
                                                style="position: absolute; bottom: -1em; padding: 0px; width: 1px; height: 1em; outline: currentcolor none medium;"
                                                autocorrect="off" autocapitalize="off"
                                                spellcheck="false" tabindex="0"
                                                wrap="off"></textarea></div>
                                    <div class="CodeMirror-vscrollbar" tabindex="-1"
                                         cm-not-content="true"
                                         style="display: block; bottom: 0px;">
                                        <div style="min-width: 1px; height: 33px;"></div>
                                    </div>
                                    <div class="CodeMirror-hscrollbar" tabindex="-1"
                                         cm-not-content="true">
                                        <div style="height: 100%; min-height: 1px; width: 0px;"></div>
                                    </div>
                                    <div class="CodeMirror-scrollbar-filler"
                                         cm-not-content="true"></div>
                                    <div class="CodeMirror-gutter-filler"
                                         cm-not-content="true"></div>
                                    <div class="CodeMirror-scroll" tabindex="-1" draggable="true">
                                        <div class="CodeMirror-sizer"
                                             style="margin-left: 0px; padding-right: 0px; padding-bottom: 0px;">
                                            <div style="position: relative;">
                                                <div class="CodeMirror-lines" role="presentation">
                                                    <div style="position: relative; outline: currentcolor none medium;"
                                                         role="presentation">
                                                        <div class="CodeMirror-measure">
                                                            <pre><span>xxxxxxxxxx</span>

Я вижу, где находится текст для print("text") (т.е. самые глубокие вложенные элементы в приведенном выше фрагменте HTML), но я не могу понять, какойэлемент здесь я мог бы отправлять текст или отправлять ключи.

Я наткнулся на robotframework-jupyterlibrary , и в нем есть некоторые подсказки, такие как this и это . Из этих ссылок я вижу

${JLAB CSS ACTIVE INPUT} ${JLAB CSS ACTIVE CELL} .CodeMirror

и

Add and Run JupyterLab Code Cell
    [Arguments]    ${code}=print("hello world")
    [Documentation]    Add a ``code`` cell to the currently active notebook and run it.
    Click Element    css:${JLAB CSS NB TOOLBAR} ${JLAB CSS ICON ADD}
    Sleep    0.1s
    ${cell} =   Get WebElement  css:${JLAB CSS ACTIVE INPUT}
    Click Element    ${cell}
    Set CodeMirror Value    ${JLAB CSS ACTIVE INPUT}  ${code}
    Run Current JupyterLab Code Cell
Click Element ${cell}

, что заставляет меня задуматься, если я выберу элемент .CodeMirror, тогда мне просто нужно выяснить, что Get WebElement делает вэтот странный язык и как это сделать в селене.

Есть идеи?


Я тоже пробовал (основываясь на https://stackoverflow.com/a/48723135/1011724 и https://stackoverflow.com/a/50279295/1011724):

from selenium.webdriver.common.action_chains import ActionChains

actions = action_chains.ActionChains(driver)
textarea = driver.find_elements_by_css_selector('.CodeMirror textarea')[0]  # tried for [0], [1] ,[2] and [3] which is all of them.
actions.move_to_element(textarea).click().send_keys("testing...").perform()

, но я продолжаю получатьошибка

selenium.common.exceptions.WebDriverException: Сообщение: TypeError: rect не определено

Ответы [ 2 ]

3 голосов
/ 29 октября 2019

Код ниже протестирован с последними версиями Chrome, Firefox и jupyterlab:

from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By

driver = webdriver.Chrome()
wait = WebDriverWait(driver, 10)
driver.get("http://localhost:8888")
token = "0107216930d05db8a7c36ad6a73573dd5349c3dd56fee852"

wait.until(EC.element_to_be_clickable((By.ID, "password_input"))).send_keys(token, Keys.ENTER)

# wait for "Python 3" Notebook menu or CodeMirror element if already launched.
wait.until(EC.presence_of_element_located(
    (By.CSS_SELECTOR, "[title='Python 3'][data-category='Notebook'], .jp-Notebook .CodeMirror")))
# if "Python 3" Notebook menu found click to open new Notebook
if len(driver.find_elements_by_css_selector("[title='Python 3'][data-category='Notebook']")) > 0:
    driver.find_element_by_css_selector("[title='Python 3'][data-category='Notebook']").click()

# wait for CodeMirror and click to focus
code_mirror = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, ".jp-Notebook .CodeMirror")))
code_mirror.click()
code_mirror.find_element_by_tag_name("textarea").send_keys("print('Hello World!')")
driver.find_element_by_css_selector("[data-icon='run']").click()

output = wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, ".jp-OutputArea-output")))
print(output.text)
assert output.text.strip() == "Hello World!"

driver.quit()
2 голосов
/ 27 октября 2019

Чтобы открыть Jupyter-Notebook:

Либо откройте командное окно и перейдите к папке репозитория, либо откройте anaconda-command-prompt окно и просто выполните

  • jupyter notebook --NotebookApp.token='' --NotebookApp.password=''

Затем, согласно вашему предположению, jupyterlab работает и работает на локальном хосте через порт 8888:

driver.get("http://localhost:8888")

После загрузки ноутбука с использованием driver.get("http://localhost:8888"), вот наиболеехитрая часть, вот как выбрать Dynamically changing object. Ссылка для посещения: Динамически изменяющиеся идентификаторы .

  • При использовании find_element_by_xpath
  • При использовании find_element_by_css_selector

Они оба дадут вам одну и ту же точку выбора, но было бы лучше использовать Xpath, что является более удобной техникой.

# Using Xpath
# I prefer using xpath, because it is simple to understand
# and if you want to dynamically enter data into fields, it would be an awesome approach
driver.find_element_by_xpath("//div[@id='new-buttons']").click()

if len(driver.find_elements_by_xpath("//div[@id='new-buttons']//li[@id='kernel-python3']")) > 0:

   time.sleep(3)
   driver.find_element_by_xpath("//div[@id='new-buttons']//li[@id='kernel-python3']").click()

driver.find_element_by_xpath('//div[@class="cell code_cell rendered selected"]').click()

# Using css_selector
#driver.find_element_by_css_selector("#notebook-container > div").click()

Вы можете использовать любой из вышеперечисленных методов, либо с Xpathили с css-selector.

command = 'print("Test for Dan - Hello World!")'

#a = driver.find_element_by_css_selector("#notebook-container > div > div.input > div.inner_cell >"
#                                         "div.input_area > div > div:nth-child(1) > textarea")

time.sleep(3)
# To select Note-Book text-area and place command in it.
a = driver.find_element_by_xpath('//div[@class="input_area"]//textarea')

time.sleep(3)
a.send_keys(command)
# To run the Code in Selected Cell
time.sleep(3)
driver.find_element_by_xpath("//button[@title='Run']").click()

print("Test is done.")
...