5

I can't get Selenium and Chrome (Canary) to download a file. I'm using Java and and Chrome 59/60 (because my tests are both for Windows and Linux) and I'm trying to start the download of a file from a webpage.

When I, from selenium, do NOT set the headless mode, the chrome window opens and the file is downloaded.

When I do set the --headless flag, the chrome window does not open and the download does not start.

    public static void chromeDownload() throws IOException, InterruptedException{
            
            ChromeOptions options = new ChromeOptions();
            String downloadFilepath = "";
            
            if (ValidateOS.isWindows()){
                System.out.println("This is a Windows system.");
                System.setProperty("webdriver.chrome.driver", "resources\\driver\\chromedriver.exe");
                options.setBinary("C:\\Users\\Juri\\AppData\\Local\\Google\\Chrome SxS\\Application\\chrome.exe");
                downloadFilepath = "C:\\";
            } else if (ValidateOS.isUnix()){
                System.out.println("This is a Unix system.");
                System.setProperty("webdriver.chrome.driver", "resources/driver/chromedriver");
                options.setBinary("/usr/bin/google-chrome");
                downloadFilepath = "/home/juri/";
            }
            
            // Manage the download
            HashMap<String, Object> chromePrefs = new HashMap<>();
            chromePrefs.put("profile.default_content_settings.popups", 0);
            chromePrefs.put("download.default_directory", downloadFilepath);
    
            // Save Chrome Options
            HashMap<String, Object> chromeOptionsMap = new HashMap<>();
            options.setExperimentalOption("prefs", chromePrefs);
            options.addArguments("--headless --disable-gpu");
            
            DesiredCapabilities cap = DesiredCapabilities.chrome();
            cap.setCapability(ChromeOptions.CAPABILITY, chromeOptionsMap);
            cap.setCapability(CapabilityType.ACCEPT_SSL_CERTS, true);
            cap.setCapability(ChromeOptions.CAPABILITY, options);
            
            ChromeDriver driver = new ChromeDriver(cap);
                    
            driver.get("http://localhost/my-test-page.html");

            driver.findElement(By.id("download")).click(); 
            Thread.sleep(5000); // wait 5 seconds for a small file to download.. yes.. I know...
            driver.quit();
        }

At the Click, in GUI mode the download starts. In Headless mode, it doesn't.

How to solve?

OT

I am using Chrome Canary which at its v.60 comes with the --headless feature. Ultra handy for running the grabber on a server without gui. But, for the same reason.. I find it useless to download Chrome on a server without GUI. Beside the main question.. I wonder if you, developers, think that it is okay to install chrome on a Linux server just for starting it in headless mode.

Update: I'm still looking for a solution if someone will ever read this :/ Search results there are a few and I tried them all

Community
  • 1
  • 1
aPugLife
  • 989
  • 2
  • 14
  • 25
  • someone asked a similar question recently which was answered, https://stackoverflow.com/questions/45631715/downloading-with-chrome-headless-and-selenium . apparently headless chrome prevents downloads unless it has been approved via a setting in dev tools – Karan Shishoo Aug 15 '17 at 22:33
  • @kshishoo hi! I'm so happy someone noticed my question. The new question is exactly what I'm looking for weeks now. I'll try working on this project again, mine is completed but I installed a Ubuntu GUI on a test server to have it working. If the headless works in this workaround, well, that's amazing! – aPugLife Aug 16 '17 at 14:01
  • Is there any update on that case? I found a code solution for Java https://bugs.chromium.org/p/chromium/issues/detail?id=696481#c93 I haven't tested it. Anyway I am looking for a shorter solution. – skymedium Mar 27 '18 at 14:18

2 Answers2

0

Solved by adapting the code found at this link: Download files in Java, Selenium using ChromeDriver and headless mode

For those who wonder how's my code now...

public static void chromeDownload(String address, String Headless, String DownDir) throws IOException, InterruptedException{

    ChromeOptions options = new ChromeOptions();
    String downloadFilepath = DownDir;

    if (ValidateOS.isWindows()){
        System.out.println("This is a Windows system.");
        System.setProperty("webdriver.chrome.driver", "resources\\driver\\chromedriver.exe");
        //options.setBinary("C:\\Users\\Juri\\AppData\\Local\\Google\\Chrome SxS\\Application\\chrome.exe");
        // If this is commented, the grabber will use the main Chrome
    } else if (ValidateOS.isUnix()){
        System.out.println("This is a Unix system.");
        System.setProperty("webdriver.chrome.driver", "resources/driver/chromedriver");
        options.setBinary("/usr/bin/google-chrome");
    }

    switch (Headless.toUpperCase()){
        case "TRUE":
            options.addArguments("--headless --disable-gpu");
            break;
        case "FALSE":
        default:
            options.addArguments("--window-size=1152,768");
            break;
    }
    options.addArguments("--test-type");
    options.addArguments("--disable-extension");

    ChromeDriverService driverService = ChromeDriverService.createDefaultService();
    ChromeDriver driver = new ChromeDriver(driverService, options);

    Map<String, Object> commandParams = new HashMap<>();
    commandParams.put("cmd", "Page.setDownloadBehavior");
    Map<String, String> params = new HashMap<>();
    params.put("behavior", "allow");
    params.put("downloadPath", downloadFilepath);
    params.put("cmd", "Page.setDownloadBehavior");

    commandParams.put("params", params);
    ObjectMapper objectMapper = new ObjectMapper();
    CloseableHttpClient httpClient = HttpClientBuilder.create().build();
    String command = objectMapper.writeValueAsString(commandParams);
    String u = driverService.getUrl().toString() + "/session/" + driver.getSessionId() + "/chromium/send_command";
    HttpPost request = new HttpPost(u);
    request.addHeader("content-type", "application/json");
    request.setEntity(new StringEntity(command));
    httpClient.execute(request);

    driver.get(address);

    driver.findElement(By.id("download")).click(); 
    driver.quit();
}
aPugLife
  • 989
  • 2
  • 14
  • 25
  • 2
    can you describe your code rather than copying it from someone else post. Your code doesnot work – Poltu Apr 09 '18 at 16:47
  • This doesnot work for pdf files which opens in new tab – Poltu Apr 10 '18 at 13:23
  • @Poltu -- Be sure to set your content type to support pdf. Also be aware that chrome tried to open pdf's inline, which can be disabled (there's other topics about this: like this https://stackoverflow.com/questions/31672897/how-to-download-a-pdf-file-in-chrome-using-selenium-webdriver ) – A_Elric Apr 20 '18 at 16:49
0

Do you anticipate using "Docker"? launch dockerized Ubuntu with selenium Grid and any amount of browsers. Or just browser without Selenium grid.

You'd have no need to use headless mode on the other hand you could you multi-threading. Ex:

  1. Download the file.

  2. Then just launch in using the following command: docker-compose up -d

  3. a few tweaks per your server to access grid server on "localhost"
    http://localhost:4444/grid/console http://localhost:4444/wd/hub

  4. Use the following code:

    WebDriver driver = new RemoteWebDriver(new URL("http://localhost:4444/wd/hub")); //handle exception on URL() constructor.

  5. you have lightweight virtual machines with browsers any amount which your sever can handle. And no need of --headless mode

It's not the solution of the initial issue though.

Rot-man
  • 18,045
  • 12
  • 118
  • 124