How to define a button with selenium without executing "find_element"? (Python) - 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!

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).

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

how to send your long WhatsApp message as a single message instead of multiple messages

I am facing issue while sending a long message to whatsApp Web using selenium Python. My message is in UTF-8 formate. Below is the sample of the message.
સમરાદિત્ય ચરિત્ર
ભવ – ૧
ભાગ – ૨૫
પ્રથમ ભવ:-
ગુણસેન(રાજા) – અગ્નિશર્મા (પુરોહિત પુત્ર)
રાજમાર્ગ પરથી મહાજનોના ૧૦૮ રથોને રથમહેલ તરફ જતા જોઇને, નગરવાસી લોકો અનેક તર્ક-વિતર્ક કરવા લાગ્યા.
Also please find the code I have tried so far.
from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.keys import Keys
import codecs
import time
#This code is to deal with the input files
grp_list_file = codecs.open('grp_list.txt','r','utf8')
grp_list_data = grp_list_file.read()
grp_list_split = grp_list_data.split('\n')
grp_list_len = len(grp_list_split)
grp_list_val_data = []
for i in range(grp_list_len):
temp = grp_list_split[i]
temp1 = temp.replace('\ufeff','')
temp2 = temp1.replace('\r','')
grp_list_val_data.append(temp2)
print('Input file processed successfully')
#This block deals with the input message file
msg_list_file = codecs.open('message.txt','r','utf-8')
msg_list_data = msg_list_file.read()
print('Message file input processed successfully')
#Keep this at here to avoid any future issues
grp_list_file.close()
msg_list_file.close()
#Open the whatsapp web
driver = webdriver.Firefox()
driver.get('https://web.whatsapp.com/')
input('Enter anyhing once the QR code has been scanned successfully')
act = ActionChains(driver)
#Let proceed with the sending message to all groups
for i in range(grp_list_len):
name = grp_list_val_data[i]
message = msg_list_data
#Select the group
user = driver.find_element_by_xpath('//span[#title = "{}"]'.format(name))
user.click()
msg_box = driver.find_element_by_class_name('_3u328')
# msg_box.send_keys(Keys.SHIFT)
act.send_keys(Keys.SHIFT,message).perform()
# msg_box.send_keys(message)
# act.key_up(Keys.SHIFT)
send = driver.find_element_by_class_name('_3M-N-')
time.sleep(10)
send.click()
print('Message sent successfully to : ',name)
Could anyone please help to send the entire text in single message instead of multiple message.
I found the way to solve the issue with help of copy paste idea.
First I copied my data to clipboard and then pasted it to desired text box location.
Thank you very much for your time and help. :)

Use login credentials that depends on the URL

I have a function created that takes several arguments including:
url
username
password
downloaded_filename
new_filename_name
example code:
def reports(url, usr, pass, downloaded_filename, new_filename_name):
driver = webdriver.Chrome('location of webdriver')
driver get(url)
usernamebox = driver.find_element_by_name('username')
userbox.send_keys(username)
....
I use this to log in to several sites and download reports.
But I defined all the above variables to specific names. Is there a way that I can assign this variables to a function so that it is only needed the function name for the variables to be updated? Is there a better way of doing this?
You can declare them outside of your method body on top of your script if you're sure that you wouldn't need to change them at any instance of you calling your method.
Your sample script would look like:
from yourImports import *
# just below your import statements
url = r'https://your_url.com'
usr = 'the_username'
password = 'your password'
downloaded_file_name = r'myFile.txt'
new_file_name = 'my_new_file'
def reports():
driver = webdriver.Chrome('location of webdriver')
driver get(url)
usernamebox = driver.find_element_by_name('username')
userbox.send_keys(usr)
....
I strongly recommend not using pass as a variable name in place for password since pass is a known keyword in python and naming a variable would shadow the keyword and python interpreter wouldn't allow it.
Other approaches:
using a dictionary to hold values and using the keys to fetch values.
using a config text file to store these things and putting them at a directory path so that if you package your code (like an .exe) and you want to change these credentials, you can just change the config file.

How to loop entire Selenium script X times

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.

Categories