Skip to content

Instantly share code, notes, and snippets.

@florentbr
Last active April 7, 2024 02:56
Show Gist options
  • Star 43 You must be signed in to star a gist
  • Fork 14 You must be signed in to fork a gist
  • Save florentbr/349b1ab024ca9f3de56e6bf8af2ac69e to your computer and use it in GitHub Desktop.
Save florentbr/349b1ab024ca9f3de56e6bf8af2ac69e to your computer and use it in GitHub Desktop.
Selenium - Drop a file from the desktop on a drop area
from selenium import webdriver
from selenium.webdriver.remote.webelement import WebElement
import os.path
# JavaScript: HTML5 File drop
# source : https://gist.github.com/florentbr/0eff8b785e85e93ecc3ce500169bd676
# param1 WebElement : Drop area element
# param2 Double : Optional - Drop offset x relative to the top/left corner of the drop area. Center if 0.
# param3 Double : Optional - Drop offset y relative to the top/left corner of the drop area. Center if 0.
# return WebElement : File input
JS_DROP_FILES = "var k=arguments,d=k[0],g=k[1],c=k[2],m=d.ownerDocument||document;for(var e=0;;){var f=d.getBoundingClientRect(),b=f.left+(g||(f.width/2)),a=f.top+(c||(f.height/2)),h=m.elementFromPoint(b,a);if(h&&d.contains(h)){break}if(++e>1){var j=new Error('Element not interactable');j.code=15;throw j}d.scrollIntoView({behavior:'instant',block:'center',inline:'center'})}var l=m.createElement('INPUT');l.setAttribute('type','file');l.setAttribute('multiple','');l.setAttribute('style','position:fixed;z-index:2147483647;left:0;top:0;');l.onchange=function(q){l.parentElement.removeChild(l);q.stopPropagation();var r={constructor:DataTransfer,effectAllowed:'all',dropEffect:'none',types:['Files'],files:l.files,setData:function u(){},getData:function o(){},clearData:function s(){},setDragImage:function i(){}};if(window.DataTransferItemList){r.items=Object.setPrototypeOf(Array.prototype.map.call(l.files,function(x){return{constructor:DataTransferItem,kind:'file',type:x.type,getAsFile:function v(){return x},getAsString:function y(A){var z=new FileReader();z.onload=function(B){A(B.target.result)};z.readAsText(x)},webkitGetAsEntry:function w(){return{constructor:FileSystemFileEntry,name:x.name,fullPath:'/'+x.name,isFile:true,isDirectory:false,file:function z(A){A(x)}}}}}),{constructor:DataTransferItemList,add:function t(){},clear:function p(){},remove:function n(){}})}['dragenter','dragover','drop'].forEach(function(v){var w=m.createEvent('DragEvent');w.initMouseEvent(v,true,true,m.defaultView,0,0,0,b,a,false,false,false,false,0,null);Object.setPrototypeOf(w,null);w.dataTransfer=r;Object.setPrototypeOf(w,DragEvent.prototype);h.dispatchEvent(w)})};m.documentElement.appendChild(l);l.getBoundingClientRect();return l"
def drop_files(element, files, offsetX=0, offsetY=0):
driver = element.parent
isLocal = not driver._is_remote or '127.0.0.1' in driver.command_executor._url
paths = []
# ensure files are present, and upload to the remote server if session is remote
for file in (files if isinstance(files, list) else [files]) :
if not os.path.isfile(file) :
raise FileNotFoundError(file)
paths.append(file if isLocal else element._upload(file))
value = '\n'.join(paths)
elm_input = driver.execute_script(JS_DROP_FILES, element, offsetX, offsetY)
elm_input._execute('sendKeysToElement', {'value': [value], 'text': value})
WebElement.drop_files = drop_files
############################# USAGE EXAMPLE #############################
driver = webdriver.Chrome()
driver.get("https://react-dropzone.js.org/")
dropzone = driver.find_element_by_css_selector("[data-preview='Basic example'] [style]")
# drop a single file
dropzone.drop_files("C:\\temp\\image1.png")
# drop two files
dropzone.drop_files(["C:\\temp\\image1.png", "C:\\temp\\image2.png"])
# drop a file by offset
dropzone.drop_files("C:\\temp\\image1.png", offsetX=25, offsetY=25)
var args = arguments,
element = args[0],
offsetX = args[1],
offsetY = args[2],
doc = element.ownerDocument || document;
for (var i = 0; ;) {
var box = element.getBoundingClientRect(),
clientX = box.left + (offsetX || (box.width / 2)),
clientY = box.top + (offsetY || (box.height / 2)),
target = doc.elementFromPoint(clientX, clientY);
if (target && element.contains(target))
break;
if (++i > 1) {
var ex = new Error('Element not interactable');
ex.code = 15;
throw ex;
}
element.scrollIntoView({behavior: 'instant', block: 'center', inline: 'center'});
}
var input = doc.createElement('INPUT');
input.setAttribute('type', 'file');
input.setAttribute('multiple', '');
input.setAttribute('style', 'position:fixed;z-index:2147483647;left:0;top:0;');
input.onchange = function (ev) {
input.parentElement.removeChild(input);
ev.stopPropagation();
var dataTransfer = {
constructor : DataTransfer,
effectAllowed : 'all',
dropEffect : 'none',
types : [ 'Files' ],
files : input.files,
setData : function setData(){},
getData : function getData(){},
clearData : function clearData(){},
setDragImage : function setDragImage(){}
};
if (window.DataTransferItemList) {
dataTransfer.items = Object.setPrototypeOf(Array.prototype.map.call(input.files, function(f) {
return {
constructor : DataTransferItem,
kind : 'file',
type : f.type,
getAsFile : function getAsFile () { return f },
getAsString : function getAsString (callback) {
var reader = new FileReader();
reader.onload = function(ev) { callback(ev.target.result) };
reader.readAsText(f);
},
webkitGetAsEntry : function webkitGetAsEntry () {
return {
constructor : FileSystemFileEntry,
name : f.name,
fullPath : '/' + f.name,
isFile : true,
isDirectory : false,
file : function file (callback) { callback(f) }
}
}
}
}), {
constructor : DataTransferItemList,
add : function add(){},
clear : function clear(){},
remove : function remove(){}
});
}
['dragenter', 'dragover', 'drop'].forEach(function (type) {
var event = doc.createEvent('DragEvent');
event.initMouseEvent(type, true, true, doc.defaultView, 0, 0, 0, clientX, clientY, false, false, false, false, 0, null);
Object.setPrototypeOf(event, null);
event.dataTransfer = dataTransfer;
Object.setPrototypeOf(event, DragEvent.prototype);
target.dispatchEvent(event);
});
};
doc.documentElement.appendChild(input);
input.getBoundingClientRect(); /* force reflow for Firefox */
return input;
var k=arguments,d=k[0],g=k[1],c=k[2],m=d.ownerDocument||document;for(var e=0;;){var f=d.getBoundingClientRect(),b=f.left+(g||(f.width/2)),a=f.top+(c||(f.height/2)),h=m.elementFromPoint(b,a);if(h&&d.contains(h)){break}if(++e>1){var j=new Error('Element not interactable');j.code=15;throw j}d.scrollIntoView({behavior:'instant',block:'center',inline:'center'})}var l=m.createElement('INPUT');l.setAttribute('type','file');l.setAttribute('multiple','');l.setAttribute('style','position:fixed;z-index:2147483647;left:0;top:0;');l.onchange=function(q){l.parentElement.removeChild(l);q.stopPropagation();var r={constructor:DataTransfer,effectAllowed:'all',dropEffect:'none',types:['Files'],files:l.files,setData:function u(){},getData:function o(){},clearData:function s(){},setDragImage:function i(){}};if(window.DataTransferItemList){r.items=Object.setPrototypeOf(Array.prototype.map.call(l.files,function(x){return{constructor:DataTransferItem,kind:'file',type:x.type,getAsFile:function v(){return x},getAsString:function y(A){var z=new FileReader();z.onload=function(B){A(B.target.result)};z.readAsText(x)},webkitGetAsEntry:function w(){return{constructor:FileSystemFileEntry,name:x.name,fullPath:'/'+x.name,isFile:true,isDirectory:false,file:function z(A){A(x)}}}}}),{constructor:DataTransferItemList,add:function t(){},clear:function p(){},remove:function n(){}})}['dragenter','dragover','drop'].forEach(function(v){var w=m.createEvent('DragEvent');w.initMouseEvent(v,true,true,m.defaultView,0,0,0,b,a,false,false,false,false,0,null);Object.setPrototypeOf(w,null);w.dataTransfer=r;Object.setPrototypeOf(w,DragEvent.prototype);h.dispatchEvent(w)})};m.documentElement.appendChild(l);l.getBoundingClientRect();return l
@oliverguenther
Copy link

