1

After click the button, how to know the downloading url(with the filename), or

how to know the filename(complete with extension) being downloaded? One problem is, e.g. the downloaded file some have .csv extension, some without.

e.g. I would like to rename it unified. (pls. don't wanna go to the D/L DIR, find the file and rename it)

from selenium import webdriver
from selenium.webdriver.firefox.options import Options 
...
profile.set_preference('browser.helperApps.neverAsk.saveToDisk', 'text/csv')
...
driver = webdriver.Firefox(profile, options=opts, executable_path=FIREFOX_GOCKO_DRIVER_PATH)

driver.get(url)
driver.find_element_by_id(Button).click()

print("The file being downloaded is... ", ??? )
print("File is being downloaded from...", ?url?)
Greg Burghardt
  • 17,900
  • 9
  • 49
  • 92
NegaOverflow
  • 138
  • 1
  • 11

2 Answers2

13

Here is the simple solution to get the latest downloaded file name and url.

Note: considering the file download is completed before running this below code.

If you want the script wait until the download completed, then check the getDownLoadedFileName method at the end of the answer.

# open a new tab
driver.execute_script("window.open()")
# switch to new tab
driver.switch_to.window(driver.window_handles[-1])
# navigate to chrome downloads
driver.get('chrome://downloads')
# get the latest downloaded file name
fileName = driver.execute_script("return document.querySelector('downloads-manager').shadowRoot.querySelector('#downloadsList downloads-item').shadowRoot.querySelector('div#content  #file-link').text")
# get the latest downloaded file url
sourceURL = driver.execute_script("return document.querySelector('downloads-manager').shadowRoot.querySelector('#downloadsList downloads-item').shadowRoot.querySelector('div#content  #file-link').href")
# print the details
print(fileName)
print (sourceURL)
# close the downloads tab2
driver.close()
# switch back to main window
driver.switch_to.window(driver.window_handles[0])

if you want you can make it as a method and call where ever it's required.

Edit: Don't worry if you have to wait until the download completed

You can relay on chrome downloads status, check the below method.

Just call the below method in you code while getting the file name

def getDownLoadedFileName(waitTime):
    downloadsList = driver.execute_script("return document.querySelector('downloads-manager').shadowRoot")
    endTime = time.time()+waitTime
    while True:
        try:
            fileName = driver.execute_script("return document.querySelector('downloads-manager').shadowRoot.querySelector('#downloadsList downloads-item').shadowRoot.querySelector('div#content  #file-link').text")
            if fileName:
                return fileName
        except:
            pass
        time.sleep(1)
        if time.time() > endTime:
            break

You can call this method as shown below.

# wait until the download completes and get the file name
fileName = getDownLoadedFileName(180)
print(fileName)

Firefox: Use the below method for firefox.

def getDownLoadedFileName(waitTime):
    driver.execute_script("window.open()")
    WebDriverWait(driver,10).until(EC.new_window_is_opened)
    driver.switch_to.window(driver.window_handles[-1])
    driver.get("about:downloads")

    endTime = time.time()+waitTime
    while True:
        try:
            fileName = driver.execute_script("return document.querySelector('#contentAreaDownloadsView .downloadMainArea .downloadContainer description:nth-of-type(1)').value")
            if fileName:
                return fileName
        except:
            pass
        time.sleep(1)
        if time.time() > endTime:
            break

Java + Chrome: In case if you are looking for java implementation.

Here is the method in java.

public String waitUntilDonwloadCompleted(WebDriver driver) throws InterruptedException {
      // Store the current window handle
      String mainWindow = driver.getWindowHandle();

      // open a new tab
      JavascriptExecutor js = (JavascriptExecutor)driver;
      js.executeScript("window.open()");
     // switch to new tab
    // Switch to new window opened
      for(String winHandle : driver.getWindowHandles()){
          driver.switchTo().window(winHandle);
      }
     // navigate to chrome downloads
      driver.get("chrome://downloads");

      JavascriptExecutor js1 = (JavascriptExecutor)driver;
      // wait until the file is downloaded
      Long percentage = (long) 0;
      while ( percentage!= 100) {
          try {
              percentage = (Long) js1.executeScript("return document.querySelector('downloads-manager').shadowRoot.querySelector('#downloadsList downloads-item').shadowRoot.querySelector('#progress').value");
              //System.out.println(percentage);
          }catch (Exception e) {
            // Nothing to do just wait
        }
          Thread.sleep(1000);
      }
     // get the latest downloaded file name
      String fileName = (String) js1.executeScript("return document.querySelector('downloads-manager').shadowRoot.querySelector('#downloadsList downloads-item').shadowRoot.querySelector('div#content #file-link').text");
     // get the latest downloaded file url
      String sourceURL = (String) js1.executeScript("return document.querySelector('downloads-manager').shadowRoot.querySelector('#downloadsList downloads-item').shadowRoot.querySelector('div#content #file-link').href");
      // file downloaded location
      String donwloadedAt = (String) js1.executeScript("return document.querySelector('downloads-manager').shadowRoot.querySelector('#downloadsList downloads-item').shadowRoot.querySelector('div.is-active.focus-row-active #file-icon-wrapper img').src");
      System.out.println("Download deatils");
      System.out.println("File Name :-" + fileName);
      System.out.println("Donwloaded path :- " + donwloadedAt);
      System.out.println("Downloaded from url :- " + sourceURL);
     // print the details
      System.out.println(fileName);
      System.out.println(sourceURL);
     // close the downloads tab2
      driver.close();
     // switch back to main window
      driver.switchTo().window(mainWindow);
      return fileName;
  }

This is how to call this in your java script.

// download triggering step 
downloadExe.click();
// now waituntil download finish and then get file name
System.out.println(waitUntilDonwloadCompleted(driver));
supputuri
  • 13,644
  • 2
  • 21
  • 39
  • Check the `getDownLoadedFileName` method that will make sure the download is completed before getting the name. You can pass the number of second to complete the download. Eg: I mentioned it as `180` seconds in my `getDownLoadedFileName(180)` method call in above answer. – supputuri Jun 12 '19 at 04:11
  • thanks! I add your code direct after click(), it goes until "fileName = driver.execute_script(", then got error "Message: javascript error: Cannot read property 'shadowRoot' of null (Session info: headless chrome=74.0.3729.169)" , I read [this link](https://stackoverflow.com/questions/23920167/accessing-shadow-dom-tree-with-selenium/37253205), shadowRoot still buggy? – NegaOverflow Jun 12 '19 at 12:06
  • Try with `fileName =getDownloadedFileName(180)` rather than `fileName = driver.execute_script(` by that way the method will make sure `shadowroot` is displayed before getting the fileName. You can see the `def getDownloadedFileName` implementation at the end of my answer. – supputuri Jun 12 '19 at 13:05
  • I put the def subroutine a the top, and call it after click(), still the same error : >> Message: javascript error: Cannot read property 'shadowRoot' of null (Session info: chrome=74.0.3729.169) (Driver info: chromedriver=74.0.3729.6 (255758eccf3d244491b8a1317aa76e1ce10d57e9-refs/branch-heads/3729@{#29}),platform=Mac OS X 10.13.6 x86_64) BTW: I read chrome headless download is still buggy > [a lot here](https://bugs.chromium.org/p/chromium/issues/detail?id=696481#c86), but still not fixed in headless, but can D/L all w/o headless. would you mind using Firefox as OP asked? thx! – NegaOverflow Jun 12 '19 at 14:20
  • check the udpated answer with the solution for firefox, however firefox doesn't store downloaded url in the downloads window, so you have to get the url from the element src/href before clicking in firefox. – supputuri Jun 12 '19 at 15:28
  • thanks! let's me check later... first upvote yours and accept it as answer. – NegaOverflow Jun 12 '19 at 16:40
  • @NegaOverflow Did you got a chance to check if the updated answer worked. – supputuri Jul 07 '19 at 03:49
  • 6
    In headless mode I get `selenium.common.exceptions.JavascriptException: Message: javascript error: Cannot read property 'shadowRoot' of null`. – Julio Batista Silva May 08 '20 at 19:35
  • This was done on normal mode, will check for headless. – supputuri May 08 '20 at 19:38
  • I'm stumped. For `fileName`, I keep getting `Message: javascript error: Cannot read property 'shadowRoot' of null` for about a few minutes and then suddenly it starts working. However, it takes a very long time to do so e.g. over 5 mins. Is there any way to reduce this time? – nabil.adnan1610 Mar 06 '22 at 23:08
2

Inspired by the work of @supputuri here is my implementation of waitUntilDownloadCompleted() written in C#.

    public static void waitUntilDownloadCompleted(this IWebDriver driver, string newFileName)
    {
        string scriptFileName, scriptPercentage, downloadsURL, fileName;

        switch (driver.GetType().ToString())
        {
            case "OpenQA.Selenium.Chrome.ChromeDriver":
                // sourceURL: use "document.querySelector('downloads-manager').shadowRoot.querySelector('#downloadsList downloads-item').shadowRoot.querySelector('div#content #file-link').href"
                // downloadLocation: use "document.querySelector('downloads-manager').shadowRoot.querySelector('#downloadsList downloads-item').shadowRoot.querySelector('div.is-active.focus-row-active #file-icon-wrapper img').src"
                scriptFileName = "return document.querySelector('downloads-manager').shadowRoot.querySelector('#downloadsList downloads-item').shadowRoot.querySelector('div#content #file-link').text";
                scriptPercentage = "return document.querySelector('downloads-manager').shadowRoot.querySelector('#downloadsList downloads-item').shadowRoot.querySelector('#progress').value";
                downloadsURL = "chrome://downloads";
                break;

            case "OpenQA.Selenium.Firefox.FirefoxDriver":
                scriptFileName = "return document.querySelector('#contentAreaDownloadsView description:nth-of-type(1)').value";
                scriptPercentage = "return document.querySelector('#contentAreaDownloadsView richlistitem.download:nth-child(1) > hbox:nth-child(1) > vbox:nth-child(2) > progress:nth-child(2)').value";
                downloadsURL = "about:downloads";
                break;

            default:
                throw new NotImplementedException(string.Format("Driver {0} is not supported", driver.GetType().ToString()));
        }

        // Store the current window handle
        string mainWindow = driver.CurrentWindowHandle;

        // open new tab and switch focus
        IJavaScriptExecutor js = driver as IJavaScriptExecutor;
        driver.SwitchTo().Window(mainWindow);
        js.ExecuteScript("window.open();");
        driver.SwitchTo().Window(driver.WindowHandles.Last());

        // navigate to downloads
        driver.Navigate().GoToUrl(downloadsURL);

        // wait until download is complete
        IJavaScriptExecutor js1 = driver as IJavaScriptExecutor;
        long percentage = 0;
        while (percentage != 100)
        {
            try
            {
                percentage = (long)js1.ExecuteScript(scriptPercentage);
            }
            catch (Exception)
            {
                // Nothing to do just wait
            }
            Thread.Sleep(1000);
        }

        // get the latest downloaded file name
        fileName = Path.Combine(Environment.ExpandEnvironmentVariables("%USERPROFILE%"), "Downloads", (string)js1.ExecuteScript(scriptFileName));

        // close the downloads tab
        driver.Close();

        // switch back to main window
        driver.SwitchTo().Window(mainWindow);
        driver.wait_A_Moment(timeDelay);

        // delete if new file exists
        if (File.Exists(newFileName))
            File.Delete(newFileName);

        // rename downloaded file
        File.Move(fileName, newFileName);
        File.Delete(fileName);
    }
Gene Yuss
  • 33
  • 5