Jonathan Porter
Jonathan Porter

Reputation: 1556

Can't select compound element with selenium using python

Using selenium and chrome driver. Python 3.5

Imagine a start time and end time box. You click into the start time box and a clock appears. The start clock is left aligned and the end clock is right aligned.

<div class="popover clockpicker-popover top clockpicker-align-left" style="display: block; top: 511px; left: 287px;">

enter image description here enter image description here

<div class="clockpicker-dial clockpicker-hours" style="visibility: visible;"></div>

<div class="clockpicker-dial clockpicker-minutes" style="visibility: visible;"></div>

Then you click into the end time box:

enter image description here enter image description here

<div class="popover clockpicker-popover top clockpicker-align-right" style="display: block; top: 511px; left: 287px;">

Same hours and minutes.

My issue is selecting the left and right versions of the clock. In fact, my code was working fine until I had to put in the end time and so then I decided to add code to distinguish them.

import time, sys
from selenium import webdriver

# open chrome and go to website
driver = webdriver.Chrome()
driver.get('website')
time.sleep(3)


def startHour(number):
    # If I remove this line I can select hours/mins for first clock but not second clock
    driver.find_element_by_css_selector('popover.clockpicker-popover.top.clockpicker-align-left')
    select = driver.find_element_by_css_selector('.clockpicker-dial.clockpicker-hours')
    print('Selected clockpicker hours')
    for hour in select.find_elements_by_class_name('clockpicker-tick'):
        print(hour.text)
        if hour.text == number:
            print('Hour.text: ' + hour.text)
            print('Hour: ' + number)
            hour.click()
            break

def endHour(number):
    driver.find_element_by_css_selector('popover.clockpicker-popover.top.clockpicker-align-right')
    select = driver.find_element_by_css_selector('.clockpicker-dial.clockpicker-hours')
    print('Selected clockpicker hours')
    for hour in select.find_elements_by_class_name('clockpicker-tick'):
        print(hour.text)
        if hour.text == number:
            print('Hour.text: ' + hour.text)
            print('Hour: ' + number)
            hour.click()
            break

def clickMinutes(number):
    select = driver.find_element_by_css_selector('.clockpicker-dial.clockpicker-minutes')
    print('Selected clockpicker minutes')
    for minutes in select.find_elements_by_class_name('clockpicker-tick'):
        print(minutes.text)
        if minutes.text == number:
            print('Minutes.text: ' + minutes.text)
            print('Minutes: ' + number)
            minutes.click()
            break

# Select start time input box, start time clock appears
driver.find_element_by_id('StartTime').click()

startHour('7')
time.sleep(4)

clickMinutes('30')
time.sleep(4)

# Select end time input box, end time clock appears
driver.find_element_by_id('EndTime').click()
time.sleep(4)

endHour('16')
time.sleep(4)

clickMinutes('00')
time.sleep(4)

driver.quit()
sys.exit()

Error:

selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate element: {"method":"css selector","selector":"popover.clockpicker-popover.top.clockpicker-align-left"}

When I remove that driver.find_element_by_css_selector('popover.clockpicker-popover.top.clockpicker-align-left') it works fine for the first clock and I can open the second clock by clicking into the input box for it but I can't actually select the second clock or its elements.

Update:

It seems like it finds the hours but it prints out a bunch of empty lines which makes me think it's still on the first clock which is hidden when the second clock comes up.

enter image description here

When I change my print statement from print(hour.text) to print(hour) it shows this:

enter image description here

24 elements for the 24 hours.

ANSWER:

I added the periods in front of popover.clockpicker... and also appended the next find element by css selector and it worked! Thank you everyone for your help.

def startHour(number):
    select = driver.find_element_by_css_selector('.popover.clockpicker-popover.top.clockpicker-align-left').find_element_by_css_selector('.clockpicker-dial.clockpicker-hours')
    print('Selected clockpicker hours')
    for hour in select.find_elements_by_class_name('clockpicker-tick'):
        print(hour.text)
        if hour.text == number:
            print('Hour.text: ' + hour.text)
            print('Hour: ' + number)
            hour.click()
            break

def endHour(number):
    select = driver.find_element_by_css_selector('.popover.clockpicker-popover.top.clockpicker-align-right').find_element_by_css_selector('.clockpicker-dial.clockpicker-hours')
    print('Selected clockpicker hours')
    for hour in select.find_elements_by_class_name('clockpicker-tick'):
        print(hour.text)
        if hour.text == number:
            print('Hour.text: ' + hour.text)
            print('Hour: ' + number)
            hour.click()
            break

Upvotes: 2

Views: 329

Answers (2)

Andersson
Andersson

Reputation: 52665

I guess your issue caused by typo in your selector:

'popover.clockpicker-popover.top.clockpicker-align-left'

actually means that you want to handle

 <popover class="clockpicker-popover top clockpicker-align-left">

element, so you need to add leading point as

'.popover.clockpicker-popover.top.clockpicker-align-left'

Upvotes: 1

Gerry Gilmore
Gerry Gilmore

Reputation: 13

So, it sounds like it is popping the first clock (align-left), but your error indicates that it is this element that is failing. That seems wrong...

Also, you mention that you have to actually click into the first clock before the second one appears, and I don't see where you are doing that.

Upvotes: 0

Related Questions