Как обрабатывать элементы внутри Shadow DOM от Selenium

Я хочу автоматизировать проверку завершения загрузки файлов в chromedriver . HTML каждой записи в списке загрузок выглядит так:

 DownloadedFile#1 

Поэтому я использую следующий код для поиска целевых элементов:

 driver.get('chrome://downloads/') # This page should be available for everyone who use Chrome browser driver.find_elements_by_tag_name('a') 

Это возвращает пустой список, когда есть 3 новых загрузки.

Как я узнал, можно обрабатывать только родительские элементы тэга #shadow-root (open) . Итак, как я могу найти элементы внутри этого элемента #shadow-root ?

    Вы можете использовать метод driver.executeScript() для доступа к элементам HTML и объектам JavaScript на своей веб-странице.

    В приведенном ниже executeScript будет возвращать в списке Promise the Node всех элементов, присутствующих в дереве executeScript элемента, который является host . Затем вы можете выполнить тестовый тест:

     it( 'check shadow root content', function () { return driver.executeScript( function () { return host.shadowRoot.querySelectorAll( 'a' ).then( function ( n ) { return expect( n ).to.have.length( 3 ) } } ) } ) 

    Примечание. Я не знаю Python, поэтому я использовал синтаксис JavaScript, но он должен работать одинаково.

    Иногда теневые корневые элементы вложены, а второй теневой корень не отображается в корневом каталоге документа, но доступен в корневом корневом корневом корневом объекте. Я считаю, что лучше использовать seleniumеры seleniumа и вставить сценарий, чтобы получить теневой корень:

     def expand_shadow_element(element): shadow_root = driver.execute_script('return arguments[0].shadowRoot', element) return shadow_root outer = expand_shadow_element(driver.find_element_by_css_selector("#test_button")) inner = outer.find_element_by_id("inner_button") inner.click() 

    Чтобы представить это в перспективе, я просто добавил тестовый пример с страницы загрузки Chrome, нажав кнопку поиска, нужно открыть 3 вложенных теневых корневых элемента: введите описание изображения здесь

     import selenium from selenium import webdriver driver = webdriver.Chrome() def expand_shadow_element(element): shadow_root = driver.execute_script('return arguments[0].shadowRoot', element) return shadow_root driver.get("chrome://downloads") root1 = driver.find_element_by_tag_name('downloads-manager') shadow_root1 = expand_shadow_element(root1) root2 = shadow_root1.find_element_by_css_selector('downloads-toolbar') shadow_root2 = expand_shadow_element(root2) root3 = shadow_root2.find_element_by_css_selector('cr-search-field') shadow_root3 = expand_shadow_element(root3) search_button = shadow_root3.find_element_by_css_selector("#search-button") search_button.click() 

    В том же подходе, предложенном в других ответах, есть недостаток, заключающийся в том, что он жестко кодирует запросы, менее читабельен и вы не можете использовать промежуточные варианты для других действий:

     search_button = driver.execute_script('return document.querySelector("downloads-manager").shadowRoot.querySelector("downloads-toolbar").shadowRoot.querySelector("cr-search-field").shadowRoot.querySelector("#search-button")') search_button.click() 

    позже отредактируйте:

    Недавно я попытался получить доступ к настройкам контента (см. Код ниже), и теперь у него есть несколько теневых корневых элементов, теперь вы не можете получить доступ к нему без предварительного расширения другого, когда у вас обычно есть динамический контент и более трех теневых элементов один в другой это делает невозможной автоматизацию. Ответ выше используется для работы несколько лет назад, но этого достаточно для всего лишь одного элемента, чтобы изменить позицию, и вам нужно всегда идти с элементом проверки вверх по дереву и посмотреть, находится ли он в тени, кошмар автоматизации.

    Не только было трудно найти только настройки контента из-за теневых и динамических изменений, когда вы обнаружите, что кнопка не может быть нажата на данный момент.

     driver = webdriver.Chrome() def expand_shadow_element(element): shadow_root = driver.execute_script('return arguments[0].shadowRoot', element) return shadow_root driver.get("chrome://settings") root1 = driver.find_element_by_tag_name('settings-ui') shadow_root1 = expand_shadow_element(root1) root2 = shadow_root1.find_element_by_css_selector('[page-name="Settings"]') shadow_root2 = expand_shadow_element(root2) root3 = shadow_root2.find_element_by_id('search') shadow_root3 = expand_shadow_element(root3) search_button = shadow_root3.find_element_by_id("searchTerm") search_button.click() text_area = shadow_root3.find_element_by_id('searchInput') text_area.send_keys("content settings") root0 = shadow_root1.find_element_by_id('main') shadow_root0_s = expand_shadow_element(root0) root1_p = shadow_root0_s.find_element_by_css_selector('settings-basic-page') shadow_root1_p = expand_shadow_element(root1_p) root1_s = shadow_root1_p.find_element_by_css_selector('settings-privacy-page') shadow_root1_s = expand_shadow_element(root1_s) content_settings_div = shadow_root1_s.find_element_by_css_selector('#site-settings-subpage-trigger') content_settings = content_settings_div.find_element_by_css_selector("button") content_settings.click() 
    Interesting Posts

    UITextField для номера телефона

    Какая версия Emacs наилучшим образом использует графический интерфейс Mac?

    Что означает «int 0x80» в коде сборки?

    Как обнаружить разъединение сокета TCP (с гнездом C Berkeley)

    Прозрачное поведение текстур в WebGL

    Как разрешены имена серверов сертификатов SSL / Можно ли добавлять альтернативные имена с помощью keytool?

    Как я могу переопределить DNS-серверы Windows10 по умолчанию для использования DNS-серверов, назначенных OpenVPN

    Скрыть имя между сообщениями одного и того же человека в Pidgin

    QEMU с пропуском GPU не запустится

    Как вы запрашиваете pthread, чтобы узнать, все ли работает?

    Подключитесь к Linux по имени, а не по IP

    Влияние кэша L3 на производительность – стоит двухпроцессорная система?

    Как создать новый div динамически, изменить его, перенести, изменить его всеми возможными способами в JavaScript?

    Конструктор по умолчанию с пустыми скобками

    Вопрос о прекращении streamа в .NET.

    Давайте будем гением компьютера.