English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
파일 업로드는 모든 UI 자동화 테스트가 직면하는 고통스러운 문제 중 하나입니다. 오늘 블로거는 여러분에게 파일 업로드를 처리하는 경험을 공유하겠습니다. 이를 통해 많은 seleniumer들이 파일 업로드에 걸린 문제를 해결할 수 있기를 바랍니다.
먼저, 업로드 버튼의 종류를 구분해야 합니다. 일반적으로 두 가지로 나눌 수 있습니다. 하나는 input 상자이며, 다른 하나는 비교적 복잡합니다. js, flash 등을 통해 실현되며, 태그는 input이 아닙니다
우리는 이 두 가지를 분석할 것입니다:
1.input 레이블
众所周知,input 레이블은 직접 send_keys를 할 수 있는 것이며,이 경우도 마찬가지입니다. 코드 예제를 보겠습니다:
예제 웹사이트: http://www.sahitest.com/demo/php/fileUpload.htm
代码:
# -*- coding: utf-8 -*- from selenium import webdriver driver = webdriver.Firefox() driver.get('http:)//sahitest.com/demo/php/fileUpload.htm') upload = driver.find_element_by_id('file') upload.send_keys('d:\\baidu.py') # send_keys print upload.get_attribute('value') # check value driver.quit()
결과:
baidu.py
很明显,对于input上传,直接send_keys是最简单的解决方案。
2.非input型上传
接下来难度要升级了,对于那些不是input框实现的上传怎么办,这种上传千奇百怪,有用a标签的,有用div的,有用button的,有用object的,我们没有办法通过直接在网页上处理掉这些上传,唯一的办法就是打开OS弹框,去处理弹框。
问题又来了,OS弹框涉及的层面已经不是selenium能解决的了,怎么办?很简单,用OS层面的操作去处理呗,到这里我们基本找到了问题的处理方法。
大体上有以下几种解决方案:
1.autoIT,借助外力,我们去调用其生成的au3或exe文件。
2.Python pywin32库,识别对话框句柄,进而操作
3.SendKeys库
4.keybd_event,跟3类似,不过是模拟按键,ctrl+a,ctrl+c, ctrl+v…
目前我只知道以上四种方法,有其他方法的请留言告诉我,让我学习一下。
我们依次看一下:
1. autoIT
关于autoIT上传以及参数化的方法我已经在另一篇博文中讲过了,请参见selenium之 autoit命令行参数 。这里不再赘述。
2.win32gui
废话不多说,上代码先:
예제 웹사이트: http://www.sahitest.com/demo/php/fileUpload.htm
代码:
# -*- coding: utf-8 -*- from selenium import webdriver import win32gui import win32con import time dr = webdriver.Firefox() dr.get('http://sahitest.com/demo/php/fileUpload.htm') upload = dr.find_element_by_id('file') upload.click() time.sleep(1) # win32gui dialog = win32gui.FindWindow('#32770', u'文件上传') # 对话框 ComboBoxEx32 = win32gui.FindWindowEx(dialog, 0, 'ComboBoxEx32', None) ComboBox = win32gui.FindWindowEx(ComboBoxEx32, 0, 'ComboBox', None) Edit = win32gui.FindWindowEx(ComboBox, 0, 'Edit', None) # 上面三句依次寻找对象,直到找到输入框Edit对象的句柄 button = win32gui.FindWindowEx(dialog, 0, 'Button', None) # 确定按钮Button win32gui.SendMessage(Edit, win32con.WM_SETTEXT, None, 'd:\\baidu.py') # 向输入框输入绝对地址 win32gui.SendMessage(dialog, win32con.WM_COMMAND, 1button) # 按button print upload.get_attribute('value') dr.quit()
결과:
baidu.py
在这里你需要一个非常重要的小工具:Spy++百度一下有很多,当然你也可以用autoIT内置的工具,不过没有这个好用,建议去下一个吧。
또한, pywin을 설치해야 합니다.32라이브러리를 찾을 수 있습니다. 그리고, pywin을 설치해야 합니다.에서Python 버전에 해당하는 라이브러리를 찾아야 합니다. 주의하세요32버전과 일치해야 합니다.64버전과 일치해야 합니다.
설치가 완료되면 [시작 메뉴 Python의 폴더]에서 PyWin32의 문서[Python for Windows 문서]에서 해당 메서드 API를 찾을 수 있습니다.
사용하는 몇 가지를 간단히 소개합니다:
win32gui.FindWindow(lpClassName=None, lpWindowName=None):
• 최상위 창에서 시작하여 일치하는 조건을 가진 창을 찾고 이 창의 핸들을 반환합니다.
• lpClassName: 클래스 이름, Spy++에서 볼 수 있습니다
• lpWindowName: 창 이름, 타이틀 바에 보이는 이름
• 코드 예제에서 업로드 창을 찾는 데 사용됩니다. 중 하나만 사용할 수 있으며, classname을 사용하면 다른 것들이 방해할 수 있지만, windowname을 사용하면 불안정할 수 있습니다. 다른 업로드 대화 상자의 window_name이 다를 수 있으며, 어떻게 정의할지는 상황에 따릅니다.
win32gui.FindWindowEx(hwndParent=0, hwndChildAfter=0, lpszClass=None, lpszWindow=None)
• 창 이름과 클래스 이름이 일치하는 창을 검색하고 이 창의 핸들을 반환합니다. 찾지 못하면 0을 반환합니다.
• hwndParent: 0이 아니면, hwndParent 창 핸들의 자식 창을 검색합니다.
• hwndChildAfter: 0이 아니면, z-index의 순서로 hwndChildAfter로부터 시작하여 자식 창을 찾습니다. 그렇지 않으면 첫 번째 자식 창에서 시작합니다.
• lpClassName: 문자형, 창의 클래스 이름입니다. 이는 Spy++에 찾습니다.
• lpWindowName: 문자형, 창 이름입니다. 즉, 타이틀 바에 보이는 제목입니다.
• 코드 예제에서 입력 필드와 확인 버튼을 계층적으로 찾는 데 사용됩니다
win32gui.SendMessage(hWnd, Msg, wParam, lParam)
• hWnd: 정수형, 메시지를 수신하는 창 핸들
• Msg: 정수형, 전송할 메시지, 이 메시지들은 모두 Windows가 사전에 정의한 것들로, 시스템 정의 메시지(시스템-정의된 메시지)
• wParam: 정수형, 메시지의 wParam 파라미터
• lParam: 정수형, 메시지의 lParam 파라미터
• 코드 예제에서 파일 주소를 입력하는 입력 필드와 확인 버튼을 클릭하는 데 사용됩니다
win에 대해서는}32api 모듈 및 다른 메서드에 대해 더 설명하지 않겠습니다. 알고 싶다면 자신의百度나 pywin을 통해 확인하세요.32문서。
3.SendKeys
먼저 SendKeys 라이브러리를 설치해야 합니다. pip을 사용하여 설치할 수 있습니다.
pip install SendKeys
코드 예제:
예제 웹사이트: http://www.sahitest.com/demo/php/fileUpload.htm
代码:
# -*- coding: utf-8 -*- from selenium import webdriver import win32gui import win32con import time dr = webdriver.Firefox() dr.get('http://sahitest.com/demo/php/fileUpload.htm') upload = dr.find_element_by_id('file') upload.click() time.sleep(1) # SendKeys SendKeys.SendKeys('D:\\baidu.py') # 파일 주소 보내기 SendKeys.SendKeys("{ENTER}") # 엔터 키 보내기 print upload.get_attribute('value') dr.quit()
결과:
baidu.py
SendKeys 라이브러리를 통해 포커스에 정보를 직접 입력할 수 있지만, 창을 엽니다. 열 때 약간의 대기 시간을 추가하면 첫 번째 글자가 send되지 않을 수 있습니다. (또는 주소 앞에 무용 문자를 추가할 수 있습니다.), 하지만 이 방법은 매우 불안정하며 권장하지 않습니다.
4.keybd_event
win32api는 keybd_event() 메서드를 제공하여 키를 모의할 수 있지만, 이 메서드는 복잡하며 불안정하므로 매우 권장하지 않습니다. 아래는 일부 코드 예제입니다. 더 공부하고 싶다면 자신의百度를 통해 배우세요.
# 원하는 파일 주소를 입력한 input 창을 찾아서, 클립보드에 복사 video.send_keys('C:\\Users\\Administrator\\Pictures\\04b20919fc78baf41fc993fd8ee2c5c9.jpg') video.send_keys(Keys.CONTROL, 'a') # selenium의 send_keys(ctrl+a) video.send_keys(Keys.CONTROL, 'x') # (ctrl+x) driver.find_element_by_id('uploadImage').click() # 업로드 버튼 클릭, 업로드 창 열기 # 붙여넣기(ctrl + v) win32api.keybd_event(17, 0, 0, 0) # 키 누르기 ctrl win32api.keybd_event(86, 0, 0, 0) # 키 누르기 v win32api.keybd_event(86, 0, win32con.KEYEVENTF_KEYUP, 0) # 키 떠놓기 v win32api.keybd_event(17, 0, win32con.KEYEVENTF_KEYUP, 0) # 升起按键 ctrl time.sleep(1) # 回车(enter) win32api.keybd_event(13, 0, 0, 0) # 按下按键 enter win32api.keybd_event(13, 0, win32con.KEYEVENTF_KEYUP, 0) # 升起按键 enter ...
是不是很麻烦,当然,你甚至可以用按键把整个路径输入进去,不过,我想没人愿意这么做的。而且在此过程中你不能随意移动鼠标,不能使用剪贴板,太不稳定了,所以非常不建议你用这种办法。。
3.多文件上传
接下来还有一种情况值得我们考虑,那就是多文件上传。如何上传多个文件,当然我们还是往输入框里输入文件路径,所以唯一要搞清楚的就是多文件上传时,文件路径是怎么写的。
我来告诉你吧,多文件上传就是在文件路径框里用引号括起单个路径,然后用逗号隔开多个路径,就是这么简单,例如:
"D:\a.txt" "D:\b.txt"
但需要注意的是:只有多个文件在同一路径下,才能这样用,否则是会失败的(下面的写法是不可以的):
"C:\a.txt" "D:\b.txt"
接下里找一个例子试试:
示例网址:http://www.sucaijiayuan.com/api/demo.php?url=/demo/20150128-1
代码:
# -*- coding: utf-8 -*- from selenium import webdriver import win32gui import win32con import time dr = webdriver.Firefox() dr.get('http://www.sucaijiayuan.com/api/demo.php?url=/demo/20150128-1) dr.switch_to.frame('iframe') # 一定要注意frame dr.find_element_by_class_name('filePicker').click() time.sleep(1) dialog = win32gui.FindWindow('#32770', None) ComboBoxEx32 = win32gui.FindWindowEx(dialog, 0, 'ComboBoxEx32', None) ComboBox = win32gui.FindWindowEx(ComboBoxEx32, 0, 'ComboBox', None) Edit = win32gui.FindWindowEx(ComboBox, 0, 'Edit', None) button = win32gui.FindWindowEx(dialog, 0, 'Button', None) # 위 예제의 코드와 같지만, 여기서 매개변수가 다릅니다. 원하시면 업로드 기능을 포장하는 업로드 함수를 작성할 수 있습니다 win32gui.SendMessage(Edit, win32con.WM_SETTEXT, 0, '"d:\\baidu.py" "d:\\upload.py" "d:\\1.html"') win32gui.SendMessage(dialog, win32con.WM_COMMAND, 1, button) print dr.find_element_by_id('status_info').text dr.quit()
결과:
선택3개 파일, 총1.17KB.
따라서, 다중 파일 업로드는 그리 복잡하지 않으며, 매우 간단합니다. 유일한 차이점은 매개변수가 다를 뿐입니다. autoIT도 구현할 수 있습니다. 관심이 있으시면 직접 시도해 보세요.
또한, 우리는 이 위 창의 코드가 이전 예제와 기본적으로 동일하다는 점을 발견할 수 있습니다. 따라서, 업로드 부분을 분리하여 함수를 작성할 수 있습니다. 이렇게 하면, 언제든지 업로드를 위해 함수를 호출하고, 매개변수를 전달할 수 있습니다.
보시면 알겠지만, 업로드는 매우 간단하게 처리할 수 있습니다.
이것이 본 문서의 전체 내용입니다. 여러분의 학습에 도움이 되길 바랍니다. 또한, 여러분의 지지와 응원을 많이 부탁드립니다.
선언: 본 문서의 내용은 인터넷에서 수집되었으며, 저작권은 원 저작자에게 있으며, 인터넷 사용자가 자발적으로 기여하고 업로드한 내용입니다. 이 웹사이트는 소유권을 가지지 않으며, 인공적으로 편집되지 않았으며, 관련 법적 책임을 부담하지 않습니다. 저작권 침해 내용을 발견하시면, notice#w로 이메일을 보내 주시기 바랍니다.3codebox.com(보내실 때, #을 @으로 변경하시오)를 통해 신고하시고, 관련 증거를 제공하시면, 확인되면 즉시 저작권 침해 내용을 제거할 것입니다。