Josh Jones
Josh Jones

Reputation: 13

How to cancel a download at chrome://downloads with Selenium in Python 3

This question is very similar to Selenium webdriver can't find elements at chrome://downloads

I'm trying to use Selenium with Python (3) to get at the cancel button on the chrome://downloads page. My use case is that I have an obfuscated link for which a random token is generated every time a user clicks on it. If you don't click on it, you can't start the download (it seems to fire a piece of js that generates the token, but I haven't been successful in digging through the code to figure out how that happens).

For my test to pass, all I need is to verify that:

  1. The download starts (and doesn't give a 404), and
  2. The file it's trying to download is the right size.

The way that I'm trying to accomplish this is by triggering the download by clicking on the button element, then having Selenium open chrome://downloads, cancel the download, and capture the file size of the file that it attempted to download.

In theory this seems like it should work, the stumbling block is trying to access any elements in the #shadow-root tags on the chrome://downloads page. The solution to the other question which I linked above unfortunately no longer works:

driver = webdriver.Chrome("chromedriver.exe")
driver.get("chrome://downloads/")

manager = driver.find_element_by_css_selector('body/deep/downloads-manager')
item = manager.find_element_by_css_selector('body/deep/downloads-item')
shadow = driver.execute_script('return arguments[0].shadowRoot;', item)
link = shadow.find_element_by_css_selector('div#title-area>a')

file_url = link.get_attribute("href")

... as it fails on the item declaration line:

>>> item = manager.find_element_by_css_selector('body/deep/downloads-item')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python3.7/site-packages/selenium/webdriver/remote/webelement.py", line 430, in find_element_by_css_selector
    return self.find_element(by=By.CSS_SELECTOR, value=css_selector)
  File "/usr/local/lib/python3.7/site-packages/selenium/webdriver/remote/webelement.py", line 659, in find_element
    {"using": by, "value": value})['value']
  File "/usr/local/lib/python3.7/site-packages/selenium/webdriver/remote/webelement.py", line 633, in _execute
    return self._parent.execute(command, params)
  File "/usr/local/lib/python3.7/site-packages/selenium/webdriver/remote/webdriver.py", line 321, in execute
    self.error_handler.check_response(response)
  File "/usr/local/lib/python3.7/site-packages/selenium/webdriver/remote/errorhandler.py", line 242, in check_response
    raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate element: {"method":"css selector","selector":"body/deep/downloads-item"}
  (Session info: chrome=80.0.3987.149)

This is out of my area of expertise, and any help in figuring out how to get at the cancel button would be greatly appreciated.

Upvotes: 1

Views: 2733

Answers (2)

Hannan Javed
Hannan Javed

Reputation: 1

The previous answer by @supputuri works, however I needed to make a little modification which took hours to figure out. Here is the script that worked for me in case anyone else can't figure it out:

# navigate to chrome downloads page first
driver.get("chrome://downloads/")
driver.execute_script("document.querySelector('downloads-manager').shadowRoot.querySelector('#downloadsList downloads-item').shadowRoot.querySelector(\"button[id='cancel']\").click()")

The main changed part is button[id='cancel']

Upvotes: 0

supputuri
supputuri

Reputation: 14135

Please try the below.

driver.execute_script("document.querySelector('downloads-manager').shadowRoot.querySelector('#downloadsList downloads-item').shadowRoot.querySelector("cr-button[focus-type='cancel']").click()")

If you need more information how to work on the shadow-root elements, please refer here. And if you want to work on the downloads then you can refer to this and update the js as per your requirement.

Upvotes: 1

Related Questions