Refactoring this Selenium Script - python

Need help refactoring this code using a function to reutilize WEbDriverWait and Search for IDs and Classes without repeating the same statements over and over. The script works as intended but I wanted to know a more "pythonic way" to code it. I've tried several ways but with no avail. "By." doesn't let me use a variable after itself to call for the Search Option nor concatenate a Str...I cant figure out how to do it.
def click_button(TypeSearch, nameElement):
newSearch = str(TypeSearch).upper()
wait = WebDriverWait(driver, 10)
element = wait.until(EC.element_to_be_clickable((By.newSearch, nameElement)))
driver.find_element(By.newSearch, nameElement).click()
click_button('ID', 'user-email')
click_button('ID', 'user-password')
Code Base:
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
from bs4 import BeautifulSoup
from selenium.webdriver.support import expected_conditions as EC
options = Options()
options.add_argument('--headless')
options.add_argument('--no-sandbox')
options.add_argument('--disable-dev-shm-usage')
# Credentials
username = "<SOME_USERNAME>"
password = "<SOME_PASS>"
# Initializing Chrome's webdriver
driver = webdriver.Chrome(PATH/TO/DRIVER, options = options)
# Loading atlassian's login page
driver.get("SOME_URL")
# Login Attempt || Username (Email Address)
wait = WebDriverWait(driver, 10)
element = wait.until(EC.element_to_be_clickable((By.ID, 'user-email')))
element.send_keys(username)
driver.find_element(By.ID,"login-button").click()
# Login Attempt || Password
wait = WebDriverWait(driver, 10)
element = wait.until(EC.element_to_be_clickable((By.ID, 'user-password')))
element.send_keys(password)
driver.find_element(By.ID,"login-button").click()
# Click On Customer Service Desk Button
wait = WebDriverWait(driver, 10)
element = wait.until(EC.element_to_be_clickable((By.CLASS_NAME, 'elrEjn')))
driver.find_element(By.CLASS_NAME, 'elrEjn').click()
# Click On Technical Support Option
wait = WebDriverWait(driver, 10)
element = wait.until(EC.element_to_be_clickable((By.CLASS_NAME, 'joNJss')))
driver.find_element(By.CLASS_NAME, 'joNJss').click()
# Fill up Summary & Description Fields
dataSummary = "Summary Automation TEST RSM Tool"
dataDescription = "Descriptor Automation TEST RSM Tool"
wait = WebDriverWait(driver, 10)
element = wait.until(EC.element_to_be_clickable((By.ID, 'summary')))
driver.find_element(By.ID, 'summary').send_keys(dataSummary)
wait = WebDriverWait(driver, 10)
element = wait.until(EC.element_to_be_clickable((By.CLASS_NAME, 'ProseMirror')))
driver.find_element(By.CLASS_NAME, 'ProseMirror').send_keys(dataDescription)
# Locating the Submit Button
# Click() Function On Line 64 Commented For Testing Purposes
# NOTE 1: When Uploading into a Production Environment: Uncomment the Submit Click() Function
# NOTE 2: When Uploading into a Production Environment: Comment Line Above Submit Click() Function & Print Function # The Bottom
xpath_submit = '//*[#id="root"]/div[1]/div/div/div[2]/main/div/div[3]/form/div/div/div[6]/button[1]'
#submit = driver.find_element(By.XPATH, xpath_submit)
submit = driver.find_element(By.XPATH, xpath_submit).click()
#print(submit.text)

Related

Can't register on site using webdriver

