Python Selenium Multithreading Different Chrome Instances - python

I am writing a code in python that opens 20 threads (each going through the same function), each thread opens a different selenium browser instance, each thread is been given a different url as parameter. So I have 20 selenium browsers opened, each on 20 different urls. This works perfect, until I add the user-data-dir selenium chrome option to every browser, in the thread function. I do this, because I want the selenium browsers opened on the same chrome icon on the taskbar (so it won't visually disturb the user). But the problem is : now I have 20 different selenium browsers opened, but all the thread commands are executed on just one (that single one browser navigates to all the 20 given urls, leaving the other 19, basically doing nothing). How can I solve this issue? Can I mix the selenium browsers in one chrome icon in a different way? This is very strange and I looked it up, for days, but nothing seems to solve my problem. I really want to solve this and if anyone knows what might be the problem, I would really appreciate some help. (I hope you understand the question.)
EDIT :
As https://stackoverflow.com/users/6393476/enriquebet mentioned in the comments, I tried using ProcessPoolExecutor, but that did no good, because my program also has a tkinter GUI app, therefore, by implementing this method, it freezes. So I figured I should use a basic multiprocessing program. It worked fine : the 20 drivers opened, with user-data-dir option, the GUI didn't freeze. But my program, also includes a close_browser button for each driver, that closes that specific driver. The problem is : I can't access the driver field, that is initiated after. I hope this code explains my issue (Note: I narrowed it down to just one driver, for avoiding complications) This is the code:
import tkinter as tk
import os
import time
import multiprocessing
import queue
from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager
class Browser():
pass
def close_browser():
print("Closing browser...")
browser.driver.close()
def start_browser_process(browser):
print("Starting browser...")
browser.driver = webdriver.Chrome(ChromeDriverManager().install())
while True:
browser.driver.get(browser.url)
time.sleep(5)
def start_browser():
browser.process = multiprocessing.Process(target=start_browser_process, args=(browser,))
browser.process.start()
if __name__=='__main__':
browser = Browser()
browser.url = 'https://facebook.com'
root = tk.Tk()
button_start_browser = tk.Button(root, command=start_browser, width=50, height=4, bg='red', text='Start Browser')
button_start_browser.pack()
button_close_browser = tk.Button(root, width=50, height=7, bg='red', command=close_browser, text='Close Browser')
button_close_browser.pack()
root.mainloop()
So, first I create a Browser instance, that, for now, has just one field (an url) and initialize the Tkinter GUI App. Then, I press the Start Browser button, that opens for me a fresh selenium driver on https://facebook.com, that keeps reentering that url, every 5 seconds, also, I assign a new field to the Browser instance : driver. But then, when I press the Close Browser button, I want to access that browser.driver field, in order to close it, they give me this error : AttributeError: 'Browser' object has no attribute 'driver'. This means that I have to dynamically share the driver field between processes. I tried this with Queue, but that still didn't work as python doesn't let you pass queue objects as process arguments. How can I share variables between processes, in this case? Is there another way? I've been searching for 4 days now, but still didn't find the answer. Any answer is much appreciated. If you have questions regarding my issue, please announce me so I can edit the question.

Related

How to dynamically update Selenium methods without restarting the webdriver?

I have a Selenium bot that interacts with EA Sports FIFA 21 web app, where you can buy and sells in-game football players. The interface looks like this.
Lets say my original program was a single script that:
login() - logged into the platform
goToTransferMarket() - navigated to the ‘market search’ page
inputSearchParameters(playername) - inputted my search parameters to search
clickSearch() - clicked Search button
evaluateResults(buy_price) - evaluated results and bought players cheaper than buy price
If any method failed, I’d have to quit and restart from scratch. To fix this, I built a tkinter GUI with buttons for each function that executes in their own thread. This way If a function fails, like clicking the search button, I can manually perform the action and proceed to test the subsequent methods.
But still, to fix the broken methods, I have to restart the program from scratch which requires a tedious login process to fix something as simple as forgetting to cast a string to an integer. Logging in a lot also draws unwanted attention.
Given that I’m already logged in during the current testing session, is there a way to recompile my program and ‘grab’ the existing webdriver session?
Even better, is it possible to dynamically change my functions and update them with an ‘update with latest code’ button in my GUI?
The 'player list' box in my GUI writes to a textfile, which allows me to change who the bot is searching for in real time. The textfile is passed to the main bot search method when I click the "Bid using list" button. This is what made me wonder if I can set it up to somehow recompile parts of my code in a separate thread and keep my existing webdriver session. Any help would be amazing thank you.
You can add a infinite while loop and try catch to make sure your test never fails else :
If you are using chrome :
you can connect to existing chrome session using debuuger address, so start the chrome with specified debugging port from cmd
Start chrome with debug port: (In windows , search for other os how to start chrome in a specific debug port)
<path>\chrome.exe" --remote-debugging-port=1559
And in selenium use :
JAVA:
System.setProperty("webdriver.chrome.driver", "C:\\chromedriver.exe");
ChromeOptions options = new ChromeOptions();
options.setExperimentalOption("debuggerAddress", "127.0.0.1:1559");
WebDriver browser=new ChromeDriver(options);`
Python :
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
chrome_options = Options()
chrome_options.add_experimental_option("debuggerAddress", "127.0.0.1:1559")
driver = webdriver.Chrome(options=chrome_options)

Open Application (such as zoom.us) with Selenium Webdriver

I want to be able to use pure selenium webdriver to open a zoom link in Chrome and then redirect me to the zoom.us application.
When I execute this:
from selenium import webdriver
def main():
driver = webdriver.Chrome()
driver.get("https://zoom.us/j/000-000-000")
main()
I receive a pop-up saying
https://zoom.us wants to open this application.
and I must press a button titled open zoom.us to open the app.
Is there a way to press this pop-up button through selenium. Or, is there some other way to open zoom from chromedriver?
NOTE: I only want to use selenium. I have been able to implement pyautogui to click on the button but that is not what I am looking for.
Solution for Java:
driver.switchTo().alert().accept();
Solution for Python:
driver.switch_to.alert.accept()
There are a lot of duplicated questions regarding this issue. Here is one of them, and it is quite sure that selenium is not capable of achieving such job since it only interacts with the chrome page. I previously encountered this issue as well and here is my solution to it. It might look really unprofessional, but fortunately it works.
The logic of my solution is to change the setting of chrome in order to skip the popup and directly open the application you want. However, the Chrome team has removed this feature in the latter version for some reasons, and we need to get it back manually. Then, we know that everytime when selenium starts to do the thing it opens a new Chrome page with NO customized settings just like the incognito page. Therefore we need to do something to let selenium opened a Chrome page with your customized setting, so that we can make sure that the popup, which we changed manually to skip, can be skipped successfully.
Type the following code in your terminal.
defaults write com.google.Chrome ExternalProtocolDialogShowAlwaysOpenCheckbox -bool true
This enables you to change the setting of skipping popups, which is the feature Chrome team removed.
Restart Chrome,and open the zoom (or whatever application) page to let the popup display. If you do the 1st step correctly you will be able to see there is a checkbox shown next to the "Open Zoom.us" saying if you check it chrome will open this application without asking, that is, to skip the popup for this application.
Now we need to let selenium open the Chrome with our customized setting. To do this, type "chrome://version" in the search tab of your ordinary Chrome (Not automated page opened by selenium). Go to "Profile Path", and copy this path without the last word "default". For example:
/Users/MYNAME/Library/Application Support/Google/Chrome/Default
This is my profile path, but I only copy everything except the last word Default, so this is what I need to copy.
/Users/MYNAME/Library/Application Support/Google/Chrome/
This is for Mac users, but for Windows only the path is different(starts with C:// or something), steps are same.
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.chrome.options import Options
option = Options()
option.add_argument('THE PATH YOU JUST COPIED')
driver = webdriver.Chrome(executable_path='YOUR PATH TO CHROMEDRIVER', options=option)
driver.get("google.com") #Or anything else
We use "options" to let selenium open a page with our customized profile. Now you will see selenium opens a Chrome page with all your account profile, settings, and it just appears like your ordinary chrome page.
Run your code. But before that, remember to quit ALL CHROME sessions manually. For Mac, make sure that there is no dot under Chrome icon indicating that Chrome is not running for any circumstances. THIS STEP IS CRITICAL otherwise selenium will open a chrome page and it just stops there.
Here are all the steps. Again, this solution is vert informal and I personally don't think it is a "solution" to this problem. I will try to figure out a better way of achieving this in the future. But I still posted this as an alternative simply because I guess it might be helpful to some extent for somebody just like me. Hope it works for you, and good luck.

Handling multiple windows in selenium python

After clicking the submit button in my application, there will be three windows opened with title as claims, group benefits and controller. By default, the control is in the claims window. I wanted the control to be moved to group benefits window. To do that, i have used windows_handles function to find the number of windows opened so that i can loop it through to find the exact window to which i want to navigate to. However, the script returns only one window as opened, when there are three windows opened upon clicking the submit button. May i know why the script is returning only one window as opened, when the script have opened 3 windows actually please?
import selenium
import time
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
driver =
webdriver.Ie("c:\\Users\\n0317311\\Desktop\\IEDriverServer.exe")
time.sleep(3)
driver.get("https://test-groupmarkets.lmig.com/LMAuth/gms1nxtlogin.fcc")
time.sleep(3)
uname = driver.find_element_by_name("USER")
uname.send_keys("USERNAME")
upwd = driver.find_element_by_name("PASSWORD")
upwd.send_keys("Password")
uname.send_keys(Keys.RETURN)
time.sleep(2)
windows = driver.window_handles
number_of_windows = len(windows)
print ("number of windows opened:", number_of_windows)
After running the above code, i am expecting the number of windows to be printed as 3 instead of 1, because the code has opened 3 windows upon clicking the submit button.

Selenium file upload leaves file selector window open (OS/X and Python)

I'm able to upload a file to a remote server using Selenium, but the file selector dialog sticks around even once the file is uploaded. The Selenium FAQ notes that, "You can't interact with the native OS file browser dialog directly, but we do some magic so that...." Given the use of "magic" here it's not surprising that the behavior I get is a little rough around the edges. But there appear to be workarounds. Taking my cues from this answer I have the following code:
import contextlib, time
from selenium import webdriver
import selenium.webdriver.common.action_chains as action_chains
with contextlib.closing(webdriver.Chrome()) as driver:
driver.get("http://www.bing.com/images")
driver.find_element_by_id("sbi_t").click()
driver.find_element_by_id("sbi_file").click()
driver.find_element_by_id("sbi_file_upload").send_keys("//Loch Ness Monster.jpg")
print driver.current_url # Still `http://www.bing.com/images` :(
file_upload = driver.find_element_by_id("sbi_file_upload")
action_chains.ActionChains(driver).click(file_upload).perform() # https://stackoverflow.com/a/16864547/2829764
But at the end of this the file upload window is still there. I suspect I need a slightly different workaround since I'm on a Mac. Can anyone help?
Don't click upload button at all.
Set the filename via send_keys() and click "Go" (tested and works for me):
element = driver.find_element_by_id("sbi_file_upload")
element.send_keys('/Path/to/file.jpeg')
driver.find_element_by_css_selector('div#sbi_sb_ipt span[name=go]').click()

Closing a generic pop up in Selenium

While scraping a page using selenium webdriver, there is a "pop up" that appears .
On Opening the page, http://www.fanatics.com/search/red%20shoes - I see a popup window with xpath '//*[#id="mm_DesktopInterstitialImage"]' - but I don't want to be using the xpath to close this alert, and have something genric that can dismiss/close the alert.
Here's what I tried so far -:
from selenium import webdriver
import os
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
chromedriver = "/usr/local/CHROMEDRIVER"
desired_capabilities=DesiredCapabilities.CHROME
os.environ["webdriver.chrome.driver"] = chromedriver
driver = webdriver.Chrome(chromedriver,desired_capabilities=desired_capabilities)
url='http://www.fanatics.com/search/red%20shoes'
driver.get(url)
#driver.set_page_load_timeout(300)
driver.implicitly_wait(60)
alert = driver.switch_to_alert()
alert.dismiss
handle=driver.window_handles
print handle
#[u'CDwindow-B1E9C127-719D-ACAA-19DE-1A6FA265A4FF']
From what I understand from related examples, folks usually switch window handles, but my handle has a single element.i.e, driver.switch_to_window(driver.window_handles[1]) then driver.close() and finally shift again, using driver.switch_to_window(driver.window_handles[1]) I also used implicit wait, since I was not sure, if the alert window was being read at-all - but that did not work either. I do not wnat to hard-code for the xpath,if that is possible.
What am I doing wrong ?
Related, but does't work for me : Selenium python how to close a pop up window?
As I can see, it's not an alert box!!. It is just a Simple Pop-up that appears when you are entering the page and it is present in main window itself(no need of switching and closing it too). Use the below code to close it.
driver.find_element_by_xpath('//div[contains(#class,"ui-dialog") and #aria-describedby="dialogContent2"]//button[#title="Close"]').click()
It works perfectly, give it a try ;)
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
options = Options()
options.add_argument("--disable-notifications")
browser = webdriver.Chrome('C:\Python34\Lib\site-packages\selenium\webdriver\chromedriver.exe', chrome_options=options)
The popup you are trying to close is not a browser alert but a DOM popup. A browser alert is a dialog box that the browser creates at the OS level. (It is appears as an additional window on your desktop.) You can use .switch_to_alert() to close these alerts. A DOM popup is just an HTML element that happens to be used the the page as if it were a dialog box. This popup has existence only in your browser. (The OS does not know about it.) You cannot use .switch_to_alert() to close DOM popups.
To get this popup and close it, you have to inspect the DOM (like you've started doing), find the DOM element that represents the close button and have Selenium click it.
I ran into a similar problem, except that our pop-up's closebox webelement had a dynamic id tag, making it difficult to latch onto. We ended up solving it by using By.className to find it. In the code below, I use a List because I was also looking to see how many elements I was dealing with, but that's not required. Also, the production code has additional handling in case window closebox elements were found.
List<WebElement> closeboxes = driver.findElements(By.className("v-window-closebox"));
for (WebElement we : closeboxes) {
we.click();
}
You can try the following:
from selenium.webdriver import ActionChains, Chrome
driver = Chrome('/usr/local/CHROMEDRIVER')
ActionChains(driver).move_to_element_with_offset(
driver.find_element_by_xpath('//html'), 0, 2338
).click().perform()
This will click an area outside of the popup thus closing it. 🤠

Categories