When I click on a button in chrome, it downloads a jpg file.
But when I am using phantomjs it doesn't download the jpg nor gives any error.
example: https://deepak5j.github.io/HelloProjectPage/download.html
How to download file with phantomjs ?
Using casperjs (based on phantomjs) :
var casper = require("casper").create();
casper.start('https://deepak5j.github.io/HelloProjectPage/download.html', function() {
var url = 'https://raw.githubusercontent.com/Deepak5j/WebImages/master/Tiles/';
this.download(url, 'sun_tile.jpg');
});
casper.run(function() {
this.exit();
});
Button click with phantom will not download file but after click you can get file as input stream. So you can save input stream to file. Code below will give an idea:
driver.findElement(By.className("Download")).click();
List<LogEntry> harLogEntries = driver.manage().logs().get("har").getAll();
LogEntry lastLogEntry = harLogEntries.get(harLogEntries.size() - 1);
String lastRequestUrl = getRequestUrlFromHarLogEntry(lastLogEntry);
DefaultHttpClient client;
HttpResponse response;
HttpGet get = new HttpGet(lastRequestUrl);
response = client.execute(get);
InputStream dataStream = response.getEntity().getContent();
I will share getRequestUrlFromHarLogEntry below:
private String getRequestUrlFromHarLogEntry(LogEntry logEntry)
throws Exception {
ObjectMapper objectMapper = new ObjectMapper();
Map<String, Object> message = objectMapper.readValue(logEntry.getMessage(), Map.class);
Map<String, Object> log = (Map<String, Object>) message.get("log");
List<Object> entries = (List<Object>) log.get("entries");
Map<String, Object> lastEntry = (Map<String, Object>) entries.get(entries.size() - 1);
Map<String, Object> request = (Map<String, Object>) lastEntry.get("request");
String url = (String) request.get("url");
return url;
}
Hope this helps..
Related
The Http Client step of pentaho only allows download of text files.
How can I download binary files with Pentaho?
Add a Modified Java Script Value with the following code
var fileURL = "https://hp.imguol.com.br/c/home/b1/2018/05/26/mohamed-salah-chora-apos-se-machucar-em-lance-com-sergio-ramos-1527363329053_300x300.jpg";
var url = java.net.URL(fileURL);
var httpConn = url.openConnection();
// opens input stream from the HTTP connection
var inputStream = httpConn.getInputStream();
var saveFilePath = "d:/myfile10.jpg";
var bis = java.io.BufferedInputStream(inputStream);
var bos = java.io.BufferedOutputStream(java.io.FileOutputStream(java.io.File(saveFilePath)));
var inByte;
while((inByte = bis.read()) != -1) {
bos.write(inByte);
}
bis.close();
bos.close();
I downloaded the latest version of chromium, to test out the headless feature.
When I run (as root, because I'm still testing things):
./chrome --no-sandbox http://cp7.awardspace.com/speed-test/awardspace-data1mb.zip
In the GUI terminal, it opens Chromium and downloads the file.
If I'm trying to run it headless, I enter the following:
./chrome --no-sandbox --headless http://cp7.awardspace.com/speed-test/awardspace-data1mb.zip
The terminal outputs some information, no window gets opened, but also: I don't have the file downloaded anywhere.
I have been scouting the internet and discussion groups for more information, but cannot find anything.
Is file downloading not working in headless mode for Chromium?
That's a reported bug in headless implementation:
https://bugs.chromium.org/p/chromium/issues/detail?id=696481
Use ChromeDriverService and POST session/{sessionId}/chromium/send_command
JSON for POST:
{
"cmd": "Page.setDownloadBehavior",
"params": {
"behavior": "allow",
"downloadPath": "C:\\Download\\Path"
}
}
C# Solution
Add reference to System.Net.Http and use NuGet to install Newtonsoft.JSON.
public static IWebDriver Driver { get; private set; }
public void SetDriver()
{
var chromeOptions = new ChromeOptions();
chromeOptions.AddArguments("--headless", "--window-size=1920,1080");
var driverService = ChromeDriverService.CreateDefaultService();
Driver = new ChromeDriver(driverService, chromeOptions);
Task.Run(() => AllowHeadlessDownload(driverService));
}
static async Task AllowHeadlessDownload(ChromeDriverService driverService )
{
var jsonContent = new JObject(
new JProperty("cmd", "Page.setDownloadBehavior"),
new JProperty("params",
new JObject(new JObject(
new JProperty("behavior", "allow"),
new JProperty("downloadPath", #"C:\Download\Path")))));
var content = new StringContent(jsonContent.ToString(), Encoding.UTF8, "application/json");
var sessionIdProperty = typeof(ChromeDriver).GetProperty("SessionId");
var sessionId = sessionIdProperty.GetValue(Driver, null) as SessionId;
using (var client = new HttpClient())
{
client.BaseAddress = driverService.ServiceUrl;
var result = await client.PostAsync("session/" + sessionId.ToString() + "/chromium/send_command", content);
var resultContent = await result.Content.ReadAsStringAsync();
}
}
In Java use following code :
System.setProperty("webdriver.chrome.driver", "/usr/local/bin/chromedriver");
ChromeOptions options = new ChromeOptions();
options.addArguments("--test-type");
options.addArguments("--headless");
options.addArguments("--disable-extensions"); //to disable browser extension popup
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", "//home//vaibhav//Desktop");
commandParams.put("params", params);
ObjectMapper objectMapper = new ObjectMapper();
HttpClient 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("http://www.seleniumhq.org/download/");
driver.findElement(By.linkText("32 bit Windows IE")).click();
The following code works in C# using ChromeDriver 2.46
private ChromeDriver GetDriver()
{
var options = new ChromeOptions();
options.AddArguments("headless");
options.AddUserProfilePreference("download.prompt_for_download", "false");
options.AddUserProfilePreference("download.directory_upgrade", "true");
options.AddUserProfilePreference("download.prompt_for_download", "false");
options.AddUserProfilePreference("safebrowsing.enabled", "false");
options.AddUserProfilePreference("safebrowsing.disable_download_protection", "true");
options.AddArguments("--disable-web-security");
var curr = Directory.GetCurrentDirectory();
options.AddUserProfilePreference("download.default_directory", curr);
var driver = new ChromeDriver(options);
Log.Info($"Started Chrome Driver with options: {options.ToJsonNoTypes()}");
var param = new Dictionary<string, object>();
param.Add("behavior", "allow");
param.Add("downloadPath", curr);
driver.ExecuteChromeCommand("Page.setDownloadBehavior", param);
return driver;
}
Note: Not exactly answer to the question, but solves the problem
I researched a lot on making headless chrome download with different parameters/options/preferences, but nothing worked. Then I used standard Java way of downloading file using Apache Commons's FileUtils
FileUtils.copyURLToFile(URI, FILE);
I was able to download files with chrome headless thanks to Chrome Remote Interface
public void TryEnableFileDownloading(string downloadPath)
{
TrySendCommand("Page.setDownloadBehavior", new Dictionary<string, object>()
{
["behavior"] = "allow",
["downloadPath"] = downloadPath
});
}
Full code for integration with selenium could be found here
https://github.com/cezarypiatek/Tellurium/blob/master/Src/MvcPages/SeleniumUtils/ChromeRemoteInterface/ChromeRemoteInterface.cs
More info about setDownloadBehavior and Chrome Remote interface
https://chromedevtools.github.io/devtools-protocol/tot/Page/#method-setDownloadBehavior
I tried today in IdeaJ editor, Java and Maven on Windows 10, and it's working fine:
ChromeOptions ds = getDesiredCapabilities(browserName);
ChromeDriverService driverService = ChromeDriverService.createDefaultService();
ChromeDriver driver = new ChromeDriver(driverService, ds);
Map<String, Object> commandParams = new HashMap<>();
commandParams.put("cmd", "Page.setDownloadBehavior");
Map<String, String> params = new HashMap<>();
params.put("behavior", "allow");
params.put("downloadPath", System.getProperty("user.home") + File.separator + "Downloads");
commandParams.put("params", params);
ObjectMapper objectMapper = new ObjectMapper();
HttpClient 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);
User this configured "driver" instance to navigate to download file either by URL or by Json/AngularJs download action.
Also it sometimes behaved to corrupt file while downloading due to internet slowness.
More on this, same configuration will work for both Google Chrome UI or Headless execution in latest chrome driver 77~
I am massively stuck with converting a PHP server request into an equivalent Java Request. This is the code that contains the JSON object that I need to replicate in JAVA and send from an Android device:
$(".unableprocess").click(function() {
if (!confirm("Confirm not able to process...!")) {
return false;
} else {
var item_id = $(this).attr('data-id');
var table_id = $(this).attr('table-id');
var data = {
BookOrders: {
item_id: item_id,
table_id: table_id
}
};
$.ajax({
url: //MY URL HERE ,
type: "POST",
data: data,
success: function(evt, responseText) {
location.reload();
}
});
}
});
And here is my Java class that attempts to perform the same functionality. The class extends AsyncTask and all network interactions occur in the doInBackground() method. Here is my code:
#Override
protected Boolean doInBackground(String... arg0) {
try{
HashMap<String, String> hashMap = new HashMap<String,String>();
JSONObject jsonObject = new JSONObject();
int statusCode;
HttpClient client = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(tableMateCannotProcessURL);
// JSON object creation begins here:
jsonObject.accumulate("item_id",this.itemId);
jsonObject.accumulate("table_id",this.tableId);
JSONObject jObject = new JSONObject();
jObject.accumulate("BookOrders", jsonObject);
// JSON object ends here
Log.v("ATOMIC BLAST",jObject.toString());
String json = jObject.toString();
StringEntity se = new StringEntity(json);
httpPost.setEntity(se);
HttpResponse response = client.execute(httpPost);
statusCode = response.getStatusLine().getStatusCode();
Integer statusCodeInt = new Integer(statusCode);
Log.v("HTTPResponse",statusCodeInt.toString());
String result= "";
StringBuilder builder = new StringBuilder();
if (statusCode == 200) {
HttpEntity entity = response.getEntity();
InputStream content = entity.getContent();
BufferedReader reader = new BufferedReader(new InputStreamReader(content));
String line;
while ((line = reader.readLine()) != null) {
builder.append(line);
}
result = builder.toString();
}
else {
Log.e("==>", "Failed to download file");
}
}
catch(Exception e){
e.printStackTrace();
}
return null;
}
The JSON object that I created looks like this after printing it out to the console:
{"BookOrders":{"table_id":"1","item_id":"2"}}
After POSTing this object to the server I do not get the expected response. What is the proper method for converting the JSON object into an equivalent JSON object in JAVA? Any guidance, direction or a solution would be most appreciated.
Update php to version 5.4 helped me.
In this version json_encode($x, JSON_PRETTY_PRINT) works just as needed.
Your JSON seems to be correct but it's an Object in an Object.
JSONObject json = new JSONObject(yourdata);
JSONObject jsonTable = new JSONObject(json.getString("BookOrders"));
Log.d("JsonDebug", "json:" + jsonTable.toString());
If you are not sure if you have a JSONObject or an Array you can validate it by using
String data = "{ ... }";
Object json = new JSONTokener(data).nextValue();
if (json instanceof JSONObject)
//you have an object
else if (json instanceof JSONArray)
//you have an array
running(fakeApplication(), new Runnable() {
public void run() {
Content html = views.html.index.render(loginForm);
assertThat(contentType(html)).isEqualTo("text/html");
assertThat(contentAsString(html)).contains("log in");
}
});
We use this code to test that a view is rendered properly, but the problem is that the text in the view doesn't use the Messages.en-file we have specified for our actual application (so it renderes login.login instead of "log in" for instance).
Is there a way to configure the fakeapplication to use a specific langauge (and then have it look for the appropriate messages-file)?
We tried this to no avail:
Map<String, String> config = new HashMap<String, String>();
config.put("application.langs", "en");
FakeApplication fakeApp = new FakeApplication(additionalConfiguration = config);
Try this:
Map<String, String> config = new HashMap<String, String>();
config.put("application.langs", "en");
FakeApplication fakeApp = new FakeApplication(new java.io.File("conf/"), Helpers.class.getClassLoader(), config, , new ArrayList<String>())`;
I was wondering, how can one use selenium/webdriver to download an image for a page. Assuming that the user session is required to download the image hence having pure URL is not helpful. Any sample code is highly appreciated.
I prefer doing something like this :
1. Get the SRC attribute of the image.
2. Use ImageIO.read to read the image onto a BufferedImage
3. Save the BufferedImage using ImageIO.write function
For e.g.
String src = imgElement.getAttribute('src');
BufferedImage bufferedImage = ImageIO.read(new URL(src));
File outputfile = new File("saved.png");
ImageIO.write(bufferedImage, "png", outputfile);
I prefer like this:
WebElement logo = driver.findElement(By.cssSelector(".image-logo"));
String logoSRC = logo.getAttribute("src");
URL imageURL = new URL(logoSRC);
BufferedImage saveImage = ImageIO.read(imageURL);
ImageIO.write(saveImage, "png", new File("logo-image.png"));
try the following
JavascriptExecutor js = (JavascriptExecutor) driver;
String base64string = (String) js.executeScript("var c = document.createElement('canvas');"
+ " var ctx = c.getContext('2d');"
+ "var img = document.getElementsByTagName('img')[0];"
+ "c.height=img.naturalHeight;"
+ "c.width=img.naturalWidth;"
+ "ctx.drawImage(img, 0, 0,img.naturalWidth, img.naturalHeight);"
+ "var base64String = c.toDataURL();"
+ "return base64String;");
String[] base64Array = base64string.split(",");
String base64 = base64Array[base64Array.length - 1];
byte[] data = Base64.decode(base64);
ByteArrayInputStream memstream = new ByteArrayInputStream(data);
BufferedImage saveImage = ImageIO.read(memstream);
ImageIO.write(saveImage, "png", new File("path"));
For my use case there were cookies and other issues that made the other approaches here unsuitable.
I ended up using an XMLHttpRequest to populate a FileReader (from How to convert image into base64 string using javascript, and then calling that using Selenium's ExecuteAsyncScript (as shown in Selenium and asynchronous JavaScript calls). This allowed me to get a Data URL which was straight forward to parse.
Here's my C# code for getting the Data URL:
public string ImageUrlToDataUrl(IWebDriver driver, string imageUrl)
{
var js = new StringBuilder();
js.AppendLine("var done = arguments[0];"); // The callback from ExecuteAsyncScript
js.AppendLine(#"
function toDataURL(url, callback) {
var xhr = new XMLHttpRequest();
xhr.onload = function() {
var reader = new FileReader();
reader.onloadend = function() {
callback(reader.result);
}
reader.readAsDataURL(xhr.response);
};
xhr.open('GET', url);
xhr.responseType = 'blob';
xhr.send();
}"); // XMLHttpRequest -> FileReader -> DataURL conversion
js.AppendLine("toDataURL('" + imageUrl + "', done);"); // Invoke the function
var executor = (IJavaScriptExecutor) driver;
var dataUrl = executor.ExecuteAsyncScript(js.ToString()) as string;
return dataUrl;
}
Another mostly correct solution is to download it directly by simple HTTP request.
You could use webDriver's user session, cause it stores cookies.
In my example, I'm just analyzing what status code it returns. If 200, then image exists and it is available for show or download. If you need to really download file itself - you could just get all image data from httpResponse entity (use it as simple input stream).
// just look at your cookie's content (e.g. using browser)
// and import these settings from it
private static final String SESSION_COOKIE_NAME = "JSESSIONID";
private static final String DOMAIN = "domain.here.com";
private static final String COOKIE_PATH = "/cookie/path/here";
protected boolean isResourceAvailableByUrl(String resourceUrl) {
HttpClient httpClient = new DefaultHttpClient();
HttpContext localContext = new BasicHttpContext();
BasicCookieStore cookieStore = new BasicCookieStore();
// apply jsessionid cookie if it exists
cookieStore.addCookie(getSessionCookie());
localContext.setAttribute(ClientContext.COOKIE_STORE, cookieStore);
// resourceUrl - is url which leads to image
HttpGet httpGet = new HttpGet(resourceUrl);
try {
HttpResponse httpResponse = httpClient.execute(httpGet, localContext);
return httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK;
} catch (IOException e) {
return false;
}
}
protected BasicClientCookie getSessionCookie() {
Cookie originalCookie = webDriver.manage().getCookieNamed(SESSION_COOKIE_NAME);
if (originalCookie == null) {
return null;
}
// just build new apache-like cookie based on webDriver's one
String cookieName = originalCookie.getName();
String cookieValue = originalCookie.getValue();
BasicClientCookie resultCookie = new BasicClientCookie(cookieName, cookieValue);
resultCookie.setDomain(DOMAIN);
resultCookie.setExpiryDate(originalCookie.getExpiry());
resultCookie.setPath(COOKIE_PATH);
return resultCookie;
}
The only way I found to avoid downloading the image twice is to use the Chrome DevTools Protocol Viewer.
In Python, this gives:
import base64
import pychrome
def save_image(file_content, file_name):
try:
file_content=base64.b64decode(file_content)
with open("C:\\Crawler\\temp\\" + file_name,"wb") as f:
f.write(file_content)
except Exception as e:
print(str(e))
def response_received(requestId, loaderId, timestamp, type, response, frameId):
if type == 'Image':
url = response.get('url')
print(f"Image loaded: {url}")
response_body = tab.Network.getResponseBody(requestId=requestId)
file_name = url.split('/')[-1].split('?')[0]
if file_name:
save_image(response_body['body'], file_name)
tab.Network.responseReceived = response_received
# start the tab
tab.start()
# call method
tab.Network.enable()
# get request to target the site selenium
driver.get("https://www.realtor.com/ads/forsale/TMAI112283AAAA")
# wait for loading
tab.wait(50)
Other solutions here don't work across all browsers, don't work across all websites, or both.
This solution should be far more robust. It uses the browser to view the image, resizes the browser to fit the image size, takes a screenshot, and finally resizes the browser back to the original size.
Python:
def get_image(driver, img_url):
'''Given an images url, return a binary screenshot of it in png format.'''
driver.get_url(img_url)
# Get the dimensions of the browser and image.
orig_h = driver.execute_script("return window.outerHeight")
orig_w = driver.execute_script("return window.outerWidth")
margin_h = orig_h - driver.execute_script("return window.innerHeight")
margin_w = orig_w - driver.execute_script("return window.innerWidth")
new_h = driver.execute_script('return document.getElementsByTagName("img")[0].height')
new_w = driver.execute_script('return document.getElementsByTagName("img")[0].width')
# Resize the browser window.
logging.info("Getting Image: orig %sX%s, marg %sX%s, img %sX%s - %s"%(
orig_w, orig_h, margin_w, margin_h, new_w, new_h, img_url))
driver.set_window_size(new_w + margin_w, new_h + margin_h)
# Get the image by taking a screenshot of the page.
img_val = driver.get_screenshot_as_png()
# Set the window size back to what it was.
driver.set_window_size(orig_w, orig_h)
# Go back to where we started.
driver.back()
return img_val
One disadvantage of this solution is that if the image is very small, the browser will not resize that small, and you may get a black border around it.
use selenium for getting the image src
elemImg.get_attribute('src')
use the programming language for this, for python;
check this answer:
How to save an image locally using Python whose URL address I already know?
If you need to test that image is available and exists, you may do like this:
protected boolean isResourceAvailableByUrl(String resourceUrl) {
// backup current url, to come back to it in future
String currentUrl = webDriver.getCurrentUrl();
try {
// try to get image by url
webDriver.get(resourceUrl);
// if "resource not found" message was not appeared - image exists
return webDriver.findElements(RESOURCE_NOT_FOUND).isEmpty();
} finally {
// back to page
webDriver.get(currentUrl);
}
}
But you need to be sure, that going through currentUrl will really turn you back on page before execution of this method. In my case it was so. If not - you may try to use:
webDriver.navigate().back()
And also, unfortunately, as it seems, there is no any chance to analyze response status code. That's why you need to find any specific web element on NOT_FOUND page and check that it was appeared and decide then - that image doesn't exist.
It is just workaround, cause I found no any official way to solve it.
NOTE:
This solution is helpful in case when you use authorized session to get resource, and can't just download it by ImageIO or strictly by HttpClient.
here is a javascript solution.
it's a tad silly -- and i'm weary of hitting the source image's server with too many requests. can someone tell me if the fetch() accesses the browser's cache? i don't want to spam the source server.
it appends a FileReader() to the window, fetches and converts the image to base64 and tags that string onto the window.
the driver can then return that window variable.
export async function scrapePic(driver) {
try {
console.log("waiting for that profile piccah")
console.log(driver)
let rootEl = await driver.findElement(By.css('.your-root-element'));
let imgEl = await rootEl.findElement(By.css('img'))
await driver.wait(until.elementIsVisible(imgEl, 10000));
console.log('profile piccah found')
let img = await imgEl.getAttribute('src')
//attach reader to driver window
await driver.executeScript(`window.myFileReader = new FileReader();`)
await driver.executeScript(`
window.myFileReader.onloadend = function() {
window['profileImage'] = this.result
}
fetch( arguments[0] ).then( res => res.blob() ).then( blob => window.electronFileReader.readAsDataURL(blob) )
`, img)
await driver.sleep(5000)
let img64 = await driver.executeScript(`return window.profileImage`)
console.log(img64)
} catch (e) {
console.log(e)
} finally {
return img64
}
}
Works for me:
# open the image in a new tab
driver.execute_script('''window.open("''' + wanted_url + '''","_blank");''')
sleep(2)
driver.switch_to.window(driver.window_handles[1])
sleep(2)
# make screenshot
driver.save_screenshot("C://Folder/" + photo_name + ".jpeg")
sleep(2)
# close the new tab
driver.execute_script('''window.close();''')
sleep(2)
#back to original tab
driver.switch_to.window(driver.window_handles[0])
Although #aboy021 JS code is syntactly correct I couldn't the code running. (using Chrome V83.xx)
However this code worked (Java):
String url = "/your-url-goes.here.jpg";
String imageData = (String) ((JavascriptExecutor) driver).executeAsyncScript(
"var callback = arguments[0];" + // The callback from ExecuteAsyncScript
"var reader;" +
"var xhr = new XMLHttpRequest();" +
"xhr.onreadystatechange = function() {" +
" if (xhr.readyState == 4) {" +
"var reader = new FileReader();" +
"reader.readAsDataURL(xhr.response);" +
"reader.onloadend = function() {" +
" callback(reader.result);" +
"}" +
" }" +
"};" +
"xhr.open('GET', '" + url + "', true);" +
"xhr.responseType = 'blob';" +
"xhr.send();");
String base64Data = imageData.split(",")[1];
byte[] decodedBytes = Base64.getDecoder().decode(base64Data);
try (OutputStream stream = new FileOutputStream("c:\\dev\\tmp\\output.jpg")) {
stream.write(decodedBytes);
} catch (IOException e) {
e.printStackTrace();
}
How to download to a file, taking URL from element text or attribute
The complete extension code can be found here:
https://github.com/gravity-api/gravity-core/blob/master/src/csharp/Gravity.Core/Gravity.Core/Extensions/WebElementExtensions.cs
If you want to use this method without writing the code, use the NuGet https://www.nuget.org/packages/Gravity.Core/
Install-Package Gravity.Core -Version 2020.7.5.3
Usage
using OpenQA.Selenium.Extensions;
...
var driver = new ChromeDriver();
// from element attribute
var element = driver.FindElement(By.XPath("//img[#id='my_img']")).DownloadResource(path: #"C:\images\cap_image_01.png", attribute: "src");
// from element text
var element = driver.FindElement(By.XPath("//div[1]")).DownloadResource(path: #"C:\images\cap_image_01.png");
It is recommended to use the NuGet, since it contains a lot more tools and extension for Selenium
For using without the NuGet (implement on your own)
Extension Class
using System.IO;
using System.Net.Http;
using System.Text.RegularExpressions;
namespace Extensions
{
public static class WebElementExtensions
{
public static IWebElement DownloadResource(this IWebElement element, string path)
{
return DoDownloadResource(element, path, "");
}
public static IWebElement DownloadResource(this IWebElement element, string path, string attribute)
{
return DoDownloadResource(element, path, attribute);
}
private static IWebElement DoDownloadResource(this IWebElement element, string path, string attribute)
{
// get resource address
var resource = (string.IsNullOrEmpty(attribute))
? element.Text
: element.GetAttribute(attribute);
// download resource
using (var client = new HttpClient())
{
// get response for the current resource
var httpResponseMessage = client.GetAsync(resource).GetAwaiter().GetResult();
// exit condition
if (!httpResponseMessage.IsSuccessStatusCode) return element;
// create directories path
Directory.CreateDirectory(path);
// get absolute file name
var fileName = Regex.Match(resource, #"[^/\\&\?]+\.\w{3,4}(?=([\?&].*$|$))").Value;
path = (path.LastIndexOf(#"\") == path.Length - 1)
? path + fileName
: path + $#"\{fileName}";
// write the file
File.WriteAllBytes(path, httpResponseMessage.Content.ReadAsByteArrayAsync().GetAwaiter().GetResult());
}
// keep the fluent
return element;
}
}
}
Usage
using Extensions;
...
var driver = new ChromeDriver();
// from element attribute
var element = driver.FindElement(By.XPath("//img[#id='my_img']")).DownloadResource(path: #"C:\images\cap_image_01.png", attribute: "src");
// from element text
var element = driver.FindElement(By.XPath("//div[1]")).DownloadResource(path: #"C:\images\cap_image_01.png");