For training purposes trying to test registering using Selenium WebDriver. Manually could do this and navigating to profile page, but using WebDriver after submitting username/email and password I stay on the same page not logging. Though registration is perfromed successfully as I could log in using specified credentials.
Manual scenario:
Navigate to https://hdrezka.ag/
Click register button to open register pop-up
register_button = driver.find_element(By.CSS_SELECTOR, 'a.b-tophead__register')
Fill in email, login, password fields.
Click register_submit_button:
register_submit_button = driver.find_element(By.XPATH, "//button[#name='submit']")
If you do it manually element profile_dropdown will be displayed. If do it using script (I set breakpoint to try clicking register_submit_button manually as well), element profile_dropdown will not be displayed.
profile_dropdown = wait.until(EC.visibility_of_element_located ((By.XPATH, "//span[#class='b-tophead-dropdown'] [text()='Профиль']")))
I tried:
incognito mode
disable-blink-features
disabling extensions
setting user agent
Maybe you have some other ideas?
from selenium.webdriver import Chrome, Firefox
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import time
from selenium.webdriver.chrome.options import Options
from fake_useragent import UserAgent
path = r'' # TODO: specify path to webdriver
options = Options()
options.add_argument("--incognito")
options.add_argument("--disable-blink-features")
options.add_argument("--disable-blink-features=AutomationControlled")
options.add_argument("--disable-extensions")
ua = UserAgent()
userAgent = ua.random
print(userAgent)
options.add_argument(f'--user-agent={userAgent}')
driver = Chrome(service=Service(path), chrome_options=options)
driver.maximize_window()
driver.get('https://hdrezka.ag/')
agent = driver.execute_script('return navigator.userAgent;')
print(agent)
register_button = driver.find_element(By.CSS_SELECTOR, 'a.b-tophead__register')
register_button.click()
wait = WebDriverWait(driver, 5)
register_popup = wait.until(EC.visibility_of_element_located((By.ID, 'register-popup')))
time.sleep(5)
from random import randint
valid_register_login = f"user{randint(1, 100000000000)}"
valid_register_email = f"{valid_register_login}#test.com"
valid_register_password = ''.join([chr(randint(48, 57)) + chr(randint(65, 90)) + chr(randint(97, 122)) for _ in range(5)])
print()
print(f"login: {valid_register_login}")
print(f"email: {valid_register_email}")
print(f"password: {valid_register_password}")
input_register_email = driver.find_element(By.ID, 'email')
input_register_email.send_keys(valid_register_email)
email_validity_checker = wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, '#result-registration-email span.string-ok')))
assert email_validity_checker.is_displayed()
input_register_login = driver.find_element(By.ID, 'name')
input_register_login.send_keys(valid_register_login)
login_validity_checker = wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, '#result-registration-login span.string-ok')))
assert login_validity_checker.is_displayed()
input_register_password = driver.find_element(By.ID, 'password1')
input_register_password.send_keys(valid_register_password)
register_submit_button = driver.find_element(By.XPATH, "//button[#name='submit']")
register_submit_button.click()
# Failed here as page is not updated when using script
profile_dropdown = wait.until(EC.visibility_of_element_located ((By.XPATH, "//span[#class='b-tophead-dropdown'] [text()='Профиль']")))
assert profile_dropdown.is_displayed()
driver.quit()
Expected element after successful registration:

Element not clickable, ElementClickInterceptedException in Selenium

