无法使用 Selenium 执行拖放 (python)
Unable to perform drag and drop with Selenium (python)
我在私有 Web 应用程序的 python 中难以使用 Selenium 执行拖放或单击并按住操作。
我尝试在 public 示例中重现我的错误:
http://the-internet.herokuapp.com/drag_and_drop
下面是我的拖放/点击并按住的基本代码
from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.common.by import By
driver = webdriver.Chrome()
driver.get('http://the-internet.herokuapp.com/drag_and_drop')
dragged = driver.find_element(By.ID, "column-a")
dropped = driver.find_element(By.ID, "column-b")
#Drag and drop
actions = ActionChains(driver)
actions.drag_and_drop(dragged, dropped).perform()
#column A is selected but not dragged
#Click and hold
actions = ActionChains(driver)
actions.move_to_element(dragged).click_and_hold().move_to_element(dropped).release().perform()
#Same result : column a is selected but not dragged
通过 Whosebug 搜索,我遇到了一个 "solution" 的 public 示例,使用 javascript。
import os
with open(os.path.abspath('C:/Users/Admin/PycharmProjects/AutoTestIntro/drag_and_drop_helper.js'), 'r') as js_file:
line = js_file.readline()
script = ''
while line:
script += line
line = js_file.readline()
driver.execute_script(script+"$('#column-a').simulateDragDrop({ dropTarget: '#column-b'});")
这可以直接在 python 中完美运行,但要求拖放元素具有 ID。我目前在做的私人项目不是这样的。
我对 Selenium 做错了什么吗?
JS 中是否有任何解决方法来指定 xpath 而不是 id ?
我终于找到答案了!!!
见下文:
https://gist.github.com/florentbr/60ef7cb8d9b1ae690cafc82aad52da73
我用的是drag-drop.min.js
中的函数
这里是 python 中的一个简短示例:
JS_DRAG_AND_DROP = "function h(a,b,c,d){var k=l.createEvent('DragEvent');k.initMouseEvent(b,!0,!0,l.defaultView,0,0,0,m,n,w,x,y,!1,0,null);Object.setPrototypeOf(k,null);k.dataTransfer=g;Object.setPrototypeOf(k,DragEvent.prototype);a.dispatchEvent(k);setTimeout(d,c)}var a=arguments,c=a[0],d=a[1],q=a[2]||0,r=a[3]||0,t=a[4]||1;a=a[5]||'';var x='alt'===a||'\ue00a'===a,w='ctrl'===a||'\ue009'===a,y='shift'===a||'\ue008'===a,l=c.ownerDocument;a=c.getBoundingClientRect();var e=d?d.getBoundingClientRect():a,m=a.left+a.width/2,n=a.top+a.height/2,u=e.left+(q?q:e.width/2),v=e.top+(r?r:e.height/2),p=l.elementFromPoint(m,n),f=l.elementFromPoint(u,v);for(d=p;d&&!d.draggable;)d=d.parentElement;if(!d||!c.contains(p))throw c=Error('source element is not interactable/draggable'),c.code=15,c;if(!f)throw c=Error('target element is not interactable'),c.code=15,c;var g={constructor:DataTransfer,effectAllowed:null,dropEffect:null,types:[],files:Object.setPrototypeOf([],null),_items:Object.setPrototypeOf([],{add:function(a,b){this[this.length]={_data:''+_data,kind:'string',type:b,getAsFile:function(){},getAsString:function(a){a(this._data)}};g.types.push(b)},remove:function(a){Array.prototype.splice.call(this,a&65535,1);g.types.splice(a&65535,1)},clear:function(a,b){this.length=0;g.types.length=0}}),setData:function(a,b){this.clearData(a);this._items.add(b,a)},getData:function(a){for(var b=this._items.length;b--&&this._items[b].type!==a;);return 0<=b?this._items[b]._data:null},clearData:function(a){for(var b=this._items.length;b--&&this._items[b].type!==a;);this._items.remove(b)},setDragImage:function(a){}};'items'in DataTransfer.prototype&&(g.items=g._items);e=f.getBoundingClientRect();h(p,'dragstart',t,function(){var a=f.getBoundingClientRect();m=a.left+u-e.left;n=a.top+v-e.top;h(f,'dragenter',1,function(){h(f,'dragover',t,function(){f=l.elementFromPoint(m,n);h(f,'drop',1,function(){h(p,'dragend',1,function(){})})})})})"
def drag_and_drop(driver, source, target=None, offsetX=0, offsetY=0, delay=25, key=None) :
driver.execute_script(JS_DRAG_AND_DROP, source, target, offsetX, offsetY, delay, key)
time.sleep(delay * 2 / 1000)
driver = webdriver.Chrome()
driver.get("http://the-internet.herokuapp.com/drag_and_drop")
# drag and drop Glass
source = driver.find_element_by_xpath("//*[@id='column-a']")
target = driver.find_element_by_xpath("//*[@id='column-b']")
drag_and_drop(driver, source, target)
我希望下面的代码可以解决您在 Java
中遇到的问题
public class darganddropTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
System.setProperty("webdriver.chrome.driver","./chromedriver_win32/chromedriver.exe");
WebDriver driver = new ChromeDriver();
driver.get("https://jqueryui.com/droppable/");
System.out.println(driver.findElements(By.tagName("iframe")).size());
driver.switchTo().frame(driver.findElement(By.className("demo-frame")));
driver.findElement(By.id("draggable")).click();
Actions a = new Actions(driver);
WebElement drag = driver.findElement(By.id("draggable"));
WebElement drop = driver.findElement(By.id("droppable"));
a.dragAndDrop(drag, drop).build().perform();
driver.switchTo().defaultContent();
}
}
我在私有 Web 应用程序的 python 中难以使用 Selenium 执行拖放或单击并按住操作。
我尝试在 public 示例中重现我的错误: http://the-internet.herokuapp.com/drag_and_drop
下面是我的拖放/点击并按住的基本代码
from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.common.by import By
driver = webdriver.Chrome()
driver.get('http://the-internet.herokuapp.com/drag_and_drop')
dragged = driver.find_element(By.ID, "column-a")
dropped = driver.find_element(By.ID, "column-b")
#Drag and drop
actions = ActionChains(driver)
actions.drag_and_drop(dragged, dropped).perform()
#column A is selected but not dragged
#Click and hold
actions = ActionChains(driver)
actions.move_to_element(dragged).click_and_hold().move_to_element(dropped).release().perform()
#Same result : column a is selected but not dragged
通过 Whosebug 搜索,我遇到了一个 "solution" 的 public 示例,使用 javascript。
import os
with open(os.path.abspath('C:/Users/Admin/PycharmProjects/AutoTestIntro/drag_and_drop_helper.js'), 'r') as js_file:
line = js_file.readline()
script = ''
while line:
script += line
line = js_file.readline()
driver.execute_script(script+"$('#column-a').simulateDragDrop({ dropTarget: '#column-b'});")
这可以直接在 python 中完美运行,但要求拖放元素具有 ID。我目前在做的私人项目不是这样的。
我对 Selenium 做错了什么吗? JS 中是否有任何解决方法来指定 xpath 而不是 id ?
我终于找到答案了!!!
见下文:
https://gist.github.com/florentbr/60ef7cb8d9b1ae690cafc82aad52da73
我用的是drag-drop.min.js
中的函数这里是 python 中的一个简短示例:
JS_DRAG_AND_DROP = "function h(a,b,c,d){var k=l.createEvent('DragEvent');k.initMouseEvent(b,!0,!0,l.defaultView,0,0,0,m,n,w,x,y,!1,0,null);Object.setPrototypeOf(k,null);k.dataTransfer=g;Object.setPrototypeOf(k,DragEvent.prototype);a.dispatchEvent(k);setTimeout(d,c)}var a=arguments,c=a[0],d=a[1],q=a[2]||0,r=a[3]||0,t=a[4]||1;a=a[5]||'';var x='alt'===a||'\ue00a'===a,w='ctrl'===a||'\ue009'===a,y='shift'===a||'\ue008'===a,l=c.ownerDocument;a=c.getBoundingClientRect();var e=d?d.getBoundingClientRect():a,m=a.left+a.width/2,n=a.top+a.height/2,u=e.left+(q?q:e.width/2),v=e.top+(r?r:e.height/2),p=l.elementFromPoint(m,n),f=l.elementFromPoint(u,v);for(d=p;d&&!d.draggable;)d=d.parentElement;if(!d||!c.contains(p))throw c=Error('source element is not interactable/draggable'),c.code=15,c;if(!f)throw c=Error('target element is not interactable'),c.code=15,c;var g={constructor:DataTransfer,effectAllowed:null,dropEffect:null,types:[],files:Object.setPrototypeOf([],null),_items:Object.setPrototypeOf([],{add:function(a,b){this[this.length]={_data:''+_data,kind:'string',type:b,getAsFile:function(){},getAsString:function(a){a(this._data)}};g.types.push(b)},remove:function(a){Array.prototype.splice.call(this,a&65535,1);g.types.splice(a&65535,1)},clear:function(a,b){this.length=0;g.types.length=0}}),setData:function(a,b){this.clearData(a);this._items.add(b,a)},getData:function(a){for(var b=this._items.length;b--&&this._items[b].type!==a;);return 0<=b?this._items[b]._data:null},clearData:function(a){for(var b=this._items.length;b--&&this._items[b].type!==a;);this._items.remove(b)},setDragImage:function(a){}};'items'in DataTransfer.prototype&&(g.items=g._items);e=f.getBoundingClientRect();h(p,'dragstart',t,function(){var a=f.getBoundingClientRect();m=a.left+u-e.left;n=a.top+v-e.top;h(f,'dragenter',1,function(){h(f,'dragover',t,function(){f=l.elementFromPoint(m,n);h(f,'drop',1,function(){h(p,'dragend',1,function(){})})})})})"
def drag_and_drop(driver, source, target=None, offsetX=0, offsetY=0, delay=25, key=None) :
driver.execute_script(JS_DRAG_AND_DROP, source, target, offsetX, offsetY, delay, key)
time.sleep(delay * 2 / 1000)
driver = webdriver.Chrome()
driver.get("http://the-internet.herokuapp.com/drag_and_drop")
# drag and drop Glass
source = driver.find_element_by_xpath("//*[@id='column-a']")
target = driver.find_element_by_xpath("//*[@id='column-b']")
drag_and_drop(driver, source, target)
我希望下面的代码可以解决您在 Java
中遇到的问题public class darganddropTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
System.setProperty("webdriver.chrome.driver","./chromedriver_win32/chromedriver.exe");
WebDriver driver = new ChromeDriver();
driver.get("https://jqueryui.com/droppable/");
System.out.println(driver.findElements(By.tagName("iframe")).size());
driver.switchTo().frame(driver.findElement(By.className("demo-frame")));
driver.findElement(By.id("draggable")).click();
Actions a = new Actions(driver);
WebElement drag = driver.findElement(By.id("draggable"));
WebElement drop = driver.findElement(By.id("droppable"));
a.dragAndDrop(drag, drop).build().perform();
driver.switchTo().defaultContent();
}
}