Selenium Page down by ActionChains - python

I have a problem using function to scroll down using PageDown key via Selenium's ActionChains in python 3.5 on Ubuntu 16.04 x64.
What I want is that my program scrolls down by PageDown twice, so it reaches bottom at the end and so I can have selected element always visible.
Tried making another function using Keys.END, but it did not work, so I assume it has something to do with ActionChains not closing or something.
The function looks like this:
from selenium.webdriver.common.action_chains import ActionChains
...
def scrollDown(self):
body = browser.find_element_by_xpath('/html/body')
body.click()
ActionChains(browser).send_keys(Keys.PAGE_DOWN).perform()
and I use it in another file like this:
mod.scrollDown()
The first time I use it, it does scroll down as would if PageDown key would be pressed, while another time nothing happens.
It does not matter where i call it, the second (or third...) time it does not execute.
Tried doing it manually and pressed PageDown button twice, works as expected.
Console does not return any error not does the IDE.

Maybe, if it has to do with the action chains, you can just do it like this:
from selenium.webdriver.common.keys import Keys
body = browser.find_element_by_css_selector('body')
body.send_keys(Keys.PAGE_DOWN)
Hope it works!

I had to click on the body for the Keys.PAGE_DOWN to work but didn't need to use the action chain:
from selenium.webdriver.common.keys import Keys
body = driver.find_element_by_css_selector('body')
body.click()
body.send_keys(Keys.PAGE_DOWN)

#python
from selenium.webdriver.common.keys import Keys
driver.find_element_by_css_selector('body').send_keys(Keys.PAGE_DOWN)

Related

Why ActionsChain.perform() dosn't work in loop?

I'm learning Selenium, and I've tried to make an automatic clicker for this game https://orteil.dashnet.org/cookieclicker/ .
I've made a Action Chain to click on the big cookie on the left side and put this into the loop.
But it click only once.
I tried, this loop also on https://clickspeedtest.com/ page, with same reasoult.
I also tried to add actions.pause(1), and time.sleep(1) inside the loop.
from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
import time
PATH = r"C:\Program Files (x86)\chromedriver.exe"
driver = webdriver.Chrome(PATH)
driver.get("https://orteil.dashnet.org/cookieclicker/")
driver.implicitly_wait(5)
bigCookie = driver.find_element_by_id("bigCookie")
actions = ActionChains(driver)
actions.click(bigCookie)
for i in range(10):
actions.perform()
When you call methods for actions on the ActionChains object, the actions are stored in a queue in the ActionChains object. When you call perform(), the events are fired in the order they are queued up.
I assume that after the first time you run perform(), the queue stays empty and you probably need to store new set of actions in the queue. So something like this:
actions = ActionChains(driver)
for i in range(10):
actions.click(bigCookie)
actions.perform()
ActionChains are used in a chain pattern. In other words, actions can be queued up one by one, then performed. When you call perform(), the events are fired in the order they are queued up.
You were almost there. However to perform the clicks in a loop, you need to create the ActionChain including both the events as follows:
driver.get('https://orteil.dashnet.org/cookieclicker/')
for i in range(10):
ActionChains(driver).move_to_element(driver.find_element(By.CSS_SELECTOR, "div#bigCookie")).click().perform()

.click() and .send_keys() methods not being recognized Python Selenium