A similar question has been asked many times, and I have gone over many of them, such as Debugging "Element is not clickable at point" error
, Selenium Webdriver - element not clickable error in firefox, ElementClickInterceptedException: Message: element click intercepted:
but haven't been able to solve my problem.
I want to select a subset of car brands from the websites search dropdown menu. Usually I would do it via Selenium's Select, but that doesn't do the trick here.
Here's my code.
from selenium import webdriver
from selenium.webdriver.chrome.service import Service as ChromeService
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.proxy import Proxy, ProxyType
from selenium.webdriver.common.by import By
import time
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.action_chains import ActionChains
ser = Service(executable_path= r'D:\chromedriver.exe')
#Note I have omitted the options that I use (proxy and header).
driver = webdriver.Chrome(service = ser)
driver.get("https://www.autotalli.com/")
time.sleep(5)
# Accepting cookies
driver.find_element(by = By.XPATH, value = "//button[contains(text(),'Asetuks')]").click()
time.sleep(5)
driver.find_element(by = By.XPATH, value = "//button[contains(text(),'Tallenna')]").click()
driver.maximize_window()
time.sleep(5)
#selecting parameters from the dropdown menu
element = WebDriverWait(driver, 20).until(
EC.element_to_be_clickable((By.XPATH, "//*[#class = 'mbsc-input-wrap']")))
element.click()
element = WebDriverWait(driver, 20).until(
EC.element_to_be_clickable((By.XPATH, "//*[#data-val = '66-duplicated']")))
element.click()
element = WebDriverWait(driver, 20).until(
EC.element_to_be_clickable((By.XPATH, "//*[#class = 'mbsc-input-wrap']")))
element.click()
element = WebDriverWait(driver, 20).until(
EC.element_to_be_clickable((By.XPATH, "//*[#data-val = '10-duplicated']")))
element.click()
What throws me off is that the code works for the 66-duplicated element but not for the 10-duplicated element, and the two are identical in every way. The error I get is
Exception has occurred: ElementClickInterceptedException
Message: element click intercepted: Element <div role="option" tabindex="-1" aria-selected="false" class="mbsc-sc-itm mbsc-sel-gr-itm mbsc-btn-e" data-index="2" data-val="10-duplicated" style="height:40px;line-height:40px;">...</div> is not clickable at point (268, 217). Other element would receive the click: <input tabindex="0" type="text" class="mbsc-sel-filter-input mbsc-control" placeholder="Hae">
To to solve this, I have tried to use javascript, move to the element and then click and maximize the window - None of which worked.
#Attempt 1:js:
driver.execute_script("arguments[0].click()", element)
#Attempt 2: moveToElement:
element = driver.find_element(by = By.XPATH, value = "//*[#data-val = '10-duplicated']")
actions = ActionChains(driver)
actions.move_to_element(element).perform()
element = WebDriverWait(driver, 20).until(
EC.element_to_be_clickable((By.XPATH, "//*[#data-val = '10-duplicated']")))
element.click()
I have also tried a combination of these but to no avail.
However,when I put a break point right before the click of element "10-duplicated" and manually scroll and move the mouse to the element, and run the remaining code, it works.
I am quite puzzled here. What's going on and how can this problem be solved?
There are 17 matches for //*[#class = 'mbsc-input-wrap'] locator on that page, but you are opening the same, first match 2 times. That is Merkit droplist.
Now, when selecting //*[#data-val = '66-duplicated'] (Nissan) from the opened droplist this will work since that option is within the visible options but when Nissan is currently selected //*[#data-val = '10-duplicated'] (BMW) option in not visible, you can not click it directly.
In order to select it now you will have to
Cancel the previous selection of Nissan so that BMW will become initially visible by opening the droplist.
Scroll the droplist
Click the //*[#data-val = '10-duplicated'] with JavaScript - not recommended since this is not what human user can do via GUI.
I will give you a code to make the first approach - cancelling the previous Nissan selection.
I have also made some improvements there.
from selenium import webdriver
from selenium.webdriver.chrome.service import Service as ChromeService
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.proxy import Proxy, ProxyType
from selenium.webdriver.common.by import By
import time
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.action_chains import ActionChains
ser = Service(executable_path= r'D:\chromedriver.exe')
#Note I have omitted the options that I use (proxy and header).
driver = webdriver.Chrome(service = ser)
driver.get("https://www.autotalli.com/")
wait = WebDriverWait(driver, 20)
time.sleep(5)
# Accepting cookies
driver.find_element(by = By.XPATH, value = "//button[contains(text(),'Asetuks')]").click()
time.sleep(5)
driver.find_element(by = By.XPATH, value = "//button[contains(text(),'Tallenna')]").click()
driver.maximize_window()
time.sleep(5)
#selecting parameters from the dropdown menu
wait.until(EC.element_to_be_clickable((By.XPATH, "//*[#class = 'mbsc-input-wrap']"))).click()
wait.until(EC.element_to_be_clickable((By.XPATH, "//*[#data-val = '66-duplicated']"))).click()
#clear the previously selected NIssan option
wait.until(EC.element_to_be_clickable((By.XPATH, "//span[contains(#class,'usedCarsMakeClear clearOption')]"))).click()
wait.until(EC.element_to_be_clickable((By.XPATH, "//*[#class = 'mbsc-input-wrap']"))).click()
wait.until(EC.element_to_be_clickable((By.XPATH, "//*[#data-val = '10-duplicated']"))).click()

How click in input with Selenium