This works perfectly, thanks @florentbr. Since you didn't mention a license, is this free to fork and adapt?

@zealot128
Copy link

zealot128 commented Jan 3, 2019

Awesome thanks!

Here is a ruby adaption for a single file:

                                                                                                                                                                              
def drop_file(element_or_selector, file, offset_x: 0, offset_y: 0)        
  js = "var c=arguments,b=c[0],k=c[1];c=c[2];for(var d=b.ownerDocument||document,l=0;;){var e=b.getBoundingClientRect(),g=e.left+(k||e.width/2),h=e.top+(c||e.height/2),f=d.elementFromPoint(g,h);if(f&&b.contains(f))break;if(1<++l)throw b=Error('Element not interactable'),b.code=15,b;b.scrollIntoView({behavior:'instant',block:'center',inline:'center'})}var a=d.createElement('INPUT');a.setAttribute('type','file');a.setAttribute('multiple','');a.setAttribute('style','position:fixed;z-index:2147483647;left:0;top:0;');a.onchange=function(b){a.parentElement.removeChild(a);b.stopPropagation();var c={constructor:DataTransfer,effectAllowed:'all',dropEffect:'none',types:['Files'],files:a.files,setData:function(){},getData:function(){},clearData:function(){},setDragImage:function(){}};window.DataTransferItemList&&(c.items=Object.setPrototypeOf(Array.prototype.map.call(a.files,function(a){return{constructor:DataTransferItem,kind:'file',type:a.type,getAsFile:function(){return a},getAsString:function(b){var c=new FileReader;c.onload=function(a){b(a.target.result)};c.readAsText(a)}}}),{constructor:DataTransferItemList,add:function(){},clear:function(){},remove:function(){}}));['dragenter','dragover','drop'].forEach(function(a){var b=d.createEvent('DragEvent');b.initMouseEvent(a,!0,!0,d.defaultView,0,0,0,g,h,!1,!1,!1,!1,0,null);Object.setPrototypeOf(b,null);b.dataTransfer=c;Object.setPrototypeOf(b,DragEvent.prototype);f.dispatchEvent(b)})};d.documentElement.appendChild(a);a.getBoundingClientRect();return a;" 
  value = File.expand_path(file)       
  element = element_or_selector.is_a?(String) ? first(element_or_selector) : element_or_selector
  input = page.execute_script(js, element, offset_x, offset_y)
  input.send_keys value
