데스크탑에 있는 파일을 셀레니움에 드래그 앤 드롭하는 방법

PC에 있는 파일을 업로드등을 할 때 셀레니움에 드래그 앤 드롭해야할 때가 있다. 파이썬에서 자동으로 할 수 있는 방법을 인터넷을 찾던 중 아주 좋은 소스를 발견하여 올린다. 리스트 형식으로 여러개의 파일을 올릴 수도 있다.

from selenium import webdriver
from selenium.webdriver.remote.webelement import WebElement
import os.path

JS_DROP_FILES = "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;"

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 에 지정
dropzone = driver.find_element_by_css_selector("[data-preview='Basic example'] [style]")

#내 PC의 한개의 파일을 dropzone 에 올릴 경우
dropzone.drop_files("C:\\temp\\image1.png")

# 두개 이상의 파일을 올리고 싶으면 리스트형식을 쓰면 된다.
dropzone.drop_files(["C:\\temp\\image1.png", "C:\\temp\\image2.png"])

# 옵셋을 지정할 수 있다. offset은 dropzone 엘리먼트의 특정 위치에 정확히 올려야 할때 사용된다.
dropzone.drop_files("C:\\temp\\image1.png", offsetX=25, offsetY=25)

출처 : https://gist.github.com/florentbr/349b1ab024ca9f3de56e6bf8af2ac69e

 

Leave a Comment