Python selenium - select an element using action chain - python

I have quite a unique goal and I'm having a hard time to have my python code working. Inside a big selenium application, I'm trying simply to check if an element located on a specific position in the browser corresponds to an element.
For example, if you look at the test website: https://learn.letskodeit.com/p/practice
there's one element (link) labeled "Open Tab" and its coordinates on the browser are: x = 588, y = 576.
This is the code I'm using to confirm in that position I have that element:
target_elem = driver.find_element_by_id("opentab")
print("target elem actual location: {}".format(target_elem.location))
time.sleep(1)
zero_elem = driver.find_element_by_tag_name('body')
x_body_offset = zero_elem.location["x"]
y_body_offset = zero_elem.location["y"]
print("Body coordinates: {}, {}".format(x_body_offset, y_body_offset))
x = 588
y = 576
actions = ActionChains(driver)
actions.move_to_element_with_offset(driver.find_element_by_tag_name('body'), -x_body_offset, -y_body_offset).click()
actions.move_by_offset( x, y ).send_keys(Keys.ESCAPE).perform()
elem_found = driver.switch_to.active_element
print(elem_found.text)
when I print elem_found.text I don't get "Open Tab".
however, if inside the action chain, right before perform(), I add click(), the code above does click on the "Open Tab" link.
Hence my question: can we simply select the element by knowing its exact position in the browser?
I totally understand getting element by location is not really the best way to get element but on my end, I do really need to be able to confirm if an element in position X,Y corresponds to something I expect to find in that location.

Related

Trying to Scroll inside a div with selenium, scroller function only scrolls up to a certain amount and then just stops

I want to get a list of all the list items which are present inside a div with a scroller. They are not loaded at once upon loading the page, rather the items are loaded dynamically as the user scrolls down (until there are no elements left). So, this is the scroller script which I tried to implement:
def scroller():
userList = None
prev = 0
while True:
time.sleep(5)
userList = WebDriverWait(browser, 50).until(
EC.presence_of_all_elements_located(( By.CLASS_NAME, '<class of list item>' ))
)
n = len(userList)
if n == prev:
break
prev = n
#getting the last element in the list in the view
userList[-1].location_once_scrolled_into_view
This function scrolls the list upto a certain length, but doesn't go to the full length of the elements (not even half). Can someone please suggest a better way to do this?
Thank you

How do I click on 2nd html element which is a duplicate of first element using selenium and python?

