The right way to download images using selenium - selenium

I have read some articles that mentioned how to get image by selenium. For example:
from selenium import webdriver
import requests
driver=webdriver.Firefox()
driver.get("http/https://your website")
img=driver.find_element_by_xpath("xpath leading to your element")#locating element
src=img.get_attribute('src')#fetch the location of image
img=requests.get(src)#fetch image
with open('image.jpg','wb') as writer:#open for writing in binary mode
writer.write(img.content)#write the image
But does this methods have a risk of more bandwidth cost?
Is there any way just like I right click on the image and save as it to local PC?
I have tried use javascript to do that:
var canvas = document.createElement('canvas');
var context = canvas.getContext('2d');
var img = document.getElementById('someImageId');
context.drawImage(img, 0, 0 );
var theData = context.getImageData(0, 0, img.width, img.height);
and meet cross-origin problem
Uncaught DOMException: Failed to execute 'getImageData' on 'CanvasRenderingContext2D': The canvas has been tainted by cross-origin data.
at <anonymous>:5:23
It's workaround is make another request just like what I do not want in the first line.
Any suggestions?

In order to avoid increasing network footprint you can consider the following approach:
Take the screenshot of the entire page using i.e. get_screenshot_as_png function
Get required element location and size
Extract "interesting" part of the page by cutting anything else but the required element's coordinates
Save the resulting file
Example code which stores the logo from the https://experitest.com/ site to logo.png file:
from selenium import webdriver
from PIL import Image
from io import BytesIO
options = webdriver.ChromeOptions()
options.add_argument("--kiosk")
driver = webdriver.Chrome(chrome_options=options)
driver.get('chrome://settings/')
driver.execute_script('chrome.settingsPrivate.setDefaultZoom(1.0);')
driver.get("https://experitest.com/")
element = driver.find_element_by_xpath("//a[#class='navbar-brand']/img")
location = element.location
size = element.size
png = driver.get_screenshot_as_png()
im = Image.open(BytesIO(png))
left = location['x']
top = location['y']
right = location['x'] + size['width']
bottom = location['y'] + size['height']
im = im.crop((left, top, right, bottom))
im.save('logo.png')
driver.quit()
Assumptions:
You have Pillow library installed (it should be as easy as pip install pillow command)
Your OS DPI scale level is set to 100%

Related

How can I load camera preview instead of a image

enter image description here
I'm Making an android app.
Well, this is a sample code for face detection provided by google.
Instead of using a jpeg file, I want to use my camera preview .
How should I change the code? It would be very thankful if you help me because I'm struggling with this for 3 hours.
ImageView myImageView = (ImageView) findViewById(R.id.imgview);
BitmapFactory.Options options = new BitmapFactory.Options();
options.inMutable=true;
Bitmap myBitmap = BitmapFactory.decodeResource(
getApplicationContext().getResources(),
R.drawable.test1,
options);
import cv2
import numpy as np
a = cv2.CascadeClassifier('haarcascades/haarcascade_frontalface_default.xml');
cam = cv2.VideoCapture(0);
while(True):
ret,img=cam.read();
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
faces = a.detectMultiScale(gray,1.3,5)
for(x,y,w,h) in faces :
cv2.rectangle(img, (x,y), (x+w,y+h), (0,0,255), 2)
cv2.imshow("Face", img);
if(cv2.waitKey(1) == ord('q')):
break;
cam.release()
cv2.destroyAllWindows()

Selenium- screenshot of visible part of page

