做ui自动化遇到文件上传的问题,a、div、button、object等等其他类型的页面元素,没有办法通过selenium直接在网页上处理掉这些上传,需要打开windows的系统弹框,去处理弹框。
使用python的pywin32模块处理这种系统页,需要辅助的工具spy++方便查找窗口信息。
spy++可以枚举所有窗口,查看父子关系,搜索某个窗口是否存在;点各位一个窗口(包括隐藏窗口)的属性,包括标题、类名、位置、进程线程 。
经过定位,我们找到浏览器的打开窗口,结构如下:
窗口的详细信息如下:
主要用到的信息:
window caption:窗口名称(不是每个窗口都有)
window handle:窗口句柄(每个窗口都有,spy++显示的是十六进制的句柄,唯一)
class name:窗体类名(每个窗口都有,但不唯一)
定位到窗口后,分析窗体结构和信息,代码如下,然后代码就可以在selenium脚本中调用了。
import win32api import win32gui import win32con import time #获取所有子窗口句柄并根据类名进行匹配,找到符合条件的句柄并返回 def get_child_window(winparent,classname,winname): if not winparent: return hwndChildList = [] #获取所有窗口 win32gui.EnumChildWindows( winparent, lambda hwnd, param: param.append(hwnd), hwndChildList) handle=0 #窗口匹配 for i in hwndChildList: if win32gui.GetClassName(i)==classname and win32gui.GetWindowText(i)==winname: handle=i return handle #点击指定句柄的窗口 def window_click(windowname): if windowname: #获取目标窗口的地址 tuple=win32gui.GetWindowRect(windowname) #计算点击位置 x=int(tuple[0]+(tuple[2]-tuple[0])/2) y=int(tuple[1]+(tuple[3]-tuple[1])/2) win32api.SetCursorPos([x,y]) #鼠标左键点击操作 win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN, 0, 0) time.sleep(1) #模拟鼠标左键放开 win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP, 0, 0) #点击指定位置 def win_point_click(x,y): win32api.SetCursorPos([x,y]) #鼠标左键点击操作 win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN, 0, 0) time.sleep(1) # 模拟鼠标左键放开 win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP, 0, 0) #找到总窗口 win = win32gui.FindWindow('#32770',u'打开') #窗口返回值是十进制,如果要跟spy++核对,最好转换成16进制 print("定位到的总窗口句柄",hex(win)) #win的下层子窗口 downwin=win32gui.FindWindowEx(win,0,'DUIViewWndClassName',None) print("tid3的句柄是",hex(downwin)) #获取最终层子窗口 childwin=get_child_window(downwin,'DirectUIHWND','') #获取需要导入的文件的位置 print("获取当前的鼠标位置",win32gui.GetCursorPos()) #点击窗体位置 win_point_click(2920,323) #定位到按钮的窗口 buttonwin=get_child_window(win,'Button','打开(&O)') #点击确认按钮位置 window_click(buttonwin)
Pywin32提供了很多访问windows的API。较重要的三个模块就是win32api、win32gui和win32con。
自动化界面用的是gui。这个模块内定义了一些有关图形操作的API。
win32api模块内定义了常用的一些API函数。
win32con,这个模块内定义了windows API内的宏。
主要方法:
win32gui.FindWindow(classname,text)
返回pyhandle windows窗体句柄,int 类型
className 窗体类名
text 窗体标题
FindWindowEx(Parent, ChildAfter , ClassName , WindowName)
通过父pyhandle窗体句柄找到第一个子窗体或控件。注意,这里只找直接子窗体,不会找子窗体的下级子窗体。
ChildAfer int类型,为0表示搜索所有
ClassName str类型,为None则搜索所有
WindowName str类型,为None则搜索所有
left,top,right,bottom=win32gui.GetClientRect(pyhandle)
得到窗体的左,顶,右 ,底的坐标
win32api.SetCursorPos([width, height])
设置鼠标在屏幕中的坐标