I want to click on an element that is copied throughout the website (it is a button), but how do I click on lets say the second button, not the first.
Here is the code of the button I want to click:
SHOP NOW
However, the issue is that sometimes it may greyed out if the item is not in stock so I don't want to click it
As a result, here is all of my code:
def mainclick(website):
while True:
time.sleep(1)
price_saved = [i.text.replace('$', "").replace(',', '') for i in driver.find_elements_by_css_selector('[itemprop=youSave]')]
print(price_saved)
for g in range(len(price_saved)):
a = g + 1
if float(price_saved[g]) > 200:
try:
driver.find_element_by_link_text("SHOP NOW")[a].click()
time.sleep(3)
try:
driver.find_element_by_id("addToCartButtonTop").click()
driver.execute_script("window.history.go(-1)")
except:
driver.execute_script("window.history.go(-1)")
except:
print("couldn't click")
pass
print(a)
driver.find_element_by_link_text("Next Page").click()
print("all pages done")
# starts time
start_time = time.time()
mainweb = "https://www.lenovo.com/us/en/outletus/laptops/c/LAPTOPS?q=%3Aprice-asc%3AfacetSys-Memory%3A16+GB%3AfacetSys-Processor%3AIntel%C2%AE+Core%E2%84%A2+i7%3AfacetSys-Processor%3AIntel%C2%AE+Core%E2%84%A2+i5%3AfacetSys-Memory%3A8+GB&uq=&text=#"
driver.get(mainweb)
mainclick(mainweb)
I tried using [a] to click on a certain one but it doesn't seem to work. Also, the href might change of the shop now button based on the product.
You can collect the elements using .find_elements*.
elements = driver.find_elements_by_link_text('insert_value_here')
elements[0].click()
The above example to click first elements.
This index [0], replace with what you want.
If you are sure that everytime you want to click on 2nd button
try using below xpath,
(//*[#class='button-called-out button-full facetedResults-cta'])[2]
If, count of buttons is not same ( may be greyed out)
try using findelements
List button=driver.findElements(By.xpath("//*[#class='button-called-out button-full facetedResults-cta']"));
button.size();
Append the button.size() to the xpath in the place of '2' dynamically, you can click on the second/first not greyed button
You can use XPath with an index a:
driver.find_element_by_xpath("(//a[.='SHOP NOW'])[{}]".format(a))
Note that the first element has index 1.

Selenium - Iterating through groups of elements - Python

I'm trying to iterate over a number of elements returned by matching class names, which I have stored in an array users. The print(len(users)) outputs as 12, which is accurately correct as to how many returned there should be. This is my code:
def follow():
time.sleep(2)
# iterate here
users = []
users = browser.find_elements_by_class_name('wo9IH')
print(len(users))
for user in users:
user_button = browser.find_element_by_css_selector('li.wo9IH div.Pkbci').click()
#user_button = browser.find_element_by_xpath('//div[#class="Pkbci"]/button').click()
However currently, only index [0] is being .click()'d and the program is terminating after this first click. What would be the problem as to why the index being iterated isn't incrementing?
resource: image - red shows what's being iterated through and blue is each button being .click()'d
try this,
You can directly make array of buttons rather than li array,
Go click all buttons contains text as Follow,
simple,
browser.maximize_window()
users = []
users = browser.find_elements_by_xpath('*//button[text()='Follow']')
print(len(users)) # check it must be 12
for user in users:
browser.execute_script("arguments[0].click()", user)
# user.click() Go click all buttons
Find all your css_selector elements as a list and then iterate that list to perform .click()
yourList = browser.find_elements_by_css_selector('w0o9IH div.Pkbci')
users = browser.find_elements_by_class_name('wo9IH') returns a list of selenium.webdriver.remote.webelement.WebElement instances that can also be transversed.
In your implementation of the iteration, the above fact about the items in the list is overlooked and the entire page is search by transversing the page source from the WebDriver instance (i.e. browser.find_element_by_css_selector).
Here is how to go about getting the button in the matched WebElements:
for user_web_element in users:
# The next line given that there is only a single <button>
# in the screenshot for the matched WebElements.
user_button = user_web_element.find_element_by_tag_name('button')
user_button.click()

How to extract multiple elements from XPath Selenium (Python)

I made this XPath
alo1 = driver.find_element(By.XPATH, "//div[#class='txt-block']/span/a/span").text
print(alo1)
but the problem is: i'm getting only the first element, but there is 3 or 4 elements with the same XPath, and i wanted then all.
From page to page the number of elements change from 0 to 4.
How can i do it?
And other thing, do you think is possible to make another XPath? I'm trying to get the name of the producers of the films.
EDIT:
I have a second difficulty. I'm passing this result to an excel sheet, but it needs to be in one line to be printed there, or else will only print the last one. How can it be done? ,
wb = xlwt.Workbook()
ws = wb.add_sheet("A Test Sheet")
driver = webdriver.Chrome()
driver.get('http://www.imdb.com/title/tt4854442/?ref_=wl_li_tt')
labels = driver.find_elements_by_xpath("//div[#class='txt-
block']/span/a/span")
for label in labels:
print (label.text)
ws.write(x-1,1,label.text)
wb.save("sinopses.xls")
The website for reference: http://www.imdb.com/title/tt4854442/?ref_=wl_li_tt
You can get them all at once, and then get text for each element:
alos = driver.find_elements(By.XPATH, "//div[#class='txt-block']/span/a/span")
for alo in alos:
print alo.text
For the first question:
FindElement always give only one result , even if the locator matches more than one , it automatically takes the first one.
If locator gives more than one matching result and you want all of them then you should go for findElements
For the second question:
labels = driver.find_elements_by_xpath("//div[#class='txt-
block']/span/a/span")
result = ''
for label in labels:
result += label.text
print (result)
ws.write(x-1,1,result)
wb.save("sinopses.xls")

How can I check if an element is completely visible on the screen?

I'm using Selenium WebDriver with the Chrome driver on OS X, implementing in Python.
I'm trying to write a test that verifies if a variety of HTML elements are completely on the screen (for example, I have a tag cloud, and because of my poor implementation, sometimes some of the words slip off the edges of the browser window, so they are half-visible).
driver.find_element_by_css_selector("div.someclass").is_displayed(), which is the only solution I can find documented elsewhere, doesn't seem to work; that returns True even if the element is partially visible.
Is there a way that I can check the entire element (including padding etc.) is visible within the standard browser viewport?
I'm implementing in Python, so Python-flavored answers would be most useful.
You could acquire the element's position and size as well as the window's current X/Y offsets (position) and size to determine whether or not the element is completely in view.
With this information, you can conclude that, in order for the element to be completely within the window, the following must be true:
The window's left bound must be less than or equal to the element's left bound
The window's right bound must be greater than or equal to the element's right bound
The window's top bound must be less than or equal to the element's top bound.
The window's bottom bound must greater than or equal to the element's bottom bound.
First, get the element's location and size. The location property will give you the coordinates of the top-left corner of the element in the canvas. The size property will give you the width and height of the element.
elem = driver.find_element_by_id('square100x100')
elem_left_bound = elem.location.get('x')
elem_top_bound = elem.location.get('y')
elem_width = elem.size.get('width')
elem_height = elem.size.get('height')
You can determine if the current window view meets this criteria by getting the X/Y offsets (position) and the size of the window.
You can get the offsets by executing some javascript. The following should work for all compliant browsers. I personally tested in Chrome, Firefox, and Safari. I know IE will probably need a little massaging.
win_upper_bound = driver.execute_script('return window.pageYOffset')
win_left_bound = driver.execute_script('return window.pageXOffset')
win_width = driver.execute_script('return document.documentElement.clientWidth')
win_height = driver.execute_script('return document.documentElement.clientHeight')
With the above, we've determined the size and position of the element as well as the size and position of the viewing window. From this data, we can now do some calculations to tell if the element is in view.
def element_completely_viewable(driver, elem):
elem_left_bound = elem.location.get('x')
elem_top_bound = elem.location.get('y')
elem_width = elem.size.get('width')
elem_height = elem.size.get('height')
elem_right_bound = elem_left_bound + elem_width
elem_lower_bound = elem_top_bound + elem_height
win_upper_bound = driver.execute_script('return window.pageYOffset')
win_left_bound = driver.execute_script('return window.pageXOffset')
win_width = driver.execute_script('return document.documentElement.clientWidth')
win_height = driver.execute_script('return document.documentElement.clientHeight')
win_right_bound = win_left_bound + win_width
win_lower_bound = win_upper_bound + win_height
return all((win_left_bound <= elem_left_bound,
win_right_bound >= elem_right_bound,
win_upper_bound <= elem_top_bound,
win_lower_bound >= elem_lower_bound)
)
This will also include padding and borders on an element, but not margins. If you want margins to be factored in, you'll want to get the value of the relevant CSS properties.
Additionally, you may want to check other things like opacity, whether it's displayed, z-index, etc.

Categories