end

drop_file ".drop-zone", "spec/files/doc.pdf"

@mbahar
Copy link

mbahar commented Jul 15, 2019

Works out-of-the box! Very much appreciated @florentbr

Btw, the reason I need that is; I found input_element.send_keys (filename) approach is unreliable with Selenium, if the DOM is manipulated on the browser with each file upload. Above code fixed my problem.

@YoussofH
Copy link

YoussofH commented Aug 30, 2019

Hi, @florentbr I would like to read a brief explanation of how to manage this project on a Mac thanks. Because I am still new to selenium but my target is not to master it, instead I need to finish a little project in my hands. And after that, I will see how can I learn about it further.

What happens is that chrome opens https://react-dropzone.js.org/ and loads a little bit, then nothing happens. I check all the drop divs if any has the selected image but, it appears no the code didn't work.

Traceback (most recent call last):
  File "UploadPDF.py", line 38, in <module>
    dropzone.drop_files("/Users/user/Desktop/simcity-buildit-fankit/SCBI Fan Kit/Icons/Production item icons/cheesefries.png", offsetX=25, offsetY=25)
  File "UploadPDF.py", line 25, in drop_files
    elm_input = driver.execute_script(JS_DROP_FILES, element, offsetX, offsetY)
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/selenium/webdriver/remote/webdriver.py", line 636, in execute_script
    'args': converted_args})['value']
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/selenium/webdriver/remote/webdriver.py", line 321, in execute
    self.error_handler.check_response(response)
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/selenium/webdriver/remote/errorhandler.py", line 242, in check_response
    raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.WebDriverException: Message: <unknown>: Element not interactable
  (Session info: chrome=76.0.3809.132)

Edit: I forgot to mention that all scripts are in the same folder. But I don't know what data I have to change inside the code!!

@bigsea00001
Copy link

