Selenium Webdriver - PhantomJS hangs upon send_keys() to file input element - python

I am performing some file uploading tests. I found that my test code hangs at element.send_keys(file) if I am using PhantomJS, however the same code does not hang if I am using Firefox.
element = self.browser.find_element_by_xpath("//input[#type='file']")
element.send_keys(file)
Is there any workarounds to make PhantomJS upload files properly? Currently I am using Windows 7, Python 3.4.1, selenium 2.42.1, PhantomJS 1.9.7.

browser = webdriver.PhantomJS()
browser.set_window_size(1200,800)
Without setting the window size, the browser remains in mobile size causing errors. Try a implicit wait too.

Should use PhantomJS.uploadFile(). However, didn't find python selenium API.
var webPage = require('webpage');
var page = webPage.create();
page.uploadFile('input[name=image]', '/path/to/some/photo.jpg');

Oddly enough i couldn't get anything to run in my ubuntu shell but it would run via iPython from Jupyter notebook on the exact same server.
I had to add a virtual display into the code to make it run from the shell as a .py script...
if it helps anyone facing the similiar problem here is the lines of code i added to my script and the send keys start to work without an issue.
from pyvirtualdisplay import Display
# Set screen resolution to 1366 x 768 like most 15" laptops. This is needed
#to run in the shell. Seems fine in iPython
display = Display(visible=0, size=(1366, 768))
display.start()

I use this approach when I can not simply change the value of the file input tag.
We will run it console, so we should use PyVirtualDisplay with window manager (I am using dwm, you can try fluxbox it is easy to install but need more RAM then dwm) and Xephyr for debug.
To run window manager we will use EasyProcess
So we will call File Upload Dialog, by clicking on element or button, then we simulate send keys with pynput and all these running in our console.
import time
from easyprocess import EasyProcess
from pynput.keyboard import Key, Controller
from pyvirtualdisplay import Display
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
class ImageUploadAutomation:
chrome = 'path/to/chrome'
chrome_options = Options()
# chrome_options.add_argument('--headless')
chrome_options.add_argument("--no-sandbox")
chrome_options.add_argument("--disable-notifications")
chrome_options.add_argument("--disable-dev-shm-usage")
chrome_options.add_argument("--window-size=1280,900")
chrome_options.add_argument("--start-maximized")
chrome_options.add_argument("user-data-dir=selenium")
chrome_options.add_experimental_option(
"excludeSwitches", ["disable-popup-blocking"]
)
chrome_options.add_argument(
"--disable-blink-features=AutomationControlled"
)
driver = None
def upload(self, photo):
# Change visible to 1 if you want to use Xephyr debug
with Display(visible=0, size=(1280, 900)) as display:
with EasyProcess(["dwm"]) as process:
keyboard = Controller()
url = "https://www.exmaple.com"
self.driver = webdriver.Chrome(
executable_path=self.chrome,
chrome_options=self.chrome_options
)
self.driver.get(url)
test = self.driver.find_element_by_xpath(
"//div[#aria-label='Add Photos']"
)
time.sleep(1)
test.click()
time.sleep(1)
for key in photo.path:
keyboard.press(key)
keyboard.release(key)
# keyboard.press(Key.enter)
with keyboard.pressed(Key.enter):
pass

Related

Opening a new unfocused tab in Chrome or Firefox with Python on Windows OS

