How to loop entire Selenium script X times - python

I have a Selenium script that logs into Salesforce, creates a contact with standard data and saves.
I would like to ask the running user how many contacts to create using raw input from the console and then loop the script x times until they have been created.
Would it be best to add this into the code below? Or enter a loop in the console when running this python file in Terminal?
Thanks!
NOTE: I have used a random int between 0-5000 to create a unique (near enough) last name and email so that duplicates are unlikely.
NOTE 2: I will only create max of 10 contacts before deleting and repeating the experiment.
Here's the code:
from selenium import webdriver
import unittest
import time
from random import randint
class SalesforceLogin(unittest.TestCase):
def setUp(self):
self.driver = webdriver.Chrome()
self.driver.get("https://test.salesforce.com")
def test_salesforce_login(self):
driver = self.driver
self.driver.find_element_by_id("username").send_keys("xxxx")
self.driver.find_element_by_id("password").send_keys("xxxx")
driver.find_element_by_id("Login").click()
time.sleep(1)
# Generate random number and assign to lastRnadom
lastRandom = randint(2,5000)
driver.find_element_by_link_text("Contacts").click()
driver.find_element_by_name("new").click()
driver.find_element_by_id("name_firstcon2").clear()
driver.find_element_by_id("name_firstcon2").send_keys("Test")
driver.find_element_by_id("name_lastcon2").clear()
driver.find_element_by_id("name_lastcon2").send_keys(lastRandom)
driver.find_element_by_id("con4").clear()
driver.find_element_by_id("con4").send_keys("xxxx")
driver.find_element_by_id("con15").clear()
# Form an email address from strings and ints
email = ("test" + "#" + str(lastRandom) + ".com")
driver.find_element_by_id("con15").send_keys(email)
driver.find_element_by_id("con10").clear()
driver.find_element_by_id("con10").send_keys("012345678")
driver.find_element_by_id("con12").clear()
driver.find_element_by_id("con12").send_keys("0123456789")
driver.find_element_by_id("con5").clear()
driver.find_element_by_id("con5").send_keys("Mr")
driver.find_element_by_id("con19street").clear()
driver.find_element_by_id("con19street").send_keys("Made Up Mailing Street")
driver.find_element_by_id("con19city").clear()
driver.find_element_by_id("con19city").send_keys("Mailing City")
driver.find_element_by_id("con19state").clear()
driver.find_element_by_id("con19state").send_keys("Mailing State")
driver.find_element_by_id("con19zip").clear()
driver.find_element_by_id("con19zip").send_keys("Mailing Zip")
driver.find_element_by_id("con19country").clear()
driver.find_element_by_id("con19country").send_keys("Mailing Country")
driver.find_element_by_id("con18street").clear()
driver.find_element_by_id("con18street").send_keys("Other Street")
driver.find_element_by_id("con18city").clear()
driver.find_element_by_id("con18city").send_keys("Other City")
driver.find_element_by_id("con18state").clear()
driver.find_element_by_id("con18state").send_keys("Other State")
driver.find_element_by_id("con18zip").clear()
driver.find_element_by_id("con18zip").send_keys("Other Zip")
driver.find_element_by_id("con18country").clear()
driver.find_element_by_id("con18country").send_keys("Other Country")
driver.find_element_by_id("con11").clear()
driver.find_element_by_id("con11").send_keys("Fax")
driver.find_element_by_id("con13").clear()
driver.find_element_by_id("con13").send_keys("Home Phone")
driver.find_element_by_id("con14").clear()
driver.find_element_by_id("con14").send_keys("Other Phone")
driver.find_element_by_id("con16").clear()
driver.find_element_by_id("con16").send_keys("Assistant")
driver.find_element_by_id("con17").clear()
driver.find_element_by_id("con17").send_keys("Asst. Phone")
driver.find_element_by_id("con20").click()
driver.find_element_by_id("con20").clear()
driver.find_element_by_id("con20").send_keys("Description")
driver.find_element_by_name("save").click()
def tearDown(self):
self.driver.quit()
if __name__ == "__main__":
unittest.main()

Loop it our use concurrency. Sadly i cant suggest you any code as im doing my scripts in java.
Also your code is missing explicit waits so theres a chance it might fail during process.

Related

How to write a proper function file in Python

