2015-02-04 17 views
5

ja analizowania JS generowane stronę tak:analizowaniem HTML5 teleinformatyczny * wartości atrybutów z selenem w Pythonie

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://www.consumerbarometer.com/en/graph-builder/?question=M1&filter=country:singapore,canada,mexico,brazil,argentina,united_states,bulgaria,austria,belgium,croatia,czech_republic,denmark,estonia,finland,france,germany,greece,hungary,italy,ireland,latvia,lithuania,norway,netherlands,poland,portugal,russia,romania,serbia,slovakia,spain,slovenia,sweden,switzerland,ukraine,united_kingdom,australia,china,israel,hong_kong_sar,japan,korea,new_zealand,malaysia,taiwan,turkey,vietnam') 

// wait for svg to appear 
WebDriverWait(driver, 10).until(EC.visibility_of_element_located((By.TAG_NAME, 'svg'))) 

for text in driver.find_elements_by_class_name('bar-text-label'): 
    print(text.text) 

driver.close() 

Poza tym coraz text z klasy bar-text-label Chciałbym również, aby uzyskać wartości z danymi HTML5 -atrybut. Na przykład <rect rx="3" ry="3" width="76%" height="40" transform="translate(0,40)" data-value="76" class="bar"></rect> i chciałbym móc przetworzyć z tego 76.

Czy można to zrobić w Selenie?

Próbowałem zarówno z dołu, bez sucess:

for text in driver.find_elements_by_class_name('bar'): 
    print(data_value.text) 

for data in driver.find_elements_by_xpath('//*[contains(@data-value)]/@data-value'): 
    print(data.text) 
+0

Czy próbowałeś użyć metody '.get_attribute()' na elemencie po jego zlokalizowaniu? –

Odpowiedz

4

Jeśli masz elementy jak następuje:

<rect rx="3" ry="3" width="76%" height="40" transform="translate(0,40)" data-value="75" class="bar">bar1</rect> 
<rect rx="3" ry="3" width="76%" height="40" transform="translate(0,40)" data-value="76" class="bar">bar2</rect> 

można uzyskać wartość tekstu i wartość atrybutu, co następuje:

elements = driver.find_elements_by_class_name('bar') 
for element in elements: 
    print element.text 
    print element.get_attribute('data-value') 

ten wypisuje:

bar1 
75 
bar2 
76 
2

Możesz wspomnieć próbowałeś:

for text in driver.find_elements_by_class_name('bar'): 
    print(data_value.text) 

Widząc jak data_value nie jest nigdzie zdefiniowane, to nie będzie działać. Jeśli zrobiłeś print(text.text) powinieneś otrzymać tekst każdego elementu, który ma klasę bar. (To jest w zasadzie to, co robisz w swoim pierwszym fragmencie.)

też wspomnieć to:

for data in driver.find_elements_by_xpath('//*[contains(@data-value)]/@data-value'): 
    print(data.text) 

To nie może działać, ponieważ selen za find_element(s)... funkcji nie może nic innego niż elementy lub list elementów powrócić. Próbujesz uzyskać to, aby zwrócić atrybut, który nie zadziała. XPath na ogół pozwala na to, ale kiedy używasz XPath przez Selenium, nie możesz uzyskać niczego innego niż elementy.

Można to zrobić albo co Jessamyn Smith suggested:

results = driver.execute_script(""" 
    var els = document.getElementsByClassName("bar"); 
    var ret = []; 
    for (var i =0, el; (el = els[i]); ++i) { 
     ret.push([el.textContent, el.attributes["data-value"].value]); 
    } 
    return ret; 
""") 
for r in results: 
    print(r[0], r[1]) 

To zajmie jedną podróż w obie strony między skryptu i przeglądarki. Zapętlanie i używanie .text i .get_attribute() obejmuje 2 podróże w obie strony na iterację. JavaScriptScript tworzy listę par wyników. Każda para zawiera tekst elementu na pierwszej pozycji, a wartość data-value na drugiej pozycji.

+0

To jest bardzo interesujące. Nie wiedziałem, że możesz wykonać takie js. – metersk

+0

Z początku też nie wiedziałem. Jeśli wszystko działasz lokalnie, różnica nie jest duża, ale jeśli używasz Sauce Labs, Browser Stack lub czegoś, aby zdalnie uruchamiać testy, wycieczki w obie strony sumują się ** dużo **. Skróciłem czas potrzebny na uruchomienie dużych zestawów testowych na pół, łącząc wiele wywołań Selenium w jedno wywołanie 'execute_script' (lub' execute_script_async'). – Louis