2

In order to automate drag and drop functionality, I am using Python Webdriver. While it worked for some apps, it didn't work for the one below.

URL: https://www.w3schools.com/html/html5_draganddrop.asp enter image description here Trying to put this image into this empty div.

The following have been tried: everything has been imported, there is no syntax error in the code.

s = wait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//*[@id='drag1']")))
d = wait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//*[@id='div2']")))
action_chains.drag_and_drop(s, d).perform()

Some questions:

  1. Can't I do this without using Jquery ?
  2. When I place the cursor on an empty div during automation, it drops in the right place (empty div), why is that?
  3. Wherever my mouse cursor is, it drops there. Why?

Can anyone please help me figure out why this is happening? I have been trying to figure it out for 3 hours straight.

Shyam Sundar
  • 131
  • 1
  • 1
  • 7
  • 1
    I suggest you to try `pyautogui`, it always work but is less precise because you cannot drag from one element to another, but rather from one position to another based on the cursor's coordinates – sound wave Jan 13 '23 at 09:39
  • @soundwave Yes sure, can you please elaborate that use. I was more curious to know, why drag and drop is not working with already made function selenium library. – Shyam Sundar Jan 14 '23 at 06:59

1 Answers1

1

I don't know why but sometimes action chains doesn't work. Luckily there is an alternative: pyautogui (pip install pyautogui). It always works but uses mouse coordinates instead of elements of the webpage, so it has the big drawback that it cannot interact with the elements found with selenium.

About the drag and drop task we have a couple of ways to do it.

First method

import pyautogui, time

# 200=horizontal displacement in pixels, 0=vertical displacement, 1=duration in seconds
pyautogui.drag(200, 0, 1, button='left')
time.sleep(1)
pyautogui.drag(-200, 0, 1, button='left')

The first command drags the mouse right 200 pixels over 1 seconds while holding down the left mouse button, then the second command drags the mouse left 200 pixels (here the documentation). The downside of this method is that before running the code you have to manually positionate the mouse over the starting element.

enter image description here

Second method

Alternatively, you can take a picture of the starting element enter image description here and a picture of the ending element enter image description here then pyautogui will search on the screen those elements (i.e. their coordinates) and drag the mouse from the center of the first one to the center of the second one.

element_start = pyautogui.locateOnScreen('start.png')
element_end = pyautogui.locateOnScreen('end.png')

# compute the coordinates (x,y) of the center
center_start = pyautogui.center(element_start)
center_end = pyautogui.center(element_end)

pyautogui.moveTo(center_start)
time.sleep(1)
pyautogui.dragTo(center_end.x, center_end.y, 1, button='left')
time.sleep(1)
pyautogui.dragTo(center_start.x, center_start.y, 1, button='left')

Both methods have obvious drawbacks with respect to the Action Chains' drag_and_drop(), but we can use them when it doesn't work.

sound wave
  • 3,191
  • 3
  • 11
  • 29
  • Thank you @sound wave for you infomartive solution. Would that work in headless mode as well ? One more thing, if we have do start it manually, then that is not an automation. What you suggest – Shyam Sundar Jan 17 '23 at 10:09
  • @ShyamSundar Unfortunately pyautogui doesn't work in headless mode because it requires the browser window to be visible on screen. The problem with the first method is to automatically find coordinates of the starting element, it's an hard task but you can try using these methods https://stackoverflow.com/questions/42807676/pythonselenium-on-screen-position-of-element. The second method can be fully automated by taking screenshot of selenium element `s` and `d` (from your code) which is done with `s.screenshot('start.png')` and `d.screenshot('end.png')` – sound wave Jan 17 '23 at 10:36