I want to write a Python file that contains functions which we want to use in our project. We are working on a Selenium web scraping bot fot Instagram. Right now we write all the functions in the scripts but we want to make a "function" file which we will import and use for our scripts. But the thing is that VS code does not use autocompletion when I want to use a webdrivers function like driver.find_element_by_xpath(cookies_button_xpath).click().
The function file (not finished yet) looks like this:
import time
from selenium.webdriver.common.keys import Keys
from selenium import webdriver
# set constants for functions to run
WEBSITE_PRE_FIX = 'https://www.instagram.com/'
FORBIDDEN_CAPTION_WORDS = ['link in bio','buy now','limited time']
def open_ig(driver: webdriver):
# opens the website and waits till it is loaded
driver.get(WEBSITE_PRE_FIX)
time.sleep(2)
# accept cookies
cookies_button_xpath = "/html/body/div[4]/div/div/button[1]"
driver.find_element_by_xpath(cookies_button_xpath).click()
def login(driver: webdriver, username, password):
time.sleep(2)
# fill in user name and password and log in
username_box_xpath = '/html/body/div[1]/section/main/article/div[2]/div[1]/div/form/div/div[1]/div/label/input'
username_element = driver.find_element_by_xpath(username_box_xpath)
username_element.send_keys(username)
password_box_xpath = '/html/body/div[1]/section/main/article/div[2]/div[1]/div/form/div/div[2]/div/label/input'
password_element = driver.find_element_by_xpath(password_box_xpath)
password_element.send_keys(password)
password_element.send_keys(Keys.ENTER)
# click on do not save username and password + do not turn on notifications
time.sleep(3)
dont_save_username_button_password_xpath = '/html/body/div[1]/section/main/div/div/div/div/button'
dont_save_username_button_element = driver.find_element_by_xpath(dont_save_username_button_password_xpath)
dont_save_username_button_element.click()
So the code does work (as in it runs and does what I want) but I would like to know if we can write the function file another way so things like autocompletion en the color filters work. I'm not completely sure if it is possible. If there is any other way to write the functions file, all recommendations are welcome.
Have you tried writing the functions file as a simple class?
class FunctionsFile():
def __init__(self):
self.website_pre_fix = 'https://www.instagram.com/'
self.forbidden_capture_words = ['link in bio','buy now','limited time']
def open_ig(self, driver: webdriver):
# opens the website and waits till it is loaded
driver.get(WEBSITE_PRE_FIX)
time.sleep(2)
# accept cookies
cookies_button_xpath = "/html/body/div[4]/div/div/button[1]"
driver.find_element_by_xpath(cookies_button_xpath).click()
def login(self, driver: webdriver, username, password):
time.sleep(2)
# fill in user name and password and log in
username_box_xpath = '/html/body/div[1]/section/main/article/div[2]/div[1]/div/form/div/div[1]/div/label/input'
username_element = driver.find_element_by_xpath(username_box_xpath)
username_element.send_keys(username)
password_box_xpath = '/html/body/div[1]/section/main/article/div[2]/div[1]/div/form/div/div[2]/div/label/input'
password_element = driver.find_element_by_xpath(password_box_xpath)
password_element.send_keys(password)
password_element.send_keys(Keys.ENTER)
# click on do not save username and password + do not turn on notifications
time.sleep(3)
dont_save_username_button_password_xpath = '/html/body/div[1]/section/main/div/div/div/div/button'
dont_save_username_button_element = driver.find_element_by_xpath(dont_save_username_button_password_xpath)
dont_save_username_button_element.click()
You can then instantiate the class in any file. If in same directory:
from FunctionsFile import FunctionsFile
funcs = FunctionsFile()
funcs.open_ig(driver)
That should use the standard VS Code color schemes and autocompletion. (I think anyway).

Python undetectable_webdriver won't open in a loop