It works fine with the first upload, but when I run it the second time, I get the following error. I have been wandering for a week. Is there any way to solve this problem? Thank you in advance.
error message ------------------------------------------------------------>>>
File "C:\Users\s\AppData\Local\Programs\Python\Python37-32\lib\site-packages\urllib3\connectionpool.py", line 603, in urlopen
chunked=chunked)
File "C:\Users\s\AppData\Local\Programs\Python\Python37-32\lib\site-packages\urllib3\connectionpool.py", line 387, in _make_request
six.raise_from(e, None)
File "", line 2, in raise_from
File "C:\Users\s\AppData\Local\Programs\Python\Python37-32\lib\site-packages\urllib3\connectionpool.py", line 383, in _make_request
httplib_response = conn.getresponse()
File "C:\Users\s\AppData\Local\Programs\Python\Python37-32\lib\http\client.py", line 1321, in getresponse
response.begin()
File "C:\Users\s\AppData\Local\Programs\Python\Python37-32\lib\http\client.py", line 296, in begin
version, status, reason = self._read_status()
File "C:\Users\s\AppData\Local\Programs\Python\Python37-32\lib\http\client.py", line 257, in _read_status
line = str(self.fp.readline(_MAXLINE + 1), "iso-8859-1")
File "C:\Users\s\AppData\Local\Programs\Python\Python37-32\lib\socket.py", line 589, in readinto
return self._sock.recv_into(b)
ConnectionResetError: [WinError 10054] The current connection was forcibly closed by the remote host

@JattMones
Copy link

JattMones commented Oct 2, 2019

@bigsea00001 I'm unsure of the error you are receiving. However, I'm getting a stale element reference error when I try to run the drag_drop function again. I assume that the drop-area webelement is updated/refreshed once a drag/drop happens. So, to call this multiple time's, you should get the updated drop-area web element each time (this fixed worked for me).

I'm assuming that you are running the function twice, not passing a list with two files. It seems like you're getting a connection issue, are you using a remote browser? Are you on a network with a proxy and firewall?

I found a similar error here. Users suggested checking anti-virus, etc.

@shubhraDunzo
Copy link

thanks. it worked perfectly !

@ShayaneB
Copy link

It worked for me... But I want to upload different files in different drop zones. I am not able to do that using this code. Can anyone please assist me doing that as I am new to this?

@pattersonrptr
Copy link

It worked wonderfully, it saved my life, thanks!

@siarheilebedzeu
Copy link

t worked wonderfully!! Thanks a lot, you save my time!

@sumitanand10
Copy link

This is awsome. It helped me save 3 hrs everyday.!!
Thank you for posting this.

@richa2227
Copy link

Can anyone tell me that where I have to put wd-drop-file.js in project?

@Theramas
Copy link

Theramas commented Apr 1, 2021

@florentbr
Worked great with files!
But I currently need to drag and drop folder. What JS script can I use for that?

@amarmulyak
Copy link

Works for me as well) Thanks a lot!

@katybaulch
Copy link

katybaulch commented Sep 2, 2021

florenbr> @Theramas

Worked great with files!
But I currently need to drag and drop folder. What JS script can I use for that?

I recently needed to do this. I've extended @florenbr 's code to check whether the path given to drop_files() is a directory, and if so to iterate through all the files in the directory and append them to the master list.

def drop_files(element, paths_to_upload, offsetX= 0, offsetY= 0):
    """Drag and drop datainto the Dropzone.

    Source: https://gist.github.com/florentbr/0eff8b785e85e93ecc3ce500169bd676
    """
    driver = element.parent
    isLocal = not driver._is_remote or "127.0.0.1" in driver.command_executor._url
    files_to_upload = []

    # Ensure files are present, and upload to the remote server if the session is remote.
    for path_to_upload in (
        paths_to_upload if isinstance(paths_to_upload, list) else [paths_to_upload]
    ):
        if isdir(path_to_upload):
            all_files = []

            # Get the list of all files in the directory tree at the given path.
            for path, _, files in walk(path_to_upload):
                all_files += [join(path, name) for name in files]

            # Add each file in the directory to the list of files to drop into the Dropzone.
            for file in all_files:
                files_to_upload.append(file if isLocal else element._upload(file))

        elif isfile(path_to_upload):
            # Add the file to the list of files to drop into the Dropzone.
            files_to_upload.append(
                path_to_upload if isLocal else element._upload(path_to_upload)
            )

        else:
            raise FileNotFoundError(path_to_upload)

    elm_input = driver.execute_script(JS_DROP_FILES, element, offsetX, offsetY)

    value = "\n".join(files_to_upload)
    elm_input._execute("sendKeysToElement", {"value": [value], "text": value})

@sandip2421
Copy link

not working for me .. getting error TypeError e.webkitGetAsEntry is not a function (java)

@florentbr
Copy link
Author

@sandip2421, i've added the webkitGetAsEntry even though it's non standard. It should work as long as the webpage doesn't try to access the filesystem api.

@kaylezhangzhaoLin
Copy link

I used this code in headless mode but this error occurred var ex = new Error('Element not interactable');, can you help me? thanks

