2

I've written a script in python with selenium to click on a certain link in a webpage to download an excel file. However, when I execute my script, it throws timeout exception. How can I make it work? Any help will be greatly appreciated.

Link to the site: webpage

Script I've tried with:

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.Chrome()
wait = WebDriverWait(driver, 10)
driver.get('replace_with_above_link')

item = wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, ".hasmore #dlink")))
item.click()
driver.quit()

Html elements which contain the dropdown options:

<li class="hasmore drophover"><span>Share &amp; more</span><div><ul><li><button class="tooltip" tip="Use a customizable report creator that can<br>output HTML, CSV, or a shareable link." id="share_on_ajax_result_table">Modify &amp; Share Table</button></li><li><button class="tooltip" tip="Get a bit of widget code to emed this table on your site">Embed this Table</button></li><li><button class="tooltip" tip="Convert the table below to comma-separated values<br>suitable for use with excel">Get as Excel Workbook (experimental)</button><a id="dlink" style="display: none;"></a></li><li><button class="tooltip" tip="Export table as <br>suitable for use with excel">Get table as CSV (for Excel)</button></li><li><button class="tooltip" tip="">Strip Mobile Formatting</button></li><li><a id="a_ajax_result_table" name="ajax_result_table" href="#ajax_result_table::none">Copy Link to Table to Clipboard</a></li><li><button class="tooltip" tip="">About Sharing Tools</button></li><li><button class="tooltip" tip=""><a href="https://www.youtube.com/watch?v=MWapXbaWs_U&amp;feature=youtu.be" target="_blank">Video: SR Sharing Tools &amp; How-to</a></button></li><li><button class="tooltip" tip=""><a href="https://www.youtube.com/watch?v=JkDLV0roT14&amp;feature=youtu.be" target="_blank">Video: Stats Table Tips &amp; Tricks</a></button></li></ul></div></li>

Location of that file in that webpage (the desired link is marked with pencil): enter image description here

