6

Tell me please, what am I doing wrong? I try to drag and drop through Selenium, but every time I come across an error "AttributeError: move_to requires a WebElement"

Here is my code:

from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains

chromedriver = '/usr/local/bin/chromedriver'

driver = webdriver.Chrome(chromedriver)
driver.get('http://www.dhtmlgoodies.com/scripts/drag-drop-custom/demo-drag-drop-3.html')

source = driver.find_elements_by_xpath('//*[@id="box3"]')
target = driver.find_elements_by_xpath('//*[@id="box103"]')

action = ActionChains(driver)
action.drag_and_drop(source, target).perform()

I also tried, like this:

from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains

chromedriver = '/usr/local/bin/chromedriver'

driver = webdriver.Chrome(chromedriver)
driver.get('http://www.dhtmlgoodies.com/scripts/drag-drop-custom/demo-drag-drop-3.html')

source = driver.find_elements_by_xpath('//*[@id="box3"]')
target = driver.find_elements_by_xpath('//*[@id="box103"]')
ActionChains(driver).click_and_hold(source).move_to_element(target).release(target).perform()

Always coming out "AttributeError: move_to requires a WebElement"

Traceback (most recent call last):
  File "drag_and_drop_test.py", line 13, in <module>
    ActionChains(driver).click_and_hold(source).move_to_element(target).release(target).perform()
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/selenium/webdriver/common/action_chains.py", line 121, in click_and_hold
    self.move_to_element(on_element)
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/selenium/webdriver/common/action_chains.py", line 273, in move_to_element
    self.w3c_actions.pointer_action.move_to(to_element)
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/selenium/webdriver/common/actions/pointer_actions.py", line 42, in move_to
    raise AttributeError("move_to requires a WebElement")
AttributeError: move_to requires a WebElement
I.Z.
  • 177
  • 1
  • 1
  • 13

4 Answers4

6

find_elements_by_xpath returns a list of WebElements, drag_and_drop (and the other methods) accept a single WebElement. Use find_element_by_xpath

source = driver.find_element_by_xpath('//*[@id="box3"]')
target = driver.find_element_by_xpath('//*[@id="box103"]')
Guy
  • 46,488
  • 10
  • 44
  • 88
  • Guy, Hello! Thanks for your reply! Yes, the real problem was that I chose 'find_elements_by_xpath', but it was necessary 'find_element_by_xpath'. Good experience, I will know – I.Z. Jan 06 '20 at 21:23
2

as @guy said:

find_elements_by_xpath

returns list of WebElements. You can use find_element_by_xpath method to get single web element. Or select specific element from WebElements return by find_elements_by_xpath. For example, if you know, you wanted to select 2nd element from return list for target. Then you can try like this:

from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains

chromedriver = '/usr/local/bin/chromedriver'

driver = webdriver.Chrome(chromedriver)
driver.get('http://www.dhtmlgoodies.com/scripts/drag-drop-custom/demo-drag-drop-3.html')

source = driver.find_elements_by_xpath('//*[@id="box3"]')[0]
target = driver.find_elements_by_xpath('//*[@id="box103"]')[1]

action = ActionChains(driver)
action.drag_and_drop(source, target).perform()

i can see we are selecting element which have id but ids are unique, so there can be only one id. So you can also do this like this:

from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains

chromedriver = '/usr/local/bin/chromedriver'

driver = webdriver.Chrome(chromedriver)
driver.get('http://www.dhtmlgoodies.com/scripts/drag-drop-custom/demo-drag-drop-3.html')

source = driver.find_element_by_id('box3')
target = driver.find_element_by_id('box103')

action = ActionChains(driver)
action.drag_and_drop(source, target).perform()

i like to use find_element_by_id because it looks cleaner to me than xpath.

Ammad Khalid
  • 176
  • 2
  • 9
0

This error message...

AttributeError: move_to requires a WebElement

...implies that the move_to_element() requires a WebElement as an argument.

Seems you were close. You have used find_elements_by_xpath() which returns a List where as you need pass a WebElement within move_to_element().

Solution

To drag the element with text as Washington and drop within the element with text as United States through Selenium you have to induce WebDriverWait for the element_to_be_clickable() and you can use the following Locator Strategies:

  • Code Block:

    driver.get('http://www.dhtmlgoodies.com/scripts/drag-drop-custom/demo-drag-drop-3.html')
    source = WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//div[@class='dragableBox' and @id='box3']")))
    target = WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//div[@class='dragableBoxRight' and @id='box103']")))
    ActionChains(driver).click_and_hold(source).move_to_element(target).release(target).perform()
    
  • Note : You have to add the following imports :

    from selenium.webdriver.support.ui import WebDriverWait
    from selenium.webdriver.common.by import By
    from selenium.webdriver.support import expected_conditions as EC
    
  • Browser Snapshot:

drag_and_drop

undetected Selenium
  • 183,867
  • 41
  • 278
  • 352
0

use find_elements_by_xpath instead find_element_by_xpath

zzhapar
  • 107
  • 3