3

I want to ask my python to click a link from a web page and I have tried below 3 ways to specify an Xpath to a Span element in my python code:

driver.find_element_by_xpath("//*[@id='ChartUnitsHistory_ranges']/span[text()='1y']").click()
driver.find_element_by_xpath("//div[@class='graphControls']/span/1y")
driver.find_element_by_xpath("//a[@class='graphControls']/span[text()='1y']").click()

but all of these failed with the same error message:

selenium.common.exceptions.InvalidSelectorException: Message: The specified selector is invalid.

Updated Error message:

Traceback (most recent call last):   File "02042020.py", line 31, in <module>
    driver.find_element_by_xpath("//span[@id='ChartUnitsHistory_ranges']/a[text()='1y']").click() File "C:\Users\username\PycharmProjects\Web_Scraping\venv\lib\site-packages\selenium\webdriver\remote\webdriver.py", line 394, in find_element_by_xpath
    return self.find_element(by=By.XPATH, value=xpath)   File "C:\Users\username\PycharmProjects\Web_Scraping\venv\lib\site-packages\selenium\webdriver\remote\webdriver.py", line 976, in find_element
    return self.execute(Command.FIND_ELEMENT, {   File "C:\Users\username\PycharmProjects\Web_Scraping\venv\lib\site-packages\selenium\webdriver\remote\webdriver.py", line 321, in execute
    self.error_handler.check_response(response)   File "C:\Users\username\PycharmProjects\Web_Scraping\venv\lib\site-packages\selenium\webdriver\remote\errorhandler.py", line 242, in check_response
    raise exception_class(message, screen, stacktrace) selenium.common.exceptions.InvalidSelectorException: Message: The specified selector is invalid.

I need help on coming up with the correct Xpath for the '1y' option.

HTML Source Code:

<div class="graphControls">
            <a href="javascript:jsChartUnitsHistory.getOptions().shiftRange(100, true)">&lt;&lt;</a>&nbsp;
            <a href="javascript:jsChartUnitsHistory.getOptions().shiftRange(33, true)">&lt;</a>
            &nbsp;&nbsp;
            <a href="javascript:jsChartUnitsHistory.getOptions().shiftRange(33, false)">&gt;</a>&nbsp;
            <a href="javascript:jsChartUnitsHistory.getOptions().shiftRange(100, false)">&gt;&gt;</a>&nbsp;
            <a href="javascript:jsChartUnitsHistory.getOptions().updateRange(0,'now')">&gt;|</a>
            &nbsp;&nbsp;&nbsp;&nbsp;
            <a href="javascript:jsChartUnitsHistory.getOptions().zoom(50);">[ + ]</a>
            <a href="javascript:jsChartUnitsHistory.getOptions().zoom(200);">[ - ]</a>
            &nbsp;&nbsp;
        <span id="ChartUnitsHistory_ranges" style="">
                    <a href="javascript:jsChartUnitsHistory.getOptions().updateRange(1,'year')">1y</a>
            <a href="javascript:jsChartUnitsHistory.getOptions().updateRange(3,'month')">3m</a>
            <a href="javascript:jsChartUnitsHistory.getOptions().updateRange(1,'month')">1m</a>
            <a href="javascript:jsChartUnitsHistory.getOptions().updateRange(2,'week')">2w</a>
            <a href="javascript:jsChartUnitsHistory.getOptions().updateRange(1,'week')">1w</a>
            <a href="javascript:jsChartUnitsHistory.getOptions().updateRange(3,'day')">3d</a>
            &nbsp;&nbsp;&nbsp;
        </span>
            <a href="#" id="ChartUnitsHistory_embiggen" onclick="EnlargeFlotChart( 'ChartUnitsHistory', jsChartUnitsHistory, 1100, 312 ); return false">enhance</a>
            <a href="#" id="ChartUnitsHistory_restore" style="display:none;" onclick="RestoreFlotChart( 'ChartUnitsHistory', jsChartUnitsHistory, 700, 160 );;return false">unenhance</a>
            <div style="clear: both;"></div>
</div>

The layout of these elements looks like this on the web page:

<<  <    >  >>  >|      [ + ] [ - ]    1y 3m 1m 2w 1w 3d     enhance unenhance

Please also see the attached screenshot of the web page: Screenshot of the webpage

Please let me know if information provided is enough or not. Thank you in advance!

3 Answers 3

1

The text "1y" is in <a> tag, the parent element with id='ChartUnitsHistory_ranges' is <span>

driver.find_element_by_xpath("//span[@id='ChartUnitsHistory_ranges']/a[text()='1y']").click()

"//div[@class='graphControls']/span/1y" didn't work because "1y" is treated like a tag here.

"//a[@class='graphControls']/span[text()='1y']" didn't work because class='graphControls' is in <div> tag and the element is no a direct child, / is for direct child, // for any descendant.

You can also use css_selector for that

driver.find_element_by_css_selector('#ChartUnitsHistory_ranges > [href$="(1,\'year\')"]').click()
Sign up to request clarification or add additional context in comments.

8 Comments

I used the xpath you provided but the same error still occurred. I also added driver.implicitly_wait(5) before the xpath line of code. Any suggestions? Thanks :)
@an1que You are getting Invalid selector exception? this is kind of wired. Actually all the xpath you used are valid, just didn't match. Can you post the full error message?
driver.find_element_by_xpath("//span[@id='ChartUnitsHistory_ranges']/a[text()='1y']").click() File "", line 394, in find_element_by_xpath return self.find_element(by=By.XPATH, value=xpath) File ", line 976, in find_element return self.execute(Command.FIND_ELEMENT, { File "", line 321, in execute self.error_handler.check_response(response) File "", line 242, in check_response raise exception_class(message, screen, stacktrace) selenium.common.exceptions.InvalidSelectorException: Message: The specified selector is invalid.
Please see the updated error message from the original post for better viewing.
@an1que Can you share the link?
|
1

The desired element is an JavaScript enabled element, so to click on the element ideally you have to induce WebDriverWait for the element_to_be_clickable() and you can use either of the following Locator Strategies:

  • Using LINK_TEXT:

    WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.LINK_TEXT, "1y"))).click()
    
  • Using CSS_SELECTOR:

    WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "div.graphControls span#ChartUnitsHistory_ranges a[href*='year']"))).click()
    
  • Using XPATH:

    WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//div[@class='graphControls']//span[@id='ChartUnitsHistory_ranges']//a[contains(@href, 'year')]"))).click()
    
  • Note : You have to add the following imports:

    from selenium.webdriver.support.ui import WebDriverWait
    from selenium.webdriver.common.by import By
    from selenium.webdriver.support import expected_conditions as EC
    

Comments

1

If you're using Chrome, you can click F12 to switch to the Developer Mode and locate the HTML element. Then right click the element to copy:

  • css selector
  • Xpath or full Xpath
  • JS path
  • Styles

In your case, you need to copy the Xpath. This would be a quick way to get the Xpath.

1 Comment

"Then right-click the element to copy:" Can be written as "you can follow these tips to navigate to the Xpath".

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.