I have a problem, I'm trying to make a script that automatically logs into this site https://www.nike.com.br/cosmic-unity-153-169-211-324680
The problem is that after a few seconds this page loads and you must select the size of the shoe and click on the button that is written "Faça login para comprar" ok, after my bot clicks there it opens a pop up where i must inform my email and password and click on the login button, the problem is that i'm trying and i can't click on the input to fill in the email and password and neither I can click on the login button, I believe that maybe it is due to the fact that it is inside a div
My code:
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
option = Options()
prefs = {'profile.default_content_setting_values': {'images': 2}}
option.add_experimental_option('prefs', prefs)
driver = webdriver.Chrome(options = option)
driver.get("https//www.nike.com.br/cosmic-unity-153-169-211-324680")
wait = WebDriverWait(driver, 10)
wait.untilEC.element_to_be_clickable((By.CSS_SELECTOR, '.cc-allow'))).click()
wait.until(EC.element_to_be_clickable((By.XPATH, '//label[#for="tamanho__id40"]'))).click()
wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, 'button#anchor-acessar-unite-oauth2'))).click()
wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, 'input#9f656f67-dbed-4cda-be83-0d0d0addc6f4'))).send_keys("test#gmail.com")
wait.untillEC.element_to_be_clickable((By.CSS_SELECTOR, 'input#7016e824-f431-43d0-b5c9-d0331c330014'))).send_keys("mypass")
wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, 'button#a7f38f9a-afd7-42ce-a978-314a7d484343'))).click()
Order this code and realize that it only works until you open the login popup, after that it generates this error:
selenium.common.exceptions.TimeoutException: Message:**
That pop up is inside an iframe, you need to switch your driver focus to that particular iframe.
wait.until(EC.frame_to_be_available_and_switch_to_it((By.ID,"nike-unite-oauth2-iframe")))
make sure once you are done with that pop up switch to default_content to proceed further.
driver.switch_to.default_content()
Update 1 :
driver = webdriver.Chrome("C:\\Users\\etc\\Desktop\\Selenium+Python\\chromedriver.exe")
driver.maximize_window()
wait = WebDriverWait(driver, 30)
driver.get("https://www.nike.com.br/cosmic-unity-153-169-211-324680")
wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, '.cc-allow'))).click()
wait.until(EC.element_to_be_clickable((By.XPATH, "//label[#for='tamanho__id40']"))).click()
wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, 'button#anchor-acessar-unite-oauth2'))).click()
wait.until(EC.frame_to_be_available_and_switch_to_it((By.ID,"nike-unite-oauth2-iframe")))
wait.until(EC.element_to_be_clickable((By.NAME, 'emailAddress'))).send_keys("test#gmail.com")
wait.until(EC.element_to_be_clickable((By.NAME, 'password'))).send_keys("mypass")
wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, "input[value='ENTRAR']"))).click()

Message: no such element: Unable to locate element: {"method":"css selector","selector":"[id="loginUsername"]"}