My OS → Microsoft Windows 11
GOOGLE CHROME:
I have Google website open and I want to open the Stack Overflow website in a new tab but the screen keeps showing the Google website, like this:
My first attempt was trying it with the webbrowser module and its autoraise argument:
sof = 'https://stackoverflow.com'
webbrowser.open(sof, new=0, autoraise=False)
webbrowser.open(sof, new=2, autoraise=False)
webbrowser.open_new_tab(sof)
None of the above options caused the tab in Chrome to open in the background keeping focus on the tab that was already open.
So I went for another try using subprocess and its getoutput function:
r = subprocess.getoutput(f"google-chrome-stable https://stackoverflow.com")
r
That option didn't even open a new tab in my browser.
MOZILLA FIREFOX:
My attempt was trying it with the webbrowser module and its autoraise argument (As my default browser is different I need to set the browser):
sof = 'https://stackoverflow.com'
webbrowser.register('firefox',
None,
webbrowser.BackgroundBrowser("C://Program Files//Mozilla Firefox//firefox.exe"))
webbrowser.get('firefox').open(sof, new=0, autoraise=False)
In neither of the two I managed to make this functionality work.
How should I proceed?
Chrome:
I don't think it is feasible (at least not w/ chrome).
See this StackExchange answer for details. Especially the mentioned bug that most likely will never get fixed.
Firefox:
Same here, did some research and the only solution to get it to work is changing the config option
'browser.tabs.loadDivertedInBackground' to 'true'
launch background tab like this (or from py with os or subprocess module):
"C:\Program Files\Mozilla Firefox\firefox.exe" -new-tab "https://stackoverflow.com/"
See https://stackoverflow.com/a/2276679/2606766. But again I don't think this solves your problem, does it?
maybe you can try to stimulate the keyboard using pynput library,
then stimulating crtl + Tab to change to the new open website?
*edit: to open the previous tab, press crtl + shift + tab
import webbrowser, time
from pynput.keyboard import Key,Controller
keyboard = Controller()
webbrowser.open("https://www.youtube.com/")
time.sleep(3)
keyboard.press(Key.ctrl)
keyboard.press(Key.shift)
keyboard.press(Key.tab)
keyboard.release(Key.ctrl)
keyboard.release(Key.shift)
keyboard.release(Key.tab)
Are you familiar with CDP and Selenium?
Option A:
CDP Via Selenium Controlled browser:
from selenium import webdriver
driver = webdriver.Chrome('/path/bin/chromedriver')
driver.get("https://example.com/")
driver.execute_cdp_cmd(cmd="Target.createTarget",cmd_args={"url": 'https://stackoverflow.com/', "background": True})
"background": True is key
EDIT:
On linux the browser doesn't close, at least for me.
If it dies when the code dies, try the following:
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
CHROME_DRIVER_PATH = '/bin/chromedriver'
chrome_options = Options()
chrome_options.add_experimental_option("excludeSwitches", ["enable-automation"])
chrome_options.add_experimental_option("detach", True)
driver = webdriver.Chrome(CHROME_DRIVER_PATH, chrome_options=chrome_options)
driver.get("https://example.com/")
driver.execute_cdp_cmd(cmd="Target.createTarget",cmd_args={"url": 'https://stackoverflow.com/', "background": True})
Option B:
Manually run chrome with a debug port (via cmd, subprocess.popen or anything else)
chrome.exe --remote-debugging-port=4455
and then either use a python CDP Client such as trio
or tell selenium to use your existing browser:
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
chrome_options = Options()
chrome_options.add_experimental_option("debuggerAddress", "127.0.0.1:4455")
# Change chrome driver path accordingly
CHROME_DRIVER_PATH= r"C:\chromedriver.exe"
driver = webdriver.Chrome(CHROME_DRIVER_PATH, chrome_options=chrome_options)
driver.get("https://example.com/")
driver.execute_cdp_cmd(cmd="Target.createTarget",cmd_args={"url": 'https://stackoverflow.com/', "background": True})
Simpliest is to switch to -1 window_handles with chromedriver
from selenium import webdriver
driver = webdriver.Chrome('chrome/driver/path')
driver.switch_to.window(driver.window_handles[-1])

Selenium Chrome Driver - Clicks and scrolls do not work when window is in background

I am running Selenium (v3.141.0) on Python 3. I have a sequence of element clicks and element scrolls which work flawlessly when the browser (Chrome) window is in focus. These however stop working completely when the Chrome window is in the background.
I am hooking Selenium to a manually opened browser window, specifically open for debugging. I also tried passing the --headless parameter to the driver options, with no luck.
Is this an inherent limitation to Selenium, do I need to keep the window in focus while the program is running, or can this be achieved successfully while the window is in the background, and I am attending to other tasks?
Use this code to create your chrome driver.
This will run in headless mode without any interference.
Plus now you don't have to keep the window open when the script is running since this codebase will run in the background and you can do whatever you want on your screen.
import os
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
class ChromeDriver_Class(webdriver.Chrome):
def __init__(self, chrome_driver_path, teardown=False):
self.driver_path = chrome_driver_path
self.options = Options()
self.options.headless = True
self.driver = webdriver.Chrome(executable_path=self.driver_path,options=self.options)
self.options.add_argument('--ignore-certificate-errors')
self.options.add_argument('--ignore-ssl-errors')
self.teardown = teardown
os.environ['PATH'] += self.driver_path
self.driver.implicitly_wait(30)
self.driver.maximize_window()

Error 401 while using Selenium and Python to log into zoom on Raspberry Pi