Is there a way to get Selenium WebDriver to take screenshot only of the visible part of the page for PhantomJS? I've browsed the source and there is no API AFAICT. So is there a trick to do that somehow?
EDIT: Chrome already snaps only visible part, so removed it as part of question.
According to the JavaDoc API for TakesScreenshot a WebDriver extending TakesScreenshot will make a best effort to return the following in order of preference:
Entire page
Current window
Visible portion of the current frame
The screenshot of the entire display containing the browser
As PhantomJS is a headless browser it probably doesn't have menus/tabs and other similar browser chrome. So all you can control is the Dimension of the browser window.
// Portrait iPhone 6 browser dimensions
Dimension dim = new Dimension(375, 627);
driver.manage().window().setSize(dim);
Taking a screenshot will most likely capture the entire page. If you want to restrict your resulting file to the dimensions you requested you could always
crop it to your required dimensions (not ideal but PhantomJS is not a real browser).
private static void capture(String url, WebDriver driver, Dimension dim, String filename) throws IOException{
driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
driver.manage().window().setSize(dim);
driver.get(url);
File scrFile = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);
int w = dim.getWidth();
int h = dim.getHeight();
Image orig = ImageIO.read(scrFile);
BufferedImage bi = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
bi.getGraphics().drawImage(orig, 0, 0, w, h, 0, 0, w, h, null);
ImageIO.write(bi, "png", new File(filename));
}
You can use robot class for this as belows
Robot rb=new Robot();
rb.keyPress(KeyEvent.VK_ALT);
rb.keyPress(KeyEvent.VK_PRINTSCREEN);
rb.keyRelease(KeyEvent.VK_PRINTSCREEN);
rb.keyRelease(KeyEvent.VK_ALT);
Once you have copied the screenshot on clipboard then u can save it to file.
WebDriver driver = new FirefoxDriver(); driver.get("http://www.google.com/");
File scrFile = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);
FileUtils.copyFile(scrFile, new File("c:\\tmp\\screenshot.png"));

createMediaElementSource plays but getByteFrequencyData returns all 0's

I am attempting to visualize audio coming out of an element on a webpage. The source for that element is a WebRTC stream connecting to an Asterisk call via sip.js. The audio works as intended.
However, when I attempt to get the frequency data using web audio api, it returns an array of all 0's, even though the audio is working. This seems be a problem with createMediaElementSource. If I call getUserMedia and use createMediaStreamSource to connect my microphone to the input, I indeed get the frequency data returned.
This was attempted in both Chrome 40.0 and Firefox 31.4. In my search I found similar errors with Android Chrome but my versions of desktop Chrome and Firefox seem like they should be functioning correctly. So far I have a feeling that the error may be due to the audio player getting it's audio from another AudioContext in sip.js, or something having to do with CORS. All of the demos that I have tried work correctly, but only use createMediaStreamSource to get mic audio, or use createMediaElementSource to play a file (rather than streaming to an element).
My Code:
var context = new (window.AudioContext || window.webkitAudioContext)();
var analyser = context.createAnalyser();
analyser.fftSize = 64;
analyser.minDecibels = -90;
analyser.maxDecibels = -10;
analyser.smoothingTimeConstant = 0.85;
var frequencyData = new Uint8Array(analyser.frequencyBinCount);
var visualisation = $("#visualisation");
var barSpacingPercent = 100 / analyser.frequencyBinCount;
for (var i = 0; i < analyser.frequencyBinCount; i++) {
$("<div/>").css("left", i * barSpacingPercent + "%").appendTo(visualisation);
}
var bars = $("#visualisation > div");
function update() {
window.requestAnimationFrame(update);
analyser.getByteFrequencyData(frequencyData);
bars.each(function (index, bar) {
bar.style.height = frequencyData[index] + 'px';
console.debug(frequencyData[index]);
});
};
$("audio").bind('canplay', function() {
source = context.createMediaElementSource(this);
source.connect(analyser);
update();
});
Any help is greatly appreciated.
Chrome doesn't support WebAudio processing of RTCPeerConnection output streams (remote streams); see this question. Their bug is here.
Edit: they now support this in Chrome 50
See the test code for firefox about to land as part of this bug:
Bug 1081819. This bug will add webaudio input to RTCPeerConnections in Firefox; we've had working WebAudio processing of output MediaStreams for some time. The test code there tests both sides; note it depends a lot on the test framework, so just use it as a guide on hooking to webaudio.

Clicking at coordinates without identifying element