I am trying to open a site multiple times in a loop to test if different credentials have expired so that I can notify our users. I'm achieving this by opening the database, getting the records, calling the chrome driver to open the site, and inputting the values into the site. The first loop works but when the next one initiates the driver hangs and eventually outputs the error:
"unknown error: cannot connect to chrome at 127.0.0.1:XXXX from chrome not reachable"
This error commonly occurs when there is already an instance running. I have tried to prevent this by using both driver.close() and driver.quit() when the first loop is done but to no avail. I have taken care of all other possibilities of detection such as using proxies, different user agents, and also using the undetected_chromedriver by https://github.com/ultrafunkamsterdam/undetected-chromedriver.
The core issue I am looking to solve is being able to open an instance of the chrome driver, close it and open it back again all in the same execution loop until all the credentials I am testing have finished. I have abstracted the code and provided an isolated version that replicates the issue:
# INSTALL CHROMDRIVER USING "pip install undetected-chromedriver"
import undetected_chromedriver.v2 as uc
# Python Libraries
import time
options = uc.ChromeOptions()
options.add_argument('--no-first-run')
driver = uc.Chrome(options=options)
length = 8
count = 0
if count < length:
print("Im outside the loop")
while count < length:
print("This is loop ",count)
time.sleep(2)
with driver:
print("Im inside the loop")
count =+ 1
driver.get("https://google.com")
time.sleep(5)
print("Im at the end of the loop")
driver.quit() # Used to exit the browser, and end the session
# driver.close() # Only closes the window in focus
I recommend using a python virtualenv to keep packages consistent. I am using python3.9 on a Linux machine. Any solutions, suggestions, or workarounds would be greatly appreciated.
You are quitting your driver in the loop and then trying to access the executor address, which no longer exists, hence your error. You need to reinitialize the driver by moving it down within the loop, before the while statement.
from multiprocessing import Process, freeze_support
import undetected_chromedriver as uc
# Python Libraries
import time
chroptions = uc.ChromeOptions()
chroptions.add_argument('--no-first-run enable_console_log = True')
# driver = uc.Chrome(options=chroptions)
length = 8
count = 0
if count < length:
print("Im outside the loop")
while count < length:
print("This is loop ",count)
driver = uc.Chrome(options=chroptions)
time.sleep(2)
with driver:
print("Im inside the loop")
count =+ 1
driver.get("https://google.com")
print("Session ID: ", end='') #added to show your session ID is changing
print(driver.session_id)
driver.quit()

An Bot To Join Online Class With Python Is Giving Invalid NameError