I am trying to learn Web Scraping with Python using Selenium. I am testing Reddit.com. I am stuck here. When I run the script it stops here on the login page and gives the following error:
(selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate element: {"method":"css selector","selector":"[id="loginUsername"]"})
Please note that the same code works fine on the login page but it doesn't work on the pop up login page. It is also inside iframe.
Here is the code:
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
option = Options()
option.add_argument("--disable-infobars")
option.add_argument("start-maximized")
option.add_argument("--disable-extensions")
option.add_experimental_option("excludeSwitches", ['enable-automation'])
# Pass the argument 1 to allow and 2 to block
option.add_experimental_option("prefs", {
"profile.default_content_setting_values.notifications": 1
})
driver = webdriver.Chrome(chrome_options=option, executable_path='C:\\Users\\Sheik\\Desktop\\web crawling\\chromedriver.exe')
driver.get('https://www.reddit.com')
# clicking on the login button
login_btn = driver.find_element_by_xpath('//*[#id="SHORTCUT_FOCUSABLE_DIV"]/div[1]/header/div/div[2]/div[2]/div[1]/a[1]')
login_btn.click()
# calling the iFrame page
frame = driver.find_element_by_class_name('_25r3t_lrPF3M6zD2YkWvZU')
driver.switch_to.frame(frame)
# sending the username
username_field = driver.find_element_by_id('loginUsername')
username_field.click()
username_field.send_keys('test_username')
# sending the password
password_field = driver.find_element_by_id('loginPassword')
password_field.click()
password_field.send_keys('test_pass')
# clicking the login submit button
submit_btn = driver.find_element_by_class_name('AnimatedForm__submitButton')
submit_btn.click()
You need to deal with the fieldset while handling elements on the iframe. Please find below working solution:
from selenium.webdriver.common.by import By
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
driver = webdriver.Chrome(executable_path=r"C:\New folder\chromedriver.exe")
driver.maximize_window()
driver.get('https://www.reddit.com')
# clicking on the login button
login_btn = driver.find_element_by_xpath('//*[#id="SHORTCUT_FOCUSABLE_DIV"]/div[1]/header/div/div[2]/div[2]/div[1]/a[1]')
login_btn.click()
driver.implicitly_wait(10)
page_title = driver.title
frame = driver.find_element_by_xpath("//iframe[#class='_25r3t_lrPF3M6zD2YkWvZU']")
driver.switch_to.frame(0)
print("alert accepted")
driver.implicitly_wait(10)
username = WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.XPATH, "//fieldset//input[#id='loginUsername']")))
username.send_keys('test_username')
pwd = WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.XPATH, "//fieldset//input[#id='loginPassword']")))
pwd.send_keys('password')
login_btn = WebDriverWait(driver, 15).until(EC.element_to_be_clickable((By.XPATH, "//fieldset//button[#class='AnimatedForm__submitButton']")))
login_btn.click()
Output:
Try this:
wait = WebDriverWait(driver, 10)
wait.until(EC.visibility_of((By.ID, 'loginUsername')))
username_field = driver.find_element_by_id('loginUsername')
username_field.send_keys('test_username')

Selenium send_keys says: Element is not currently interactable and may not be manipulated

I want to send key to a login form. the problem is that an error says:
Element is not currently interactable and may not be manipulated
This is my code:
url = 'http://tx3.travian.ir'
hero_url = 'http://tx3.travian.ir/spieler.php?uid=19865'
driver = webdriver.PhantomJS(r'phantomjs/bin/phantomjs')
try:
driver.set_page_load_timeout(15)
driver.get(url)
except:
Debug.PrintException()
wait = WebDriverWait(driver, 10)
username = wait.until(EC.visibility_of_element_located((By.NAME, 'name')))
password = wait.until(EC.visibility_of_element_located((By.NAME, 'password')))
username.send_keys('user')
password.send_keys('pass')
login_btn = driver.find_element_by_id('s1')
login_btn.click()
driver.get(hero_url)
driver.close()
What's wrong?
You defined WebDriverWait but you never use it
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions
wait = WebDriverWait(driver, 10)
username = wait.until(expected_conditions.visibility_of_element_located((By.NAME, 'name')))
I have used your own code and made 5 adjustments as follows:
Set the window_size to (1400,1000)
For username field instead of (By.NAME, 'name') I have used (By.XPATH, "//input[#name='name']")
For password field instead of (By.NAME, 'password') I have used (By.XPATH, "//input[#name='password']")
For login_btn button instead of find_element_by_id('s1') I have used find_element_by_xpath("//button[#id='s1']")
Finally, I have added a print statement to confirm the End of Script.
Here is the working code block:
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
url = 'http://tx3.travian.ir'
hero_url = 'http://tx3.travian.ir/spieler.php?uid=19865'
driver = webdriver.PhantomJS(executable_path=r'C:\\Utility\\phantomjs-2.1.1-windows\\bin\\phantomjs.exe')
try:
driver.set_page_load_timeout(15)
driver.set_window_size(1400,1000)
driver.get(url)
except:
# Debug.PrintException()
pass
wait = WebDriverWait(driver, 10)
username = wait.until(EC.element_to_be_clickable((By.XPATH, "//input[#name='name']")))
password = wait.until(EC.element_to_be_clickable((By.XPATH, "//input[#name='password']")))
username.send_keys('user')
password.send_keys('pass')
login_btn = driver.find_element_by_xpath("//button[#id='s1']")
login_btn.click()
driver.get(hero_url)
driver.close()
print("Driver Closed")
This code block prints the following on my console:
Driver Closed
Try click at input box and then Enter text.
sometimes, thread.sleep(ms) in java also helps.

Categories