As part of my Selenium test for a login function, I would like to click a button by identifying its coordinates and instructing Selenium to click at those coordinates. This would be done without identifying the element itself (via id, xpath, etc).
I understand there are other more efficient ways to run a click command, but I'm looking to specifically use this approach to best match the user experience. Thanks.
There is a way to do this. Using the ActionChains API you can move the mouse over a containing element, adjust by some offset (relative to the middle of that element) to put the "cursor" over the desired button (or other element), and then click at that location. Here's how to do it using webdriver in Python:
from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
browser = webdriver.Chrome()
elem = browser.find_element_by_selector(".some > selector")
ac = ActionChains(browser)
ac.move_to_element(elem).move_by_offset(x_offset, y_offset).click().perform()
Y'all are much to quick to dismiss the question. There are a number of reasons one might to need to click at a specific location, rather than on an element. In my case I have an SVG bar chart with an overlay element that catches all the clicks. I want to simulate a click over one of the bars, but since the overlay is there Selenium can't click on the element itself. This technique would also be valuable for imagemaps.
In C# API you use actions
var element = driver.FindElement(By...);
new Actions(driver).moveToElement(element).moveByOffset(dx, dy).click().perform();
Although it is best to just use simple Id, CSS, Xpath selectors when possible. But the functionality is there when needed (i.e. clicking elements in certain geographic places for functionality).
I first used the JavaScript code, it worked amazingly until a website did not click.
So I've found this solution:
First, import ActionChains for Python & active it:
from selenium.webdriver.common.action_chains import ActionChains
actions = ActionChains(driver)
To click on a specific point in your sessions use this:
actions.move_by_offset(X coordinates, Y coordinates).click().perform()
NOTE: The code above will only work if the mouse has not been touched, to reset the mouse coordinates use this:
actions.move_to_element_with_offset(driver.find_element_by_tag_name('body'), 0,0))
In Full:
actions.move_to_element_with_offset(driver.find_element_by_tag_name('body'), 0,0)
actions.move_by_offset(X coordinates, Y coordinates).click().perform()
This can be done using Actions class in java
Use following code -
new Actions(driver).moveByOffset(x coordinate, y coordinate).click().build().perform();
Note: Selenium 3 doesn't support Actions class for geckodriver
Also, note that x and y co-ordinates are relative values from current mouse position. Assuming mouse co-ordinates are at (0,0) to start with, if you want to use absolute values, you can perform the below action immediately after you clicked on it using the above code.
new Actions(driver).moveByOffset(-x coordinate, -y coordinate).perform();
If using a commercial add-on to Selenium is an option for you, this is possible: Suppose your button is at coordinates x=123, y=456. Then you can use Helium to click on the element at these coordinates as follows:
from helium.api import *
# Tell Helium about your WebDriver instance:
set_driver(driver)
click(Point(123, 456))
(I am one of Helium's authors.)
This worked for me in Java for clicking on coordinates irrespective on any elements.
Actions actions = new Actions(driver);
actions.moveToElement(driver.findElement(By.tagName("body")), 0, 0);
actions.moveByOffset(xCoordinate, yCoordinate).click().build().perform();
Second line of code will reset your cursor to the top left corner of the browser view and last line will click on the x,y coordinates provided as parameter.
In Selenium Java, you can try it using Javascript:
WebDriver driver = new ChromeDriver();
if (driver instanceof JavascriptExecutor) {
((JavascriptExecutor) driver).executeScript("el = document.elementFromPoint(x-cordinate, y-cordinate); el.click();");
}
Action chains can be a little finicky. You could also achieve this by executing javascript.
self.driver.execute_script('el = document.elementFromPoint(440, 120); el.click();')
I used the Actions Class like many listed above, but what I found helpful was if I need find a relative position from the element I used Firefox Add-On Measurit to get the relative coordinates.
For example:
IWebDriver driver = new FirefoxDriver();
driver.Url = #"https://scm.commerceinterface.com/accounts/login/?next=/remittance_center/";
var target = driver.FindElement(By.Id("loginAsEU"));
Actions builder = new Actions(driver);
builder.MoveToElement(target , -375 , -436).Click().Build().Perform();
I got the -375, -436 from clicking on an element and then dragging backwards until I reached the point I needed to click. The coordinates that MeasureIT said I just subtracted. In my example above, the only element I had on the page that was clickable was the "loginAsEu" link. So I started from there.
If all other methods mentioned on this page failed and you are using python, I suggest you use the mouse module to do it in a more native way instead. The code would be as simple as
import mouse
mouse.move("547", "508")
mouse.click(button='left')
You can also use the keyboard module to simulate keyboard actions
import keyboard
keyboard.write('The quick brown fox jumps over the lazy dog.')
To find the coordinate of the mouse, you can use the follow JavaScript Code.
document.onclick=function(event) {
var x = event.screenX ;
var y = event.screenY;
console.log(x, y)
}
If you don't like screenX, you can use pageX or clientX. More on here
P.S. I come across a website that prevents programmatic interactions with JavaScript/DOM/Selenium. This is probably a robot prevention mechanism. However, there is no way for them to ban OS actions.
WebElement button = driver.findElement(By.xpath("//button[#type='submit']"));
int height = button.getSize().getHeight();
int width = button.getSize().getWidth();
Actions act = new Actions(driver);
act.moveToElement(button).moveByOffset((width/2)+2,(height/2)+2).click();
import pyautogui
from selenium import webdriver
driver = webdriver.Chrome(chrome_options=options)
driver.maximize_window() #maximize the browser window
driver.implicitly_wait(30)
driver.get(url)
height=driver.get_window_size()['height']
#get browser navigation panel height
browser_navigation_panel_height = driver.execute_script('return window.outerHeight - window.innerHeight;')
act_y=y%height
scroll_Y=y/height
#scroll down page until y_off is visible
try:
driver.execute_script("window.scrollTo(0, "+str(scroll_Y*height)+")")
except Exception as e:
print "Exception"
#pyautogui used to generate click by passing x,y coordinates
pyautogui.FAILSAFE=False
pyautogui.moveTo(x,act_y+browser_navigation_panel_height)
pyautogui.click(x,act_y+browser_navigation_panel_height,clicks=1,interval=0.0,button="left")
This is worked for me. Hope, It will work for you guys :)...
I used AutoIt to do it.
using AutoIt;
AutoItX.MouseClick("LEFT",150,150,1,0);//1: click once, 0: Move instantaneous
Pro:
simple
regardless of mouse movement
Con:
since coordinate is screen-based, there should be some caution if the app scales.
the drive won't know when the app finish with clicking consequence actions. There should be a waiting period.
To add to this because I was struggling with this for a while. These are the steps I took:
Find the coordinates you need to click. Use the code below in your console and it will display and alert of the coordinates you need.
document.onclick = function(e)
{
var x = e.pageX;
var y = e.pageY;
alert("User clicked at position (" + x + "," + y + ")")
};
Make sure the element is actually visible on the screen and click it using Actionchains
WebDriverWait(DRIVER GOES HERE, 10).until(EC.element_to_be_clickable(YOUR ELEMENT LOCATOR GOES HERE))
actions = ActionChains(DRIVER GOES HERE)
actions.move_by_offset(X, Y).click().perform()
Selenium::WebDriver has PointerActions module which includes a number of actions you can chain and/or trigger without specifying the element, eg. move_to_location or move_by. See detailed specs here. As you can see, you can only use actual coordinates. I am sure this interface is implemented in other languages / libraries accordingly.
My short reply may echo some other comments here, but I just wanted to provide a link for reference.
You could use the html tag as the element and then use the coordinates you want, in this example below I am using Javascript. But I am able to click on the top left of the screen.
async function clickOnTopLeft() {
const html = driver.wait(
until.elementLocated(By.xpath('/html')),
10000)
const { width, height } = await html.getRect()
const offSetX = - Math.floor(width / 2)
const offsetY = - Math.floor(height / 2)
await driver.actions().move(
{ origin: html, x: offSetX, y: offsetY })
.click().perform()
}
If you can see the source code of page, its always the best option to refer to the button by its id or NAME attribute. For example you have button "Login" looking like this:
<input type="submit" name="login" id="login" />
In that case is best way to do
selenium.click(id="login");
Just out of the curiosity - isnt that HTTP basic authentification? In that case maybe look at this:
http://code.google.com/p/selenium/issues/detail?id=34
Selenium won't let you do this.