This Is My Code:
#importing necessary modules for our program.
from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.keys import Keys
import time
#Fill In Your email and password in the CREDS dictionary.
CREDS = {"email" : "9714#sindhimodel.in", "password" : "DhruvSev2006"}
URL = "https://teams.microsoft.com"
def start_browser():
#This Function Will Start Your Browser.
PATH = "C:\Program Files (x86)\chromedriver.exe"
chrome = webdriver.Chrome(PATH)
chrome.get(URL)
print("Browser Opened. \n")
login()
def login():
#This Function Will Login To Your Account, Using The CREDS dictionary.
time.sleep(2)
print("Logging In To Your Account. \n")
EmailField = chrome.find_element_by_id("i0116")
EmailField.send_keys(CRED['email'])
next = chrome.find_element_by_id("idSIButton9")
next.click()
time.sleep(2)
pswd = chrome.find_element_by_id("i0118")
pswd.send_keys(CRED['password'])
sign_in = chrome.find_element_by_id("idSIButton9")
sign_in.click()
time.sleep(2)
web_app = chrome.find_element_by_class_name("use-app-lnk")
web_app.click()
time.sleep(5)
print("Logged In To Your Account. \n")
def change_class():
#This Function Is Related To My School And My Classes. You Can Delete It. :)
print("Changing Format Of Classes. \n")
clas = input("which Class Do You Want To Join: ")
classes = [["maths", "english", "p/c", "biology", "csc", "social"], ["hindi"]]
if clas in classes[0]:
clas = "Class:9:All Subjects Except Hindi"
elif clas in classes[1]:
clas = "Class:9:Hindi"
else:
clas = ""
raise KeyError("Class Not Found :(")
return clas
def know_class():
#This Will Ask The User For The Class, Which The User Wants To Join.
clas = change_class()
if clas == "Class:9:All Subjects Except Hindi":
team = "9 General"
elif clas == "Class:9:Hindi":
team = "9 HINDI General"
else:
team = ""
def join_other_class():
general_9 = chrome.find_element_by_title_name("ts-ongoing-call-header is-call-message")
general_9.click()
start_browser()
know_class()
join_other_class()
Gives An Error In login() function (Line 20), When Called In start_browser() function (Line 79).
chrome = webdriver.Chrome(PATH)
The Error Which Was Given ( When Running The Code In Command Prompt ( CMD ) In Windows ) Is:
Traceback (most recent call last):
File "C:\Users\DHRUV\Desktop\New folder\o.py", line 79, in <module>
start_browser()
File "C:\Users\DHRUV\Desktop\New folder\o.py", line 20, in start_browser
login()
File "C:\Users\DHRUV\Desktop\New folder\o.py", line 27, in login
EmailField = chrome.find_element_by_id("i0116")
NameError: name 'chrome' is not defined
Pls Help Me Out Here. I Have Defined chrome But It Stills Gives An Error.
Still The Code Isn't Finished But Still Want To Check If The Code Works Till Now.
And Please Also Give Ways To Improve The Code. This Is Just Written In A Hurry. And Also I Am A Beginner.
Thanks In Advance!
chrome is a local variable in start_browser().
If you want to access it in your other method login(), you have several options:
Pass it as a parameter
Use a global variable (you may need to use the global keyword in your function if you're assigning it for the first time)
Instead of individual functions, write a class and make chrome an instance attribute, that way you can access it in all other instance methods with self.chrome
My personal preference would be option 3, but you may chose any option you want or even something totally different from my suggestions.
What you have to do is specify the chrome as a global variable, you can do that in 2 different ways, first is just to put this code outside your function and let it be a variable that's available to all functions like this
PATH = "C:\Program Files (x86)\chromedriver.exe"
chrome = webdriver.Chrome(PATH)
def start_browser():
...
Or by doing this
def start_browser():
#This Function Will Start Your Browser.
PATH = "C:\Program Files (x86)\chromedriver.exe"
global chrome
chrome = webdriver.Chrome(PATH)
chrome.get(URL)
print("Browser Opened. \n")
login()
Here you can find out more about global variables

Reload a python script after an auto selenium error

Hi guys I have a hard time making a script.
I have a python script using selenium
I am doing automation on a site, the script needs to be running on that site for a long time.
The problem is that the site times out, the robot returns an error and stops executing.
I need that when this happens close all windows and reconnect to the site again
site timeout is = 30min
if anyone can help me it will help a lot!!!
from selenium import webdriver
import pyautogui
URL = 'https://XXXXXXX'
URL2 = 'https://XXXXXX'
user = 'user12345'
password = 'password12345'
class Web:
browser = webdriver.Ie(URL)
browser.find_element_by_name('login').send_keys(user)
browser.find_element_by_name('password').send_keys(password)
pyautogui.moveTo(121,134)# here I open a login window so I can use another link that I need to use
pyautogui.click(121,134)
browser.execute_script("window.open()")
browser.switch-to.frame(browser.window_handles[1])
browser.get(URL2)
with open(tabela, "r") as leitor:
reader = csv.DictReader(leitor, delimiter=';')
for linha in reader:
folder = linha['folder']
try:
browser.find_element_by_id('field').send_keys(folder)
browser.find_element_by_id('save').click()
except:
with open('falied.txt', 'a') as wirter:
writer.write(folder)
writer.close()
browser.quit()
if __name__ == '__main__':
Web()
from now on he needs to be running the code inside the page
this code is an example similar to my original code
Replace your part of code with the code below:
if __name__ == '__main__':
while True:
try:
Web()
Except:
browser.quit()
As you can see we're calling it in while True which means it'll run indefinitely browser.quit() will close the selenium.

How to define a button with selenium without executing "find_element"? (Python)

I really like to pre-define locators and assign them to variables in my test automation project so I could just refer to the variable name later on like this:
login_button = <browser>.find_element_by_id("login")
login_button.click()
The problem is that if these locators are saved in 'File A' and I import this file into 'File B' (at the very beginning of the program) than those "find_element" methods are executed during the import process while the pages that contain those buttons are not loaded yet which of course leaves me with an exception.
How can I save buttons into variables and import the containing file in the very beginning?
You can store such variables as strings, eg:
login_button_click = "driver.find_element_by_id('login').click()"
And then when required use:
exec(login_button_click)
In my opinion, you should divide your files like this:
file_a:
def click_login(driver):
login_elem = driver.find_element_by_id('login')
login_elem.click()
def send_username(driver, username: str):
login_elem = driver.find_element_by_id('username')
login_elem.send_keys(username)
def send_password(driver, password: str):
login_elem = driver.find_element_by_id('password')
login_elem.send_keys(password)
file_b:
from file_a import *
from selenium import webdriver
driver = webdriver.Chrome()
username = "my_username"
password = "my_password"
def preform_login():
send_username(driver, username)
send_password(driver, password)
click_login(driver)
For testing, you should use a config file config.ini for all your var's.
Again this is just my opinion...
Hope you find this helpful!

Categories