Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python (Selenium) - Invalid selector when using Xpath

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!

like image 238
an1que Avatar asked Nov 20 '25 15:11

an1que


2 Answers

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()
like image 151
Guy Avatar answered Nov 23 '25 04:11

Guy


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
    
like image 23
undetected Selenium Avatar answered Nov 23 '25 06:11

undetected Selenium