I am trying to navigate through a miniature window containing a grid (1000+ rows) which lies inside of a website. And my goal requires me to click each row of the grid. Initially I tried locating each row using xPATH but there is no reliable way to do this because when I scroll down the grid, the xPATH changes (eg. row 1 -> ...div/div[1]/..., row n -> ...div/div[6]/...)
therefore to get around this issue, I used actionChains move_by_offset and located the row I want this way. and using a loop to add on some grid-width each time, before hitting some maximum number of rows that can appear on screen and scrolling down using a.send_keys(Keys.PAGE_DOWN).
This is all working well and i can see the hover animation above the rows when i want them. However, I cannot get the actionChains to click on the rows when hovering. I have tried click, double click and click_and_hold + release to no success.
Any help on either making move_by_offset + click work or using xPATH's more effectively would be great.
For context, I am using this on website for work so I cannot release the URL/photos of it. This is my first time using selenium.
for s in range(n):
scrollLim = 7
base = 180
for x in range(scrollLim):
print(str(x))
a.reset_actions()
a.move_by_offset(60, base + 60 * x).double_click()
a.perform()
time.sleep(1)
if x == scrollLim - 1:
a.send_keys(Keys.PAGE_DOWN).perform()
Related
I'm creating a webscraper with Selenium that will add products to a cart, and then cycle through cities, states and zip codes to give me the total cost of shipping + taxes for each area.
The website I'm using is: https://www.power-systems.com/shop/product/proelite-competition-kettlebell
Everything in my code appears to be working normally - the window will open, close a few pop ups and I can see Selenium select the proper option. However, regardless of whatever I've tried, after selenium clicks the "Add to Cart" button, it always adds the first option, despite having selected the proper one
Here is what I have been trying:
#created to simplify the code since I'll be using this option often
def element_present_click1(path_type,selector):
element_present = EC.element_to_be_clickable((path_type , selector))
WebDriverWait(driver, 30).until(element_present)
try:
driver.find_element(path_type , selector).click()
except:
clicker = driver.find_element(path_type , selector)
driver.execute_script("arguments[0].click();", clicker)
path = "C:\Program Files (x86)\msedgedriver.exe"
driver = webdriver.Edge(path)
driver.get('https://www.power-systems.com/shop/product/proelite-competition-kettlebell')
element_present_click1(By.CSS_SELECTOR,'button[name="bluecoreCloseButton"]')
element_present_click1(By.CSS_SELECTOR,'a[id="hs-eu-decline-button"]')
###this will correctly select the proper element
element_present_click1(By.XPATH, f"//span[text()='32 kg']")
###after this is clicked, it will always add the first option, which is 8 kg
driver.find_element(By.CSS_SELECTOR,'button.btn.btn-primary.add-to-cart.js-add-to-cart-button').submit()
I've tried a few different things, adding in some time.sleep() after clicking the option, refreshing the browser page, or selecting the option twice - no matter what I try, when I click add to cart it always adds the first option
Is there something I'm missing? Any help would be appreciated
You are using a wrong selector in the last step.
button.btn.btn-primary.add-to-cart.js-add-to-cart-button is not a unique locator.
You need to click the button inside the selected element block.
This will work:
driver.find_element(By.CSS_SELECTOR, ".variant-info.selected .add-to-cart-rollover").click()
It looks to me that find_element returns ONLY the first element it can find. Having taken a look at find_element it looks like you'd want to replace
driver.find_element(By.CSS_SELECTOR,'button...').submit()
with
random.choice(driver.find_elements(By.CSS_SELECTOR,'button...')).submit()
Imagine I am using a website interface, similar to an online survey. My code can navigate and complete the form by clicking the necessary button. I need to be able to identify which question to click based on a given input.
key_str = '10.'
element = driver.find_element(By.ID, key_str)
We now have to move a few elements forward to click the box that will exist to the right of it. I cannot simply direct xpath to the button, as I will not know where it will be prior to opening the webpage. This needs to be a 1 size fits all type of solution. That said, we will always find "Question #10", and there will always be a button nearby the question.
Ideally the code will be able to identify the position that the "key_str" element resides, feed back this positioning as some sort of variable, then use that variable to find 'button' element that is to the right of it on the page.
Visually: (excuse the fake code here, more meant to be conceptual)
position = element.location() #figure out location of our key_str
if element contains key_str: #check we are in right place
button_pos = position + 3 #if in right place, move to button element
action = ActionChains(driver)
# click the button
action.click(on_element = button_pos)
All advice is appreciated!
Today I'm having troubles due to a "a href" button that does not have any ID to be identified, then let's explain a little bit more about the problem... I have an structure like this one(let's assume XXX is an anonymous path):
wait = WebDriverWait(driver, 5)
el=wait.until(EC.presence_of_element_located((By.ID, 'XXX1')))
entries = el.find_elements_by_tag_name('tr')
for i in range(len(entries)):
if(entries[i].find_element_by_xpath(XXX2).text==compare):
el = wait.until(EC.element_to_be_clickable((By.ID,XXX3)))
el.click()
el=wait.until(EC.presence_of_element_located((By.ID, XXX4)))
entries2 = el.find_elements_by_tag_name('tr')
for j in range(len(entries2)):
#Some statements...
xpath = ".../a"
your_element=WebDriverWait(driver,10)\
.until(EC.element_to_be_clickable((By.XPATH,xpath)))##Here the problem
your_element.click()
Then, I'm getting information from an hibrid page (dynamic and static) using as driver a ChromeDriver one, once I get a big table, inside every row there is a button that shows more info, then I need to click it for open it too, the main problem is when this operation iterates, that error is shown by the output. This driver is a ChromeDriver one. In summary, first I search something and click on search button, then I get a table where every row(at the end in the last column) has a button that once is open, shows more information, consequently I need to open it and close it due to the next row, it works with the first row, but with the second one, it crashes. I would really appreciate any advice of how to handle this problem.
Thanks in advance!
The problem is that you change with the click the dom within your loop. For mr this never worked.
One solution is, to try to re-query within the loop to make sure your at the correct position. Your third line:
entries = el.find_elements_by_tag_name('tr')
should be executed every time and with a counter make sure you are at the correct position of your <tr> entries.
i am in a project to scroll and get the every posts that everyone posted. the problem is my code not reading every posts (just 2 or 3 and skipping to next). below is my code and i like to have my code in a way that it reads every posts. i also tried changing sleep() duration and pixel count while scrolling and scroll to view options , but no improvement
# scrolling and grabbing data
for i in range(1000):
element = driver.find_element_by_xpath('//div[contains(#class, "mnk10 copy-txt")]')
# driver.execute_script("return document.body.scrollHeight / 2",element)
driver.execute_script("arguments[0].scrollIntoView(true)",element)
# driver.execute_script("arguments[0].scrollBy(0, -300)",element)
# driver.execute_script("return, document.body.scrollHeight/4",element)
data1 = driver.find_element_by_xpath('//div[contains(#class, "mnk10 copy-txt")]').get_attribute('dat-plin-txt')
print(data1)
time.sleep(2)
You could try to scroll by a certain amount of one post instead of "scrollIntoView(true)" using the following script part:
driver.execute_script("arguments[0].scrollBy(0, 500)", element)
you might or might not have to change the "500" part
Problem similar to the one described here.
I want to get the mouse from point a to point b along a curve that I define. So, I need a and b's location coordinates. Point a is the mouse's current location, and point b is an element that I can locate. I can find the element's position using the following:
element = driver.find_element_by_class_name("insertnamehere")
x, y = element.location["x"], element.location["y"]
Unfortunately, I can't use similar Selenium methods to find the mouse's current location (as far as I know). So I have to find the mouse like this:
import pyautogui
x_mouse, y_mouse = pyautogui.position()
Pyautogui gives screen location, which--as the above linked question described--is not what element.location gives. But the linked solution doesn't work for me on the site that I'm interested in. That is, I don't get matching coordinates. The site is this one.
I suspect it's because Selenium's locator doesn't count the map element as part of the web page, and returns coordinates relative to the listings (the part that you can scroll). So, here are some ideas I've tried:
Convert the screen location into Selenium location, or vice versa.
This is difficult because I think the formula (screen to Selenium) will depend on my monitor, so won't work generally.
Put the mouse on a web element so that point a can be located using Selenium's .location.
Might be the best solution, but I would have to move to the element using ActionChains(driver).move_to_element(), which defeats the purpose of defining an a -> b mouse path.
Either find the mouse location using Selenium's location method or find the element in terms of screen coordinates.
I've tried pyautogui's locateOnScreen(). Seems promising, and I will probably just do it this way.
If you are trying to get the absolute x and y values (x and y values relative to screen) then use the below logic.
# maximize the browser window so that you can get the absolute x and y based on the window inner and outer heights
driver.maximize_window()
# navigate to OP
driver.get("https://stackoverflow.com/questions/56688961/locating-elements-screen-position-in-selenium-using-python")
# get ask question element
askQuestion = driver.find_element_by_link_text("Ask Question")
# get the browser panel height
panel_height = driver.execute_script('return window.outerHeight - window.innerHeight;')
# get absolute x value
abs_x = askQuestion.location['x']
# get y value (this is relative y value - meaning y value with in browser)
y = askQuestion.location['y']
abs_y = y + panel_height
# print the absolute x and y values
print ("Absolute x : " + abs_x)
print ("Absolute y : " + abs_y)