Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Downloading a file in new window in headless ChromeDriver #5722

Closed
Dejital opened this issue Apr 2, 2018 · 15 comments
Closed

Downloading a file in new window in headless ChromeDriver #5722

Dejital opened this issue Apr 2, 2018 · 15 comments

Comments

@Dejital
Copy link

Dejital commented Apr 2, 2018

Meta -

OS:
Windows 10
Selenium Version:
Selenium.WebDriver v3.11.0
Selenium.WebDriver.ChromeDriver v2.37.0
Browser:
Headless ChromeDriver

Expected Behavior -

Attempting to download a file using a headless ChromeDriver. The website being "driven" opens a new window on button click, which then triggers a download of a CSV file.

Actual Behavior -

var submitBtn = _driver.GetById("downloadSubmitBtn");
submitBtn.Click();

This does open a new Window. However, that window is not in focus in the ChromeDriver. If I switch to the Window, I get an error. There is no file downloaded to the default download directory. The following user preferences are set:

var downloadDirectory = "C:\\Temp";
var chromeOptions = new ChromeOptions();
chromeOptions.AddArguments(new List<string>() { "headless" });
chromeOptions.AddUserProfilePreference("download.default_directory", downloadDirectory);
chromeOptions.AddUserProfilePreference("download.prompt_for_download", false);
chromeOptions.AddUserProfilePreference("disable-popup-blocking", "true");
chromeOptions.AddUserProfilePreference("block_third_party_cookies", true);

return new ChromeDriver(chromeOptions);

Running the same code in not headless mode does open a new window, which does successfully down the file to the specified default directory (using same user profile preferences as above).

Steps to reproduce -

Page is unfortunately behind authentication and cannot be linked to directly.

@cgoldberg
Copy link
Contributor

@Dejital
Copy link
Author

Dejital commented Apr 2, 2018

@cgoldberg Sounds like there is no solution yet, but I'm not alone. Is there a way to temporarily "un-headless" the headless browser to just download the file?

@cgoldberg
Copy link
Contributor

@Dejital you can send an HTTP request to fetch the file directly (all the cookies you need are in your driver instance if auth is required)

@Dejital
Copy link
Author

Dejital commented Apr 2, 2018

@cgoldberg Tried and failed that, since fetching cookies from the driver throws an exception. -- ArgumentException on the Cookie object's Name. Presumably the website I'm authenticating against saves a cookie with no name. Same story for other WebDrivers as well. Somehow they work just fine on their own (authentication), but I can't get the cookies out to make the HTTP request.

@p0deje
Copy link
Member

p0deje commented Apr 3, 2018

Duplicate of #5159

@p0deje p0deje marked this as a duplicate of #5159 Apr 3, 2018
@p0deje p0deje closed this as completed Apr 3, 2018
@ppratikcr7
Copy link

ppratikcr7 commented Jan 24, 2019

It's easy. Call this enabler function after your switch window for your driver:

 def enable_download_in_headless_chrome(driver, download_dir):
    # add missing support for chrome "send_command"  to selenium webdriver
    driver.command_executor._commands["send_command"] = ("POST",'/session/$sessionId/chromium/send_command')
    params = {'cmd': 'Page.setDownloadBehavior', 'params': {'behavior': 'allow', 'downloadPath': download_dir}}
    command_result = driver.execute("send_command", params)

expected_download = 'ur/download/path'
opt = Options()
opt.add_experimental_option("prefs", { \
    'download.default_directory': expected_download,
     'download.prompt_for_download': False,
     'download.directory_upgrade': True,
  })
opt.add_argument('--headless')
opt.add_argument('--window-size=1920,1080');

login_page = "https://www.google.com"
driver = webdriver.Chrome(options=opt)
driver.implicitly_wait(5)
driver.get(login_page)
driver.maximize_window()

#On below click you will be in new tab
scoresheet_tab = driver.find_element_by_xpath("//*[@class='sideNav-item is--scoresheet']").click()

instances = driver.window_handles
driver.switch_to.window(instances[1]) # this is the new browser
#this below function below does all the trick
enable_download_in_headless_chrome(driver, expected_download)

@avmgan
Copy link

avmgan commented Jan 30, 2019

@ppratikcr7 - Is it possible to call using C#? where I can call this enabler function after the switch window for the driver?

1 similar comment
@avmgan
Copy link

avmgan commented Jan 30, 2019

@ppratikcr7 - Is it possible to call using C#? where I can call this enabler function after the switch window for the driver?

@avmgan
Copy link

avmgan commented Jan 30, 2019

ppratikcr7 - Is it possible to call using C#? where I can call this enabler function after the switch window for the driver?

@jimevans
Copy link
Member

@avmgan There is already support for executing Chrome Debug Protocol commands in the .NET bindings for ChromeDriver, so not all of the plumbing that is required for Python is required here. The C# equivalent would look something like this:

public void EnableDownloadInHeadlessChrome(ChromeDriver driver, string downloadDir)
{
    // There is no need to add support for the Chrome "send_command"; the ChromeDriver
    // class already has it built in.
    var params = new Dictionary<string, object>();
    params["behavior"] = "allow";
    params["downloadPath"] = downloadDir;
    driver.ExecuteChromeCommand("Page.setDownloadBehavior", params);
}

One small issue I'll take with @ppratikcr7's solution is that it assumes the handle with index 1 will be the new window (cf. driver.switch_to.window(instances[1])). This is a common misconception about getting window handles using driver.WindowHandles (driver.window_handles in Python). The handles returned by that property are absolutely not guaranteed to be in any order. Assuming "the handle in the collection with index 1 must be the most recently open window" is a ticking time bomb.

@cgoldberg
Copy link
Contributor

so not all of the plumbing that is required for Python is required here.

FWIW, it's not required in Python either :)

params = {'behavior': 'allow', 'downloadPath': dir}
driver.execute_cdp_cmd('Page.setDownloadBehavior', params)

@rishi1992
Copy link

Is it possible in Java?

@phenry9999
Copy link

Thank you for the Page.setDownloadBehavior, except I have a new problem. The default browser behavior is when you download file1.xml it download fine, then you download file1.xml again and normally Windows\browser will rename the file to file1 (1).xml (notice the brackets and number count). This number will increment as the same file is downloaded. This is the default behavior. The above code breaks this behavior. How do we get it back?

@amishad02
Copy link

@ppratikcr7 how can I do same for java please help.

@KrishnaYadav2102
Copy link

Thank you for the Page.setDownloadBehavior, except I have a new problem. The default browser behavior is when you download file1.xml it download fine, then you download file1.xml again and normally Windows\browser will rename the file to file1 (1).xml (notice the brackets and number count). This number will increment as the same file is downloaded. This is the default behavior. The above code breaks this behavior. How do we get it back?

I am also facing the same issue. Is there any solution to download multiple files with same name?

@lock lock bot locked and limited conversation to collaborators Aug 14, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

10 participants