I am learning to use Selenium and my goal is to open zoom through a python program on a Raspberry Pi 4. Upon running the pasted code, the program works as intended; opens zoom in browser, maximizes window, selects and clicks sign in, enters credentials and then presses enter. After log in is attempted I am given "error: Http 401 error". I am guessing this is because zoom is detecting an auto-login and blocking me. First off, am I correct? And if so, is there any way to get around this? Or does zoom block any auto filling of credentials.
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By
driver=webdriver.Chrome()
driver.get("https://zoom.us")
driver.maximize_window()
elem = driver.find_element(By.XPATH, "//a[contains(text(),'SIGN IN')]").click()
emailField = driver.find_element(By.XPATH, "//input[#id='email']")
emailField.send_keys("email") #"email" replaced with zoom login
passField = driver.find_element(By.XPATH, "//input[#id='password']")
passField.send_keys("password") #"password" replaced with zoom password
passField.send_keys(Keys.RETURN)
I faced the same issue, and was able to get around the bot-detection by using
the undetected-chromedriver package.
replace
from selenium import webdriver
...
driver = webdriver.chrome()
with
import undetected_chromedriver.v2 as ucdriver
...
driver = ucdriver.Chrome()
Add this to your code, right after the libraries import, and it will work:
options = webdriver.ChromeOptions()
options.add_argument('--disable-blink-features=AutomationControlled')
#in executable_path put the path to your chromedriver.exe
driver = webdriver.Chrome(options=options, executable_path=r'C:\WebDrivers\chromedriver.exe')
driver.get("https://zoom.us")

How to open a url using an adress of an application

How to open a URL without webbrowser using Python, but with an address of the application with which I want to open it.
There are three ways to do this
Case 1: You just need to open a page. and that is it,
import webbrowser
webbrowser.open("https://yoursite.com")
The above will open https://yoursite.com on your default browser
Case 2: You need to open, as well as do a task eg refresh
from selenium import webdriver
import time
driver = webdriver.Edge("path to your edge driver")
driver.get("https://yoursite.com")
# The command below will refresh your webbrowser after 3 seconds of opening it
time.sleep(3)
driver.refresh()
If you want to use chrome... use driver = webdriver.Chrome("path to your chrome driver")
Case 3:You have already opened your webbrowser (via selenium) and you are in another program and you want to see it without opening it manually
from selenium import webdriver
import time
driver = webdriver.Edge("path to your edge driver")
driver.get("https://yoursite.com")
time.sleep(10)
# this command stores your webbrowser window in a variable
main_page = driver.current_window_handle
# this command moves the webbrowser to the front
driver.switch_to.window(main_page)
Also you have to install a driver for your browser if you are using the selenium thing...
For edge go to https://developer.microsoft.com/en-us/microsoft-edge/tools/webdriver/#:~:text=Microsoft%20Edge%20WebDriver%20for%20Microsoft%20Edge%20will%20work,find%20your%20correct%20build%20number%3A%20Launch%20Microsoft%20Edge. and choose your edge version...
And for chrome go to https://chromedriver.chromium.org/downloads
You will also have to do pip install selenium in the terminal...
Hope this helps ;)
Try selenium, although you'll have to first download Chromedriver:
from selenium import webdriver from selenium.webdriver.common.keys import Keys
driver = webdriver.Firefox() driver.get("http://stackoverflow.com/")
body = driver.find_element_by_tag_name("body") body.send_keys(Keys.CONTROL + 't')
driver.close()

How to prevent selenium window from becoming an active one on session start? [duplicate]

