How can I have a selenium download file?
Basically I want to at least check that a download-able file exists / download link works and preferably get stuff like the file size too.
Here's an example:
link = self.browser.find_element_by_link_text('link text')
href = link.get_attribute('href')
download = self.browser.get(href)
print download
That fourth line prints "None", presumably because I haven't manually clicked the Save button, and even if I had, I doubt WebDriver would be able to "see" the file.
Any ideas? I'm using Firefox as my browser-under-test, and I understand that the file handling for downloads is somewhat browser and/or OS-specific.
You can check the header response of the selenium download file to check that you get a 200 OK (or maybe a redirect, depending on your expected outcome) and it will tell you that a file exists.
Here is my implementation.
This finds the link on the page and extracts the URL being linked to. It then uses apache commons to replicate the browser session used by selenium and then download the file. There are some instances where it won't work (where the link found on the page does not actually link to the download file but a layer to prevent automated file download).
Generally, it works well and is cross-platform/cross-browser compliant.
The code is:
/*
* Copyright (c) 2010-2011 Ardesco Solutions - http://www.ardescosolutions.com
*
* Licensed under the Apache Licence, Version 2.0 (the "Licence");
* you may not use this file except in compliance with the Licence.
* You may obtain a copy of the Licence at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the Licence is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the Licence for the specific language governing permissions and
* limitations under the Licence.
*/
package com.lazerycode.ebselen.customhandlers;
import com.google.common.annotations.Beta;
import com.lazerycode.ebselen.EbselenCore;
import com.lazerycode.ebselen.handlers.FileHandler;
import org.apache.commons.httpclient.*;
import org.apache.commons.httpclient.cookie.CookiePolicy;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.GetMethod;
import java.io.*;
import java.net.URL;
import java.util.Set;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Beta
public class FileDownloader {
private static final Logger LOGGER = LoggerFactory.getLogger(EbselenCore.class);
private WebDriver driver;
private String downloadPath = System.getProperty("java.io.tmpdir");
public FileDownloader(WebDriver driverObject) {
this.driver = driverObject;
}
/**
* Get the current location that files will be downloaded to.
*
* @return The file path that the file will be downloaded to.
*/
public String getDownloadPath() {
return this.downloadPath;
}
/**
* Set the path that files will be downloaded to.
*
* @param filePath The file path that the file will be downloaded to.
*/
public void setDownloadPath(String filePath) {
this.downloadPath = filePath;
}
/**
* Load in all the cookies WebDriver currently knows about so that we can mimic the browser cookie state
*
* @param seleniumCookieSet
* @return
*/
private HttpState mimicCookieState(Set seleniumCookieSet) {
HttpState mimicWebDriverCookieState = new HttpState();
for (org.openqa.selenium.Cookie seleniumCookie : seleniumCookieSet) {
Cookie httpClientCookie = new Cookie(seleniumCookie.getDomain(), seleniumCookie.getName(), seleniumCookie.getValue(), seleniumCookie.getPath(), seleniumCookie.getExpiry(), seleniumCookie.isSecure());
mimicWebDriverCookieState.addCookie(httpClientCookie);
}
return mimicWebDriverCookieState;
}
/**
* Mimic the WebDriver host configuration
*
* @param hostURL
* @return
*/
private HostConfiguration mimicHostConfiguration(String hostURL, int hostPort) {
HostConfiguration hostConfig = new HostConfiguration();
hostConfig.setHost(hostURL, hostPort);
return hostConfig;
}
public String fileDownloader(WebElement element) throws Exception {
return downloader(element, "href");
}
public String imageDownloader(WebElement element) throws Exception {
return downloader(element, "src");
}
public String downloader(WebElement element, String attribute) throws Exception {
//Assuming that getAttribute does some magic to return a fully qualified URL
String downloadLocation = element.getAttribute(attribute);
if (downloadLocation.trim().equals("")) {
throw new Exception("The element you have specified does not link to anything!");
}
URL downloadURL = new URL(downloadLocation);
HttpClient client = new HttpClient();
client.getParams().setCookiePolicy(CookiePolicy.RFC_2965);
client.setHostConfiguration(mimicHostConfiguration(downloadURL.getHost(), downloadURL.getPort()));
client.setState(mimicCookieState(driver.manage().getCookies()));
HttpMethod getRequest = new GetMethod(downloadURL.getPath());
FileHandler downloadedFile = new FileHandler(downloadPath + downloadURL.getFile().replaceFirst("/|\\", ""), true);
try {
int status = client.executeMethod(getRequest);
LOGGER.info("HTTP Status {} when getting '{}'", status, downloadURL.toExternalForm());
BufferedInputStream in = new BufferedInputStream(getRequest.getResponseBodyAsStream());
int offset = 0;
int len = 4096;
int bytes = 0;
byte[] block = new byte[len];
while ((bytes = in.read(block, offset, len)) > -1) {
downloadedFile.getWritableFileOutputStream().write(block, 0, bytes);
}
downloadedFile.close();
in.close();
LOGGER.info("File downloaded to '{}'", downloadedFile.getAbsoluteFile());
} catch (Exception Ex) {
LOGGER.error("Download failed: {}", Ex);
throw new Exception("Download failed!");
} finally {
getRequest.releaseConnection();
}
return downloadedFile.getAbsoluteFile();
}
}