@thpryrchn
Copy link

@carl-pki For headless, you need to set the window size. this is what I do:

if data['headless']:
    options = Options()
    options.add_argument('--headless')
    options.add_argument('--disable-gpu')  # Last I checked this was necessary.
    driver = webdriver.Chrome(options=options)
else:
    driver = webdriver.Chrome()
driver.set_window_size(1547, 1102)
driver.implicitly_wait(2400)
driver.get("https://rumble.com/")
driver.find_element(..........

As You can see, I am using Chrome... But I'm sure it applies to other browsers

@raishid
Copy link

raishid commented Jul 19, 2022

and trying to use this code in an implementation to upload files with this method to Google Drive but notice that it stays in this can someone try?

here the code...

`from undetected_chromedriver import Chrome
from undetected_chromedriver import ChromeOptions
from selenium.webdriver.remote.webelement import WebElement
import os
from time import sleep

opts = ChromeOptions()
opts.add_argument(f'--user-data-dir={os.getcwd()}/driver/profile')
opts.add_argument(f"--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36")

driver = Chrome(executable_path=f'{os.getcwd()}/driver/chromedriver.exe', options=opts)

sleep(2)

driver.get('https://drive.google.com/drive/my-drive')
sleep(5)
JS_DROP_FILES = "var k=arguments,d=k[0],g=k[1],c=k[2],m=d.ownerDocument||document;for(var e=0;;){var f=d.getBoundingClientRect(),b=f.left+(g||(f.width/2)),a=f.top+(c||(f.height/2)),h=m.elementFromPoint(b,a);if(h&&d.contains(h)){break}if(++e>1){var j=new Error('Element not interactable');j.code=15;throw j}d.scrollIntoView({behavior:'instant',block:'center',inline:'center'})}var l=m.createElement('INPUT');l.setAttribute('type','file');l.setAttribute('multiple','');l.setAttribute('style','position:fixed;z-index:2147483647;left:0;top:0;');l.onchange=function(q){l.parentElement.removeChild(l);q.stopPropagation();var r={constructor:DataTransfer,effectAllowed:'all',dropEffect:'none',types:['Files'],files:l.files,setData:function u(){},getData:function o(){},clearData:function s(){},setDragImage:function i(){}};if(window.DataTransferItemList){r.items=Object.setPrototypeOf(Array.prototype.map.call(l.files,function(x){return{constructor:DataTransferItem,kind:'file',type:x.type,getAsFile:function v(){return x},getAsString:function y(A){var z=new FileReader();z.onload=function(B){A(B.target.result)};z.readAsText(x)},webkitGetAsEntry:function w(){return{constructor:FileSystemFileEntry,name:x.name,fullPath:'/'+x.name,isFile:true,isDirectory:false,file:function z(A){A(x)}}}}}),{constructor:DataTransferItemList,add:function t(){},clear:function p(){},remove:function n(){}})}['dragenter','dragover','drop'].forEach(function(v){var w=m.createEvent('DragEvent');w.initMouseEvent(v,true,true,m.defaultView,0,0,0,b,a,false,false,false,false,0,null);Object.setPrototypeOf(w,null);w.dataTransfer=r;Object.setPrototypeOf(w,DragEvent.prototype);h.dispatchEvent(w)})};m.documentElement.appendChild(l);l.getBoundingClientRect();return l"

def drop_files(element, files, offsetX=0, offsetY=0):
driver = element.parent
isLocal = not driver._is_remote or '127.0.0.1' in driver.command_executor._url
paths = []

# ensure files are present, and upload to the remote server if session is remote
for file in (files if isinstance(files, list) else [files]):
    if not os.path.isfile(file):
        raise FileNotFoundError(file)
    paths.append(file if isLocal else element._upload(file))

value = '\n'.join(paths)
elm_input = driver.execute_script(JS_DROP_FILES, element, offsetX, offsetY)
elm_input._execute('sendKeysToElement', {'value': [value], 'text': value})

WebElement.drop_files = drop_files
dropzone = driver.find_element_by_xpath('//c-wiz[@data-region-root]')

dropzone.drop_files(f'{os.getcwd()}\downloads\english.srt')`

image

with this code it stays on this screen and does not go up.

@semisenioritis
Copy link

worked straight out of the box!! o7
the only solution on the internet that actually solves the problem without beating around the bush.

@hieult37
Copy link

hieult37 commented Mar 7, 2024

Hi guys,
I tried to test it and get the error message.

selenium.common.exceptions.WebDriverException: Message: <unknown>: Element not interactable

Can any one can help me resolve it?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment