Can we Zoom the browser window in python selenium webdriver? - python

I am trying to ZOOM IN and ZOOM OUT the Chrome( selenium webdriver) only using keyboard. I have tried --
from selenium.webdriver.common.keys import Keys
driver.find_element_by_tag_name("body").send_keys(Keys.CONTROL,Keys.SUBTRACT).
but it is not working. Need answer in python.

I was just struggling with this. I managed to find something that works for me, hopefully it works for you:
driver.execute_script("document.body.style.zoom='zoom %'")
Have 'zoom%' = whatever zoom level you want. (e.g. '67%')

Environment:
Selenium 3.6.0
chromedriver 2.33
Chrome version 62.0.3202.75 (Official Build) (64-bit)
macOS Sierra 10.12.6
I tried the ways (without use the CSS) that people suggested in other questions in the past. For example, the answers in this question: Selenium webdriver zoom in/out page content.
Or this: Test zoom levels of page on browsers
without success.
So, I thought: if not with the shortcuts, what could be a different way to do that?
The idea is to use the "chrome://settings/" page in order to change the zoom:
Ok I know, for example from Going through Chrome://settings by Selenium, that every settings should be set in the ChromeOptions.
From this question I noticed that in the list of preferences the only paramater (I think) could be:
// Double that indicates the default zoom level.
const char kPartitionDefaultZoomLevel[] = "partition.default_zoom_level";
I tried, without success.
I want to repeat that I know it isn't the correct approach (and that will be different with different browser versions), but it works and, at least, was useful for me to understand how to go inside a shadow root element with selenium.
The following method return the elements inside a shadow root:
def expand_shadow_element(element):
shadow_root = driver.execute_script('return arguments[0].shadowRoot', element)
return shadow_root
It is useful because in the chrome://settings/ page there are shadow root elements.
In order to do that in my browser, this is the path:
root1=driver.find_element_by_xpath("*//settings-ui")
shadow_root1 = expand_shadow_element(root1)
container= shadow_root1.find_element_by_id("container")
root2= container.find_element_by_css_selector("settings-main")
shadow_root2 = expand_shadow_element(root2)
root3=shadow_root2.find_element_by_css_selector("settings-basic-page")
shadow_root3 = expand_shadow_element(root3)
basic_page = shadow_root3.find_element_by_id("basicPage")
settings_section= basic_page.find_element_by_xpath(".//settings-section[#section='appearance']")
root4= settings_section.find_element_by_css_selector("settings-appearance-page")
shadow_root4=expand_shadow_element(root4)
and finally:
settings_animated_pages= shadow_root4.find_element_by_id("pages")
neon_animatable=settings_animated_pages.find_element_by_css_selector("neon-animatable")
zoomLevel= neon_animatable.find_element_by_xpath(".//select[#id='zoomLevel']/option[#value='0.5']")
zoomLevel.click()
The entire code:
driver = webdriver.Chrome(executable_path=r'/pathTo/chromedriver')
def expand_shadow_element(element):
shadow_root = driver.execute_script('return arguments[0].shadowRoot', element)
return shadow_root
driver.get('chrome://settings/')
root1=driver.find_element_by_xpath("*//settings-ui")
shadow_root1 = expand_shadow_element(root1)
container= shadow_root1.find_element_by_id("container")
root2= container.find_element_by_css_selector("settings-main")
shadow_root2 = expand_shadow_element(root2)
root3=shadow_root2.find_element_by_css_selector("settings-basic-page")
shadow_root3 = expand_shadow_element(root3)
basic_page = shadow_root3.find_element_by_id("basicPage")
settings_section= basic_page.find_element_by_xpath(".//settings-section[#section='appearance']")
root4= settings_section.find_element_by_css_selector("settings-appearance-page")
shadow_root4=expand_shadow_element(root4)
settings_animated_pages= shadow_root4.find_element_by_id("pages")
neon_animatable=settings_animated_pages.find_element_by_css_selector("neon-animatable")
zoomLevel= neon_animatable.find_element_by_xpath(".//select[#id='zoomLevel']/option[#value='0.5']")
zoomLevel.click()
driver.get("https://www.google.co.uk/")
EDIT
As suggested by #Florent B in the comments, we can obtain the same result simple with:
driver.get('chrome://settings/')
driver.execute_script('chrome.settingsPrivate.setDefaultZoom(1.5);')
driver.get("https://www.google.co.uk/")

firefox solution for me,
Zoom body browser
zoom is a non-standard property, use transform instead (demo):
driver.execute_script("document.body.style.transform = 'scale(0.8)'")
https://github.com/SeleniumHQ/selenium/issues/4244
driver.execute_script('document.body.style.MozTransform = "scale(0.50)";')
driver.execute_script('document.body.style.MozTransformOrigin = "0 0";')

Yes, you can invoke the Chrome driver to zoom without having to use CSS. There are methods packaged into the Chrome DevTools Protocol Viewer, one being Input.synthesizePinchGesture aka zoom in/out.
For ease of use, with regards to the DevTools Protocol API, we will use a class called MyChromeDriver with webdriver.Chrome as a metaclass and a new method for sending these commands to Chrome:
# selenium
from selenium import webdriver
# json
import json
class MyChromeDriver(webdriver.Chrome):
def send_cmd(self, cmd, params):
resource = "/session/%s/chromium/send_command_and_get_result" % self.session_id
url = self.command_executor._url + resource
body = json.dumps({'cmd':cmd, 'params': params})
response = self.command_executor._request('POST', url, body)
return response.get('value')
1. Setup our webdriver and get some page:
webdriver = MyChromeDriver()
webdriver.get("https://google.com")
2. Send Chrome the Input.synthesizePinchGesture command along with its parameters via our new method send_cmd:
webdriver.send_cmd('Input.synthesizePinchGesture', {
'x': 0,
'y': 0,
'scaleFactor': 2,
'relativeSpeed': 800, # optional
'gestureSourceType': 'default' # optional
})
3. Walla! Chrome's zoom is invoked:
As a side note, there are tons of other commands you could use with send_cmd. Find them here: https://chromedevtools.github.io/devtools-protocol/
Based off this answer: Take full page screen shot in Chrome with Selenium

As you mentioned that Need it to work in Chrome. The current solutions are only for Firefox, here are a few updates and options :
Zoom the CSS :
driver.execute_script("document.body.style.zoom='150%'")
This option did work for me. But it zooms the CSS, not the Chrome Browser. So probably you are not looking at that.
Zoom In & Zoom Out the Chrome Browser :
After 4131, 4133 and 1621 the fullscreen() mode got supported to Zoom In through Selenium-Java Clients but it's not yet publicly released to PyPI.
I can see it's implemented but not pushed. Selenium 3.7 (Python) will be out soon. The push to sync version numbers will include that.
Configure the webdriver to open the Browser :
If your requirement is to execute the Test Suite in Full Screen mode, you can always use the Options Class and configure the webdriver instance with --kiosk argument as follows:
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
options = Options()
options.add_argument("--kiosk")
driver = webdriver.Chrome(chrome_options=options, executable_path=r'C:\Utility\BrowserDrivers\chromedriver.exe')
driver.get('https://www.google.co.in')

# zoom in firefox browser
driver.get("about:preferences")
driver.execute_script("arguments[0].click();", driver.find_element(By.XPATH, "// [#id='defaultZoom']"))
ActionChains(driver).click(driver.find_element(By.XPATH, "//*[#value='50']")).perform()

Related

python selenium get_log("performance") won't log webworker requests

following many article one can log XHR calls in an automated browser (using selenium) as bellow:
capabilities = DesiredCapabilities.CHROME
capabilities["loggingPrefs"] = {"performance": "ALL"} # newer: goog:loggingPrefs driver = webdriver.Chrome(
desired_capabilities=capabilities, executable_path="./chromedriver" )
...
logs_raw = driver.get_log("performance")
my probleme is the target request is performed by a "WebWorker", so it's not listed in the performance list of the browser main thread.
getting in chrome and manualy selecting the webworkers scope in the dev console "performance.getEntries()" gets me the request i want;
my question is how can someone perform such an action in selenium ? (python preferable).
no where in the doc of python selenium or Devtool Api have i found something similar
i'm so greatful in advance.
Edit: after some deggin i found that it has something to do with execution context of javascrip, i have no clue how to switch that in selenium

Scraping Google Play Store BeautifulSoup / Selenium

I'm scraping data from the Android Store (Google Play Store) and I want to automate the downloading process on a connected phone. I'm trying to automate the click on the 'Install' button in an app page with Selenium but I can't click on it
Here is my python code :
from selenium import webdriver
driver=webdriver.Safari()
driver.get("https://play.google.com/store/apps/details?
id=com.playdemic.golf.android")
dr_button = driver.find_element_by_xpath("//*[#id='fcxH9b']/div[4]/c-wiz/div/div[2]/div/div[1]/div/c-wiz[1]/c-wiz[1]/div/div[2]/div/div[2]/div/div[2]/div[2]/c-wiz/div/span/button")
dr_button.click()
The problem is Google uses element obfuscation to prevent automation against their site in a malicious manner. You are on the right path with using XPATH, but you're going to have to manually create the XPATH... path.. which will help simplify your code, anyway. You could so something such as:
dr_button = driver.find_element_by_xpath("//button[#aria-label='Install']")
EDIT: To clarify on element obfuscation, you can see all the class names, as well as other element attributes are a seemingly random 6 character alpha numeric string. These strings can and will change intermittently. Most element-finding is used my element id's and classes.
EDIT
I solved 90% of the problem with Safari, I had first to log in here is my code.
driver = webdriver.Safari()
driver.get("https://play.google.com/store/apps/details?
id=com.king.candycrushsaga")
connexionbutton= "//*[#id='gb_70']"
emailfield= "identifierId"
GoogleAccUser="*****#gmail.com"
GoogleAccPassword="*****"
passwordfield="//*[#id='password']/div[1]/div/div[1]/input"
nextButton = "//*[#id='identifierNext']/content/span"
nextButtonTwo = "//*[#id='passwordNext']/content/span"
appsTabW = "//*[#id='wrapper']/div[1]/div/ul/li[2]/a/span/span[2]"
appsTab = "//*[#id='wrapper']/div[1]/div/ul/li[2]/a"
installButton = "//*[#id='fcxH9b']/div[4]/c-
wiz/div/div[2]/div/div[1]/div/c-wiz[1]/c-
wiz[1]/div/div[2]/div/div[2]/div/div[2]/div[2]/c-wiz/div/span/button"
confirmInstallButton = "//*[#id='purchase-ok-button']/span"
xx = "//*[#id='purchase-cancel-button']"
loginbuttonElement = WebDriverWait(driver,10).until(lambda driver:
driver.find_element_by_xpath(xpathbutton))
loginbuttonElement.click()
emailFieldElement = WebDriverWait(driver,10).until(lambda driver:
driver.find_element_by_id(emailfield))
emailFieldElement.clear()
emailFieldElement.send_keys(GoogleAccUser)
nextButtonElement = WebDriverWait(driver,10).until(lambda driver:
driver.find_element_by_xpath(nextButton))
nextButtonElement.click()
passwordFieldElement = WebDriverWait(driver,10).until(lambda driver:
driver.find_element_by_xpath(passwordfield))
passwordFieldElement.clear()
passwordFieldElement.send_keys(GoogleAccPassword)
nextButtonElementTwo = WebDriverWait(driver,10).until(lambda driver:
driver.find_element_by_xpath(nextButtonTwo))
nextButtonElementTwo.click()
installButtonElement = WebDriverWait(driver,10).until(lambda driver:
driver.find_element_by_xpath(installButton))
installButtonElement.click()
confirmInstallButtonElement = WebDriverWait(driver,50).until(lambda
driver: driver.find_element_by_xpath(xx))
confirmInstallButtonElement.click()
Now the problem is the Install confirmation which is on a popup window and I can't detect the button to click on it and download the app
I have to log in, but i can click on "install"! :) Try other browser?
from selenium import webdriver
driver=webdriver.Firefox()
driver.get("https://play.google.com/store/apps/details?id=com.playdemic.golf.android")
dr_button = driver.find_element_by_xpath("//*[#id='fcxH9b']/div[4]/c-wiz/div/div[2]/div/div[1]/div/c-wiz[1]/c-wiz[1]/div/div[2]/div/div[2]/div/div[2]/div[2]/c-wiz/div/span/button")
dr_button.click()

Intercept when url changes before the page is completely loaded

Is it possible to catch the event when the url is changed inside my browser using selenium?
Here is my scenario:
I load my website test.com
After all the static files are loaded, when executing one of the js file, I am redirected (not sure how) to another page redirect-one.test.com/blah
My browser gets the url redirect-one.test.com/blah and gets a 307 response to go to redirect-two.test.com/blahblah
Here my browser receives a final 302 to go to final.test.com/
The page of final.test.com/ is loaded and at the end of this, selenium enables me to search for elements and so on...
I'd like to be able to intercept (and time the moment it happens) each time I am redirected.
After that, I still need to do some other steps for which selenium is more suitable:
Enter my username and password
Test some functionnalities
Log out
Here a sample of how I tried to intercept the first redirect:
from selenium import webdriver
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
from selenium.webdriver.support.ui import WebDriverWait
def url_contains(url):
def check_contains_url(driver):
return (url in driver.current_url)
return check_contains_url
driver = webdriver.Remote(
command_executor='http://127.0.0.1:4444/wd/hub',
desired_capabilities=DesiredCapabilities.FIREFOX)
driver.get("http://test.com/")
try:
url = "redirect-one.test.com"
first_redirect = WebDriverWait(driver, 20).until(url_contains(url))
print("found first redirect")
finally:
print("move on to the next redirect...."
Is this even possible using selenium?
I cannot change the behavior of the website and the reason it is built like this is because of an SSO mechanism I cannot bypass.
I realize I specified python but I am open to tools in other languages.
Selenium is not the tool for this. All the redirects that the browser encounters are handled by the browser in a way that Selenium does not allow you to check.
You can perform the checks using urllib2, or if you prefer a sane interface, using requests.

How to capture network traffic using selenium webdriver and browsermob proxy on Python?

I would like to capture network traffic by using Selenium Webdriver on Python. Therefore, I must use a proxy (like BrowserMobProxy)
When I use webdriver.Chrome:
from browsermobproxy import Server
server = Server("~/browsermob-proxy")
server.start()
proxy = server.create_proxy()
from selenium import webdriver
co = webdriver.ChromeOptions()
co.add_argument('--proxy-server={host}:{port}'.format(host='localhost', port=proxy.port))
driver = webdriver.Chrome(executable_path = "~/chromedriver", chrome_options=co)
proxy.new_har
driver.get(url)
proxy.har # returns a HAR
for ent in proxy.har['log']['entries']:
print ent['request']['url']
the webpage is loaded properly and all requests are available and accessible in the HAR file.
But when I use webdriver.Firefox:
# The same as above
# ...
from selenium import webdriver
profile = webdriver.FirefoxProfile()
driver = webdriver.Firefox(firefox_profile=profile, proxy = proxy.selenium_proxy())
proxy.new_har
driver.get(url)
proxy.har # returns a HAR
for ent in proxy.har['log']['entries']:
print ent['request']['url']
The webpage cannot be loaded properly and the number of requests in the HAR file is smaller than the number of requests that should be.
Do you have any idea what the problem of proxy settings in the second code? How should I fix it to use webdriver.Firefox properly for my purpose?
Just stumbled across this project https://github.com/derekargueta/selenium-profiler. Spits out all network data for a URL. Shouldn't be hard to hack and integrate into whatever tests you're running.
Original source: https://www.openhub.net/p/selenium-profiler
For me, following code component works just fine.
profile = webdriver.FirefoxProfile()
profile.set_proxy(proxy.selenium_proxy())
driver = webdriver.Firefox(firefox_profile=profile)
I am sharing my solution, this would not write any logs to any file
but you can collect all sort of messages such as Errors,
Warnings, Logs, Info, Debug , CSS, XHR as well as Requests(traffic)
1. We are going to create Firefox profile so that we can enable option of
"Persist Logs" on Firefox (you can try it to enable on your default browser and see
if it launches with "Persist Logs" without creating firefox profile )
2. we need to modify the Firefox initialize code
where this line will do magic : options.AddArgument("--jsconsole");
so complete Selenium Firefox code would be, this will open Browser Console
everytime you execute your automation :
else if (browser.Equals(Constant.Firefox))
{
var profileManager = new FirefoxProfileManager();
FirefoxProfile profile = profileManager.GetProfile("ConsoleLogs");
FirefoxDriverService service = FirefoxDriverService.CreateDefaultService(DrivePath);
service.FirefoxBinaryPath = DrivePath;
profile.SetPreference("security.sandbox.content.level", 5);
profile.SetPreference("dom.webnotifications.enabled", false);
profile.AcceptUntrustedCertificates = true;
FirefoxOptions options = new FirefoxOptions();
options.AddArgument("--jsconsole");
options.AcceptInsecureCertificates = true;
options.Profile = profile;
options.SetPreference("browser.popups.showPopupBlocker", false);
driver = new FirefoxDriver(service.FirefoxBinaryPath, options, TimeSpan.FromSeconds(100));
driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(10);
}
3. Now you can write your logic since you have traffic/ logging window open so don't
go to next execution if test fails. That way Browser Console will keep your errors
messages and help you to troubleshoot further
Browser : Firefox v 61
How can you launch Browser Console for firefox:
1. open firefox (and give any URL )
2. Press Ctrl+Shift+J (or Cmd+Shift+J on a Mac)
Link : https://developer.mozilla.org/en-US/docs/Tools/Browser_Console

How to retrieve the values of dynamic html content using Python

I'm using Python 3 and I'm trying to retrieve data from a website. However, this data is dynamically loaded and the code I have right now doesn't work:
url = eveCentralBaseURL + str(mineral)
print("URL : %s" % url);
response = request.urlopen(url)
data = str(response.read(10000))
data = data.replace("\\n", "\n")
print(data)
Where I'm trying to find a particular value, I'm finding a template instead e.g."{{formatPrice median}}" instead of "4.48".
How can I make it so that I can retrieve the value instead of the placeholder text?
Edit: This is the specific page I'm trying to extract information from. I'm trying to get the "median" value, which uses the template {{formatPrice median}}
Edit 2: I've installed and set up my program to use Selenium and BeautifulSoup.
The code I have now is:
from bs4 import BeautifulSoup
from selenium import webdriver
#...
driver = webdriver.Firefox()
driver.get(url)
html = driver.page_source
soup = BeautifulSoup(html)
print "Finding..."
for tag in soup.find_all('formatPrice median'):
print tag.text
Here is a screenshot of the program as it's executing. Unfortunately, it doesn't seem to be finding anything with "formatPrice median" specified.
Assuming you are trying to get values from a page that is rendered using javascript templates (for instance something like handlebars), then this is what you will get with any of the standard solutions (i.e. beautifulsoup or requests).
This is because the browser uses javascript to alter what it received and create new DOM elements. urllib will do the requesting part like a browser but not the template rendering part. A good description of the issues can be found here. This article discusses three main solutions:
parse the ajax JSON directly
use an offline Javascript interpreter to process the request SpiderMonkey, crowbar
use a browser automation tool splinter
This answer provides a few more suggestions for option 3, such as selenium or watir. I've used selenium for automated web testing and its pretty handy.
EDIT
From your comments it looks like it is a handlebars driven site. I'd recommend selenium and beautiful soup. This answer gives a good code example which may be useful:
from bs4 import BeautifulSoup
from selenium import webdriver
driver = webdriver.Firefox()
driver.get('http://eve-central.com/home/quicklook.html?typeid=34')
html = driver.page_source
soup = BeautifulSoup(html)
# check out the docs for the kinds of things you can do with 'find_all'
# this (untested) snippet should find tags with a specific class ID
# see: http://www.crummy.com/software/BeautifulSoup/bs4/doc/#searching-by-css-class
for tag in soup.find_all("a", class_="my_class"):
print tag.text
Basically selenium gets the rendered HTML from your browser and then you can parse it using BeautifulSoup from the page_source property. Good luck :)
I used selenium + chrome
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
url = "www.sitetotarget.com"
options = Options()
options.add_argument('--headless')
options.add_argument('--disable-gpu')
options.add_argument('--no-sandbox')
options.add_argument('--disable-dev-shm-usage')`
Building off another answer. I had a similar issue. wget and curl do not work well anymore to get the content of a web page. It's particularly broken with dynamic and lazy content. Using Chrome (or Firefox or Chromium version of Edge) allows you to deal with redirects and scripting.
Below will launch an instance of Chrome, increase the timeout to 5 sec, and navigate this browser instance to a url. I ran this from Jupyter.
import time
from tqdm.notebook import trange, tqdm
from PIL import Image, ImageFont, ImageDraw, ImageEnhance
from selenium import webdriver
driver = webdriver.Chrome('/usr/bin/chromedriver')
driver.set_page_load_timeout(5)
time.sleep(1)
driver.set_window_size(2100, 9000)
time.sleep(1)
driver.set_window_size(2100, 9000)
## You can manually adjust the browser, but don't move it after this.
## Do stuff ...
driver.quit()
Example of grabbing dynamic content and screenshots of the anchored (hence the "a" tag) HTML object, another name for hyperlink:
url = 'http://www.example.org' ## Any website
driver.get(url)
pageSource = driver.page_source
print(driver.get_window_size())
locations = []
for element in driver.find_elements_by_tag_name("a"):
location = element.location;
size = element.size;
# Collect coordinates of object: left/right, top/bottom
x1 = location['x'];
y1 = location['y'];
x2 = location['x']+size['width'];
y2 = location['y']+size['height'];
locations.append([element,x1,y1,x2,y2, x2-x1, y2-y1])
locations.sort(key = lambda x: -x[-2] - x[-1])
locations = [ (el,x1,y1,x2,y2, width,height)
for el,x1,y1,x2,y2,width,height in locations
if not (
## First, filter links that are not visible (located offscreen or zero pixels in any dimension)
x2 <= x1 or y2 <= y1 or x2<0 or y2<0
## Further restrict if you expect the objects to be around a specific size
## or width<200 or height<100
)
]
for el,x1,y1,x2,y2,width,height in tqdm(locations[:10]):
try:
print('-'*100,f'({width},{height})')
print(el.text[:100])
element_png = el.screenshot_as_png
with open('/tmp/_pageImage.png', 'wb') as f:
f.write(element_png)
img = Image.open('/tmp/_pageImage.png')
display(img)
except Exception as err:
print(err)
Installation for mac+chrome:
pip install selenium
brew cask install chromedriver
brew cask install google-chrome
I was using Mac for the original answer and Ubuntu + Windows 11 preview via WSL2 after updating. Chrome ran from Linux side with X service on Windows to render the UI.
Regarding responsibility, please respect robots.txt on each site.
I know this is an old question, but sometimes there is a better solution than using heavy selenium.
This request module for python comes with JS support (in the background it is still chromium) and you can still use beautifulsoup like normal.
Though, sometimes if you have to click elements or sth, I guess selenium is the only option.

Categories

Resources