SIM
  • 21,997
  • 5
  • 37
  • 109
  • Did u try to first move the cursor over to the "Share&more" element? – JACK ZHANG Mar 30 '18 at 20:44
  • Yes. I even clicked on the `share&more` link in the first place and found it working. Troubles come up when i try to initiate a click on the link I mentioned above. – SIM Mar 30 '18 at 20:52
  • The link actually results in file download and a SaveAs dialog. Set proper options for Chrome for automatic downlading (like here for example https://stackoverflow.com/questions/49053624/chrome-keep-asking-me-for-a-download-location-on-selenium-hub-driver-on-python/49054602#49054602) – Alexey Dolgopolov Mar 30 '18 at 21:22
  • Possible duplicate of [How to download any file and save it to the desired location using Selenium Webdriver](https://stackoverflow.com/questions/16746707/how-to-download-any-file-and-save-it-to-the-desired-location-using-selenium-webd) – SiKing Mar 30 '18 at 23:01
  • 1
    @SiKing, I went through your profile to see if you always mark different questions as duplicate which have been asked before? The answer is no. You try to solve them when you see you may be able to do so. However, take a look at [this link](https://stackoverflow.com/questions/44460076/retrieving-substring-in-selenium/49288883#49288883). That is your latest reply. Do you think that the linked question was unique? You tried to solve that because it was easy but when you come across any post like what I've posted here, you mark it as duplicate. What a joke!!!!! – SIM Mar 31 '18 at 02:14

2 Answers2

1

Target link is hidden and so wait for its visibility will always fail. You should try to handle button node instead:

item = wait.until(EC.visibility_of_element_located((By.XPATH, "//li[span='Share & more']")))
item.click()
wait.until(lambda driver: "drophover" in item.get_attribute("class"))
item.find_element_by_xpath("//button[.='Get as Excel Workbook (experimental)']").click()
Andersson
  • 51,635
  • 17
  • 77
  • 129
  • I tried it just now. It throws timeout exception when it hits the line containing `wait.until()`. Hope you take a look. Given plus one for this. Thanks sir. – SIM Apr 06 '18 at 09:50
  • Do you mean this line `item = wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, ".hasmore")))`? – Andersson Apr 06 '18 at 09:52
  • Nope sir. This line `wait.until(lambda driver: "drophover" in item.get_attribute("class"))`. – SIM Apr 06 '18 at 09:53
  • Yep. My mistake :) That's because `".hasmore"` selector is unreliable (note that there are more than 1 node with `"hasmore"` class name). Try updated answer – Andersson Apr 06 '18 at 10:02
  • Finally I did it sir. I needed a little twitch in your suggested approach. Perhaps you are not in a position to test. Thanks a zillion sir. This is what brought me success:`item = wait.until(EC.visibility_of_element_located((By.XPATH, "//li[span='Share & more']"))): item.click(): wait.until(EC.visibility_of_element_located((By.XPATH, "//button[.='Get as Excel Workbook (experimental)']"))).click() ` Semicolon for new lines. – SIM Apr 06 '18 at 10:30
  • Hmm... `time.sleep(5)` is not good :) Didi you get an exception without sleep? Maybe you need to replace `visibility_of_element_located` with `element_to_be_clickable` on last line? – Andersson Apr 06 '18 at 10:34
  • Without `time.sleep()` it works just fine. One last question sir: If i keep the line `driver.quit()` then the browser quits without downloading. Why sir? – SIM Apr 06 '18 at 10:36
  • You just performs the click on last line. Downloading process is not the selenium part, so it won't wait for downloading to be completed. Or did you mean that downloading doesn't even start? – Andersson Apr 06 '18 at 10:49
  • Downloading gets started and finished successfully if I take out `driver.quit()` this line. – SIM Apr 06 '18 at 10:53
  • 1
    Check [this ticket](https://stackoverflow.com/questions/34338897/python-selenium-find-out-when-a-download-has-completed) and let me know in case it doesn't help – Andersson Apr 06 '18 at 10:57
0

As you are trying to click on the link with text as Get as Excel Workbook (experimental) and as per your comment you are already able to click on the Share&more link in the first place and found it working next your intended <a> tagged element contains the attribute style set to display: none;. So to invoke click() to download you can use the following code block :

Get_as_Excel_Workbook_link = driver.find_element_by_xpath("//li[@class='hasmore drophover']//ul//li//a[@id='dlink']")
driver.execute_script("arguments[0].removeAttribute('style')", Get_as_Excel_Workbook_link)
Get_as_Excel_Workbook_link.click()

Update A

As per your comment :

comment

  • I am not sure if the xpath which you have used is a valid one or not :

    "//li[a[@id='dlink']]/a"
    
  • You tried using :

    Get_link = driver.find_element_by_xpath("//li[a[@id='dlink']]/a") 
    print(Get_link.get_attribute("outerHTML"))
    

But why? Is there any necessity?

  • As per my research and analysis you can be assured that you are at the right place. See the formatted version of the HTML you have shared and the resolution of the xpath I have provided.

<li class="hasmore drophover"><span>Share &amp; more</span>
  <div>
    <ul>
      <li><button class="tooltip" tip="Use a customizable report creator that can<br>output HTML, CSV, or a shareable link." id="share_on_ajax_result_table">Modify &amp; Share Table</button></li>
      <li><button class="tooltip" tip="Get a bit of widget code to emed this table on your site">Embed this Table</button></li>
      <li><button class="tooltip" tip="Convert the table below to comma-separated values<br>suitable for use with excel">Get as Excel Workbook (experimental)</button>
        <a id="dlink" style="display: none;"></a>
      </li>
      <li><button class="tooltip" tip="Export table as <br>suitable for use with excel">Get table as CSV (for Excel)</button></li>
      <li><button class="tooltip" tip="">Strip Mobile Formatting</button></li>
      <li><a id="a_ajax_result_table" name="ajax_result_table" href="#ajax_result_table::none">Copy Link to Table to Clipboard</a></li>
      <li><button class="tooltip" tip="">About Sharing Tools</button></li>
      <li><button class="tooltip" tip=""><a href="https://www.youtube.com/watch?v=MWapXbaWs_U&amp;feature=youtu.be" target="_blank">Video: SR Sharing Tools &amp; How-to</a></button></li>
      <li><button class="tooltip" tip=""><a href="https://www.youtube.com/watch?v=JkDLV0roT14&amp;feature=youtu.be" target="_blank">Video: Stats Table Tips &amp; Tricks</a></button></li>
    </ul>
  </div>
</li>
  • So the result you have seen is pretty correct. Now, for you understanding I have inserted some text as MyLink within the intended tag :

    <a id="dlink" style="display: none;"></a>
    
  • Converted as :

    <a id="dlink" style="display: none;">MyLink</a>
    
  • See the result :

result

  • Check out my solution once again I can ensure that works.

Update B

unable to locate element is good message to debug perhaps apart from "display: none;" you have pulled a rug over the actual issue by mentioning clicked on the share&more link in the first place and found it working. Troubles come up when i try to initiate a click on the link.

If you observe the HTML the element is within class="tooltip" so you need to induce a waiter as follows :

//perform click on the link Share&more
Get_as_Excel_Workbook_link = WebDriverWait(driver, 20).until(EC.visibility_of_element_located((By.XPATH, "//li[@class='hasmore drophover']//ul//li//a[@id='dlink']")))
driver.execute_script("arguments[0].removeAttribute('style')", Get_as_Excel_Workbook_link)
Get_as_Excel_Workbook_link.click()
undetected Selenium
  • 183,867
  • 41
  • 278
  • 352
  • Thanks a lot for your solution @DebanjanB. It looks promising. As soon as I'm near my pc I'm gonna let you know the feedback. – SIM Mar 31 '18 at 09:45
  • I tried it just now but unfortunately it could not do the trick. To be specific I tried using `Get_link = driver.find_element_by_xpath("//li[a[@id='dlink']]/a") print(Get_link.get_attribute("outerHTML"))` as well to see if I'm in the right place. The result it produces is ``. Turn out that there is no such link to be clicked. – SIM Mar 31 '18 at 13:01
  • @Topto Check out my answer update and let me know the status. – undetected Selenium Mar 31 '18 at 13:56
  • I tried with your suggested portion several times. Every time it throws `unable to locate element` error. However, I tried your `xpath` `//li[@class='hasmore drophover']//ul//li//a[@id='dlink']` in the chrome console as well to see if it is able to locate the desired portion. But it could not. Then finally I tried with this `//li[contains(@class,'hasmore')]//ul//li//a[@id='dlink']` in the chrome and found it locating the desired portion. When I tried the same within the script then I encounter `element not visible error`. This is the total status. – SIM Mar 31 '18 at 14:44
  • Check out my answer update and let me know the status. – undetected Selenium Mar 31 '18 at 15:55