How can I programmatically create a screen shot of a given Web site?

I want to be able to create a screen shot of a given Web site, but the Web site may be larger than can be viewed on the screen. Is there a way I can do this?
Goal is to do this with .NET in C# in a WinForms application.
There are a few tools.
The thing is, you need to render it in some given program, and take a snapshot of it.
I don't know about .NET but here are some tools to look at.
KHTML2PNG
imagegrabwindow() (Windows PHP Only)
Create screenshots of a web page using Python and QtWebKit
Website Thumbnails Service
Taking automated webpage screenshots with embedded Mozilla
I just found out about the website browsershots.org which generates screenshots for a whole bunch of different browsers. To a certain degree you can even specify the resolution.
I wrote a program in VB.NET that did what you specified, except for the screen size issue.
I embedded a web control(look at the very bottom of all controls) onto my form, and tweaked it's settings(Hide scroll). I used a timer to wait on dynamic content, and then I used "copyFromScreen" to get the image.
My program had dynamic dimensions(settable via command line). I found that if I made my program larger than the screen, the image would just return black pixels for the off screen area. I did not research farther since my job was complete at that time.
Hope that gives you a good start. Sorry for any wrong wordings. I log onto windows to develop only once every couple of months.
Doing at as a screen shot is likely to get ugly. It's easy enough to capture the entire content of the page with wget, but the image means capturing the rendering.
Here's some tools that purport to do it.
You can render it on WebBrowser control and then take snapshot if page size bigger than screen size you have to scroll control take one or more snapshots and then merge all pictures :)
This is the code for creating screenshot programatically:
using System.Drawing.Imaging;
int screenWidth = Screen.GetBounds(new Point(0, 0)).Width;
int screenHeight = Screen.GetBounds(new Point(0, 0)).Height;
Bitmap bmpScreenShot = new Bitmap(screenWidth, screenHeight);
Graphics gfx = Graphics.FromImage((Image)bmpScreenShot);
gfx.CopyFromScreen(0, 0, 0, 0, new Size(screenWidth, screenHeight));
bmpScreenShot.Save("test.jpg", ImageFormat.Jpeg);
Java ScreenShots of WebSite
Combine Screens together for Final Entire WebPage Screenshot.
public static void main(String[] args) throws FileNotFoundException, IOException {
System.setProperty("webdriver.chrome.driver", "D:\\chromedriver.exe");
ChromeDriver browser = new ChromeDriver();
WebDriver driver = browser;
driver.get("https://news.google.co.in/");
driver.manage().timeouts().implicitlyWait(500, TimeUnit.SECONDS);
JavascriptExecutor jse = (JavascriptExecutor) driver;
Long clientHeight = (Long) jse.executeScript("return document.documentElement.clientHeight");
Long scrollHeight = (Long) jse.executeScript("return document.documentElement.scrollHeight");
int screens = 0, xAxis = 0, yAxis = clientHeight.intValue();
String screenNames = "D:\\Screenshots\\Yash";
for (screens = 0; ; screens++) {
if (scrollHeight.intValue() - xAxis < clientHeight) {
File crop = new File(screenNames + screens+".jpg");
FileUtils.copyFile(browser.getScreenshotAs(OutputType.FILE), crop);
BufferedImage image = ImageIO.read(new FileInputStream(crop));
int y_Axixs = scrollHeight.intValue() - xAxis;
BufferedImage croppedImage = image.getSubimage(0, image.getHeight()-y_Axixs, image.getWidth(), y_Axixs);
ImageIO.write(croppedImage, "jpg", crop);
break;
}
FileUtils.copyFile(browser.getScreenshotAs(OutputType.FILE), new File(screenNames + screens+".jpg"));
jse.executeScript("window.scrollBy("+ xAxis +", "+yAxis+")");
jse.executeScript("var elems = window.document.getElementsByTagName('*');"
+ " for(i = 0; i < elems.length; i++) { "
+ " var elemStyle = window.getComputedStyle(elems[i], null);"
+ " if(elemStyle.getPropertyValue('position') == 'fixed' && elems[i].innerHTML.length != 0 ){"
+ " elems[i].parentNode.removeChild(elems[i]); "
+ "}}"); // Sticky Content Removes
xAxis += yAxis;
}
driver.quit();
}