2015-03-07 17 views
8

Ist es möglich, Elemente finden in dem Schatten DOM mit Python-Selen?Zugriff auf Elemente im Schatten DOM

Beispiel Anwendungsfall:

Ich habe diese input mit type="date":

<input type="date">

Und ich möchte der Datumsauswahl-Taste auf der rechten Seite klicken und wählen Sie ein Datum aus dem Kalender.

Wenn Sie das Element in Chrome Developer Tools überprüfen würde und die Schatten-Wurzelknoten des Datumseingabe erweitern, würden Sie sehen, die Taste erscheint als:

<div pseudo="-webkit-calendar-picker-indicator" id="picker"></div> 

Screenshot zeigt, wie es in Chrome aussieht:

enter image description here

die "Picker" -Schaltfläche von id Ergebnisse zu finden, in NoSuchElementException:

>>> date_input = driver.find_element_by_name('bday') 
>>> date_input.find_element_by_id('picker') 
... 
selenium.common.exceptions.NoSuchElementException: Message: no such element 

Ich habe auch versucht ::shadow und /deep/ Locators zu verwenden, wie here vorgeschlagen:

>>> driver.find_element_by_css_selector('input[name=bday]::shadow #picker') 
... 
selenium.common.exceptions.NoSuchElementException: Message: no such element 
>>> 
>>> driver.find_element_by_css_selector('input[name=bday] /deep/ #picker') 
... 
selenium.common.exceptions.NoSuchElementException: Message: no such element 

Bitte beachte, dass ich das Datum in der Eingabe durch das Senden Tasten, um es ändern:

driver.find_element_by_name('bday').send_keys('01/11/2014') 

Aber will ich das Datum speziell setzen, indem sie aus einem Kalender auswählen.

+0

Sie die letzte Version von ChromeDriver verwenden? Chromedriver unterstützt Shadow DOM seit v2.14 (2015-01-28). –

+0

@ f.cipriani ja, die neueste (2.14). Vielen Dank. – alecxe

+0

Haben Sie ein _funktionelles_ Beispiel für den Anwendungsfall? – SiKing

Antwort

8

Es gibt keinen Weg, um die Schatten Wurzel von nativen HTML-5-Elemente zuzugreifen.

Nicht in diesem Fall nützlich, aber mit Chrome ist es möglich, einen benutzerdefinierter erstellten Schatten root zuzugreifen:

var root = document.querySelector("#test_button").createShadowRoot(); 
 
root.innerHTML = "<button id='inner_button'>Button in button</button"
<button id="test_button"></button>

Die Wurzel kann dann auf diese Weise zugegriffen werden:

var element = document.querySelector("#test_button").shadowRoot; 

Wenn Sie einen Klick auf den inneren Knopf mit Selen python (chromedriver Version 2 automatisieren möchten.14+):

>>> outer = driver.execute_script('return document.querySelector("#test_button").shadowRoot') 
>>> inner = outer.find_element_by_id("inner_button") 
>>> inner.click() 

Update 9 Jun 2015

Dies ist der Link auf die aktuelle Schatten DOM W3C Editor Entwurf auf GitHub:

http://w3c.github.io/webcomponents/spec/shadow/

Wenn Sie interessiert sind Durchsuchen des blink Quellcodes, this is a good starting point.

+0

Das macht absolut Sinn: Sie sagen im Grunde genommen, dass diese neue Chrom-Driver-Funktion: [Problem 852: \t Schatten Schatten in Chrom-Treiber unterstützen.] (Https://code.google.com/p/chromedriver/issues/detail?id = 852) bezieht sich im Grunde genommen auf benutzerdefinierte Elemente mit Shadow-DOM, korrekt? – alecxe

+3

Das ist korrekt.Chromedriver ist nur ein Wrapper oben auf der Browser-API. Da Chrome keinen skriptfähigen Zugriff auf User-Agent-Shadow-DOMs zulässt (können sie sein styled to), das gleiche gilt für Selen –

+0

große Antwort, aber es hat einige Nachteile für verschachtelte Schattenwurzelelemente überprüfen Sie meine Antwort unten –

1

Die akzeptierte Antwort hat einen Nachteil, viele Male die Schatten-Host-Elemente sind mit Schattenbäumen versteckt, deshalb ist der beste Weg, dies zu tun, die Selen Selektoren zu verwenden, um die Schatten-Host-Elemente zu finden und das Skript zu injizieren, nur um die zu nehmen Schatten root:

def expand_shadow_element(element): 
    shadow_root = driver.execute_script('return arguments[0].shadowRoot', element) 
    return shadow_root 

#the accepted answer code then becomes 
outer = expand_shadow_element(driver.find_element_by_css_selector("#test_button")) 
inner = outer.find_element_by_id("inner_button") 
inner.click() 

dies in die richtige Perspektive zu setzen habe ich nur noch ein prüfbar Beispiel mit Chrome Download-Seite, klicken auf die Suchtaste muss offen 3 verschachtelte Schatten Stammelemente: enter image description here

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() 

das gleiche tun die akzeptierte Antwort-Ansatz hat den Nachteil, dass es schwer-Codes die Abfragen, ist weniger lesbar und Sie können nicht die Vermittler Auswahl für andere Aktionen verwenden:

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() 
Verwandte Themen