I'm using Selenium in Python to click a text entry field and write some text into it. Neither the .click() nor .send_keys() methods are being recognized. Can someone help with this?
Also, is there a way to stop Selenium from printing to the console automatically? My program is console-based and Selenium is writing things to an input() that I gave because it prints to the console.
Here is a code snippet:
url = "https://weather.com/weather/today/l/69ef4b6e85ca2de422bea7adf090b06c1516c53e3c4302a01b00ba763d49be65"
browser = webdriver.Edge("Web Scrapers\msedgedriver.exe")
browser.get(url)
textbox = browser.find_element_by_id("LocationSearch_input")
textbox.click()
textbox.send_keys(zipcode)
textbox.send_keys(Keys.ENTER)
you could try the explicitWait hope this will work for you
WebDriverWait(browser,10).until(EC.element_to_be_clickable((By.XPATH,"//input[#type='text']"))).send_keys("20874",Keys.RETURN)
I would suggest you to do it with explicit wait.
I am giving this answer, cause none of the answer's are really using Explicit waits with ID attribute :
driver.maximize_window()
driver.implicitly_wait(30)
driver.get("https://weather.com/weather/today/l/69ef4b6e85ca2de422bea7adf090b06c1516c53e3c4302a01b00ba763d49be65")
wait = WebDriverWait(driver, 10)
wait.until(EC.element_to_be_clickable((By.ID, "LocationSearch_input"))).send_keys('60007' + Keys.RETURN)
wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, "div[class^='CurrentConditions--dataWrapperInner']"))).click()
Imports :
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
From what I can tell, everything is working fine here, however you are pointing your textbox variable to the wrong HTML element.
LocationSearch_input is a hidden label that isn't directly attached to the searchbox. I would try pointing it to
SearchInput--SearchInput--M7lKl SearchInput--enableSearchIcon--1Ugsx, one of the parent elements.
At least testing in firefox, it's a timing thing. The click works. The error of element not interactable (not reachable by keyboard) comes off of the send_keys line. If we wait after the click(), the element becomes reachable by keyboard.
The following could probably be refined (really don't like sleep, but sometimes it works), but works for me:
url = "https://weather.com/weather/today/l/69ef4b6e85ca2de422bea7adf090b06c1516c53e3c4302a01b00ba763d49be65"
browser.get(url)
browser.find_element_by_id('LocationSearch_input').click()
time.sleep(5)
browser.find_element_by_id('LocationSearch_input').send_keys('Boston')
At that point you need to click on whichever of the 10 options is what you really want.

How to handle Python Selenium recurring loading modals and stay DRY?

I'm using python 3.6 and selenium 3.8.1, Chrome browser to simulate users entering an order. The app we use has a particularly frustrating implementation for automation - a loading modal will pop up whenever a filter for a product is loading, but it does not truly cover elements underneath it. Additionally, load time fluctuates wildly, but with an upper bound. If I don't use excessive sleep statements, selenium will either start clicking wildly before the correct objects are loaded or clicks on the element but, of course, hits the loading modal. (Fun side note, the loading modal only fills the screen view, so selenium is also able to interact with items below the fold. :P)
To get around this:
def kill_evil_loading_modal(self):
# i pause for a second to make sure the loader has a chance to pop
time.sleep(1)
# pulling locator type and from another file: ("id","locator_id")
loading_modal = ProductsLocators.loading_modal_selector
# call a function that returns true/false for object if exists
check_for_evil = self.is_element_exist(*loading_modal)
while check_for_evil == True:
check_for_evil = self.is_element_exist(*loading_modal)
This works great! Where I had a ton of evil time.sleep(x) statements to avoid the loading modal, I'm now catching it and waiting until it's gone to move forward.
If I only had to deal with that two or three times, I would move on. Sadly, this loading modal hits after every click ... so this is what my main script looks like now:
new_quote02_obj.edit_quote_job(**data)
new_quote03_obj.kill_evil_loading_modal()
new_quote03_obj.click_product_dropdown()
new_quote03_obj.kill_evil_loading_modal()
new_quote03_obj.click_product_dropdown_link()
new_quote03_obj.kill_evil_loading_modal()
new_quote03_obj.select_category_dropdown(scenario_data['category_name'])
new_quote03_obj.kill_evil_loading_modal()
new_quote03_obj.select_market_dropdown(scenario_data['local_sales_market'])
new_quote03_obj.kill_evil_loading_modal()
new_quote03_obj.add_products_job(scenario_data['product_list_original'])
new_quote03_obj.kill_evil_loading_modal()
new_quote03_obj.click_done_btn()
new_quote03_obj.kill_evil_loading_modal()
new_quote03_obj.next_btn_page()
How can I refactor to stay DRY?
If you want to wait until modal disappeared and avoid using time.sleep() you can try ExplicitWait:
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait as wait
wait(driver, 10).until_not(EC.visibility_of_element_located(("id", "locator_id")))
or
wait(driver, 10).until(EC.invisibility_of_element_located(("id", "locator_id")))
This should allow you to wait up to 10 seconds (increase delay if needed) until element with specified selector ("id", "locator_id") will become invisible
If modal appears after each click you can implement your own click method, like
def click_n_wait(by, value, timeout=10):
wait(driver, timeout).until(EC.element_to_be_clickable((by, value))).click()
wait(driver, timeout).until(EC.invisibility_of_element_located(("id", "locator_id")))
and use it as
click_n_wait("id", "button_id")
As you mentioned in your question a loading modal will pop up whenever a filter for a product is loading irespective of the loader cover elements underneath it or not you can simply wait for the next intended element with which you want to interact with. Following this approach you can completely get rid of the function kill_evil_loading_modal() which looks to me as a overhead. As a replacement to kill_evil_loading_modal() function you have to invoke WebDriverWait() method along with proper expected_conditions as required as follows :
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
# other code
WebDriverWait(driver, 2).until(EC.element_to_be_clickable((By.XPATH, "xpath_of_element_A"))).click()
WebDriverWait(driver, 5).until(EC.element_to_be_clickable((By.XPATH, "xpath_of_element_B"))).click()
WebDriverWait(driver, 3).until(EC.element_to_be_clickable((By.XPATH, "xpath_of_element_C"))).click()

Send keys without specifying element in python selenium webdriver

I have a page whose source code is not available, but there is a input box where cursor is blinking.
Can i write something into the text box without finding the element. I mean, some way where send key can automatically look for focused inputbox and type input to it.
My code does not work obviously
driver.send_keys("testdata")
Solved it
from selenium.webdriver.common.action_chains import ActionChains
actions = ActionChains(self.driver)
actions.send_keys('dummydata')
actions.perform()
If you get error about 'self' in this code:
from selenium.webdriver.common.action_chains import ActionChains
actions = ActionChains(self.driver)
actions.send_keys('dummydata')
actions.perform()
just use:
actions = ActionChains(driver)
I don't have comment rights that's why I put this as answer
Edit: Added this enhancement as a comment on the original answer.
This worked for me:
driver.find_element_by_tag_name('body').send_keys(' ')
(Which I used to use a space character to scroll through a page)

Selenium/Python - hover and click on element

I'm running into an issue with my Selenium script on Python. In the javascript web application that I'm interacting with, an element I need to click doesn't exist until I hover over it. I've looked and found various answers on how to hover, but the sequence needs to include the clicking of a new element during the hover event. Here is the code I am currently working with. The element is renamed from add to add1 when a hover occurs, once add1 exists; I should be able to click/send.keys to execute said element.
...
driver = webdriver.Firefox()
from selenium.webdriver.common.action_chains import ActionChains
...
add = driver.find_element_by_css_selector('input.add')
Hover = ActionChains(driver).move_to_element(add)
Hover.perform()
SearchButton = driver.find_element_by_css_selector('input.add1')
SearchButton.click()
I'm new with Python and with programming in general, but I can't figure out how to sequence this correctly.
Any help would be greatly appreciated.
Following had worked for me, please give a try:
add = driver.find_element_by_css_selector('input.add')
SearchButton = driver.find_element_by_css_selector('input.add1')
Hover = ActionChains(driver).move_to_element(add).move_to_element(SearchButton)
Hover.click().build().perform()
I'm not sure about above Python code. But you can use above logic.
here another useful link
How to mouseover in python Webdriver
#TDHM
you should mention this below line to make it works
from selenium.webdriver.common.action_chains import ActionChains
thank you

Categories

Resources