I have a Selenium test suite that runs many tests and on each new test it opens a browser window on top of any other windows I have open. Very jarring while working in a local environment. Is there a way to tell Selenium or the OS (Mac) to open the windows in the background?
If you are using Selenium web driver with Python, you can use PyVirtualDisplay, a Python wrapper for Xvfb and Xephyr.
PyVirtualDisplay needs Xvfb as a dependency. On Ubuntu, first install Xvfb:
sudo apt-get install xvfb
Then install PyVirtualDisplay from PyPI:
pip install pyvirtualdisplay
Sample Selenium script in Python in a headless mode with PyVirtualDisplay:
#!/usr/bin/env python
from pyvirtualdisplay import Display
from selenium import webdriver
display = Display(visible=0, size=(800, 600))
display.start()
# Now Firefox will run in a virtual display.
# You will not see the browser.
browser = webdriver.Firefox()
browser.get('http://www.google.com')
print browser.title
browser.quit()
display.stop()
EDIT
The initial answer was posted in 2014 and now we are at the cusp of 2018. Like everything else, browsers have also advanced. Chrome has a completely headless version now which eliminates the need to use any third-party libraries to hide the UI window. Sample code is as follows:
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
CHROME_PATH = '/usr/bin/google-chrome'
CHROMEDRIVER_PATH = '/usr/bin/chromedriver'
WINDOW_SIZE = "1920,1080"
chrome_options = Options()
chrome_options.add_argument("--headless")
chrome_options.add_argument("--window-size=%s" % WINDOW_SIZE)
chrome_options.binary_location = CHROME_PATH
driver = webdriver.Chrome(executable_path=CHROMEDRIVER_PATH,
chrome_options=chrome_options
)
driver.get("https://www.google.com")
driver.get_screenshot_as_file("capture.png")
driver.close()
There are a few ways, but it isn't a simple "set a configuration value". Unless you invest in a headless browser, which doesn't suit everyone's requirements, it is a little bit of a hack:
How to hide Firefox window (Selenium WebDriver)?
and
Is it possible to hide the browser in Selenium RC?
You can 'supposedly', pass in some parameters into Chrome, specifically: --no-startup-window
Note that for some browsers, especially Internet Explorer, it will hurt your tests to not have it run in focus.
You can also hack about a bit with AutoIt, to hide the window once it's opened.
Chrome 57 has an option to pass the --headless flag, which makes the window invisible.
This flag is different from the --no-startup-window as the last doesn't launch a window. It is used for hosting background apps, as this page says.
Java code to pass the flag to Selenium webdriver (ChromeDriver):
ChromeOptions options = new ChromeOptions();
options.addArguments("--headless");
ChromeDriver chromeDriver = new ChromeDriver(options);
For running without any browser, you can run it in headless mode.
I show you one example in Python that is working for me right now
from selenium import webdriver
options = webdriver.ChromeOptions()
options.add_argument("headless")
self.driver = webdriver.Chrome(executable_path='/Users/${userName}/Drivers/chromedriver', chrome_options=options)
I also add you a bit more of info about this in the official Google website https://developers.google.com/web/updates/2017/04/headless-chrome
I used this code for Firefox in Windows and got answer(reference here):
from selenium import webdriver
from selenium.webdriver.firefox.options import Options
Options = Options()
Options.headless = True
Driver = webdriver.Firefox(options=Options, executable_path='geckodriver.exe')
Driver.get(...)
...
But I didn't test it for other browsers.
Since Chrome 57 you have the headless argument:
var options = new ChromeOptions();
options.AddArguments("headless");
using (IWebDriver driver = new ChromeDriver(options))
{
// The rest of your tests
}
The headless mode of Chrome performs 30.97% better than the UI version. The other headless driver PhantomJS delivers 34.92% better than the Chrome's headless mode.
PhantomJSDriver
using (IWebDriver driver = new PhantomJSDriver())
{
// The rest of your test
}
The headless mode of Mozilla Firefox performs 3.68% better than the UI version. This is a disappointment since the Chrome's headless mode achieves > 30% better time than the UI one. The other headless driver PhantomJS delivers 34.92% better than the Chrome's headless mode. Surprisingly for me, the Edge browser beats all of them.
var options = new FirefoxOptions();
options.AddArguments("--headless");
{
// The rest of your test
}
This is available from Firefox 57+
The headless mode of Mozilla Firefox performs 3.68% better than the UI version. This is a disappointment since the Chrome's headless mode achieves > 30% better time than the UI one. The other headless driver PhantomJS delivers 34.92% better than the Chrome's headless mode. Surprisingly for me, the Edge browser beats all of them.
Note: PhantomJS is not maintained any more!
On Windows you can use win32gui:
import win32gui
import win32con
import subprocess
class HideFox:
def __init__(self, exe='firefox.exe'):
self.exe = exe
self.get_hwnd()
def get_hwnd(self):
win_name = get_win_name(self.exe)
self.hwnd = win32gui.FindWindow(0,win_name)
def hide(self):
win32gui.ShowWindow(self.hwnd, win32con.SW_MINIMIZE)
win32gui.ShowWindow(self.hwnd, win32con.SW_HIDE)
def show(self):
win32gui.ShowWindow(self.hwnd, win32con.SW_SHOW)
win32gui.ShowWindow(self.hwnd, win32con.SW_MAXIMIZE)
def get_win_name(exe):
''' Simple function that gets the window name of the process with the given name'''
info = subprocess.STARTUPINFO()
info.dwFlags |= subprocess.STARTF_USESHOWWINDOW
raw = subprocess.check_output('tasklist /v /fo csv', startupinfo=info).split('\n')[1:-1]
for proc in raw:
try:
proc = eval('[' + proc + ']')
if proc[0] == exe:
return proc[8]
except:
pass
raise ValueError('Could not find a process with name ' + exe)
Example:
hider = HideFox('firefox.exe') # Can be anything, e.q., phantomjs.exe, notepad.exe, etc.
# To hide the window
hider.hide()
# To show again
hider.show()
However, there is one problem with this solution - using send_keys method makes the window show up. You can deal with it by using JavaScript which does not show a window:
def send_keys_without_opening_window(id_of_the_element, keys)
YourWebdriver.execute_script("document.getElementById('" + id_of_the_element + "').value = '" + keys + "';")
I suggest using PhantomJS. For more information, you may visit the Phantom Official Website.
As far as I know PhantomJS works only with Firefox...
After downloading PhantomJs.exe you need to import it to your project as you can see in the picture below PhantomJS.
I have placed mine inside: common → Library → phantomjs.exe
Now all you have to do inside your Selenium code is to change the line
browser = webdriver.Firefox()
To something like
import os
path2phantom = os.getcwd() + "\common\Library\phantomjs.exe"
browser = webdriver.PhantomJS(path2phantom)
The path to PhantomJS may be different... change as you like :)
This hack worked for me, and I'm pretty sure it will work for u too ;)
It may be in options. Here is the identical Java code.
ChromeOptions chromeOptions = new ChromeOptions();
chromeOptions.setHeadless(true);
WebDriver driver = new ChromeDriver(chromeOptions);
This is a simple Node.js solution that works in the new version 4.x (maybe also 3.x) of Selenium.
Chrome
const { Builder } = require('selenium-webdriver')
const chrome = require('selenium-webdriver/chrome');
let driver = await new Builder().forBrowser('chrome').setChromeOptions(new chrome.Options().headless()).build()
await driver.get('https://example.com')
Firefox
const { Builder } = require('selenium-webdriver')
const firefox = require('selenium-webdriver/firefox');
let driver = await new Builder().forBrowser('firefox').setFirefoxOptions(new firefox.Options().headless()).build()
await driver.get('https://example.com')
The whole thing just runs in the background. It is exactly what we want.
If you are using the Google Chrome driver, you can use this very simple code (it worked for me):
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
chrome_options = Options()
chrome_options.add_argument("--headless")
driver = webdriver.Chrome('chromedriver2_win32/chromedriver.exe', options=chrome_options)
driver.get('https://www.anywebsite.com')
On *nix, you can also run a headless X Window server like Xvfb and point the DISPLAY environment variable to it:
Fake X server for testing?
One way to achieve this is by running the browser in headless mode. Another advantage of this is that tests are executed faster.
Please find the code below to set headless mode in the Chrome browser.
package chrome;
public class HeadlessTesting {
public static void main(String[] args) throws IOException {
System.setProperty("webdriver.chrome.driver",
"ChromeDriverPath");
ChromeOptions options = new ChromeOptions();
options.addArguments("headless");
options.addArguments("window-size=1200x600");
WebDriver driver = new ChromeDriver(options);
driver.get("https://contentstack.built.io");
driver.get("https://www.google.co.in/");
System.out.println("title is: " + driver.getTitle());
File scrFile = ((TakesScreenshot) driver)
.getScreenshotAs(OutputType.FILE);
FileUtils.copyFile(scrFile, new File("pathTOSaveFile"));
driver.quit();
}
}
If you are using Ubuntu (Gnome), one simple workaround is to install Gnome extension auto-move-window: https://extensions.gnome.org/extension/16/auto-move-windows/
Then set the browser (eg. Chrome) to another workspace (eg. Workspace 2). The browser will silently run in other workspace and not bother you anymore. You can still use Chrome in your workspace without any interruption.
Here is a .NET solution that worked for me:
Download PhantomJS at http://phantomjs.org/download.html.
Copy the .exe file from the bin folder in the download folder and paste it to the bin debug/release folder of your Visual Studio project.
Add this using
using OpenQA.Selenium.PhantomJS;
In your code, open the driver like this:
PhantomJSDriver driver = new PhantomJSDriver();
using (driver)
{
driver.Navigate().GoToUrl("http://testing-ground.scraping.pro/login");
// Your code here
}
I had the same problem with my chromedriver using Python and options.add_argument("headless") did not work for me, but then I realized how to fix it so I bring it in the code below:
opt = webdriver.ChromeOptions()
opt.arguments.append("headless")
Just add a simple "headless" option argument.
from selenium import webdriver
options = webdriver.ChromeOptions()
options.add_argument("--headless")
driver = webdriver.Chrome("PATH_TO_DRIVER", options=options)
Use it ...
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
options = Options()
options.headless = True
driver = webdriver.Chrome(CHROMEDRIVER_PATH, chrome_options=options)

Categories

Resources