• ruby+watirwatir3.0上实现快照/截图


    我想在watir框架运行时,在出现错误“FAIL”状态前建立一个快照,就想到了watir的截图功能,在网上找了一些例子(参考:http://www.cnblogs.com/sky_online/archive/2009/12/13/1546252.html),但是不好使,提示“Win32API”的错误。

    环境:Ruby192+watir3.0.0

    gem list信息如下:

    gem list
    Microsoft Windows XP [版本 5.1.2600]
    (C) 版权所有 1985-2001 Microsoft Corp.
    C:\Documents and Settings\Administrator>gem list
    *** LOCAL GEMS ***
    addressable (2.2.8)
    builder (3.0.0)
    childprocess (0.3.2)
    commonwatir (3.0.0)
    cucumber (1.2.1)
    diff-lcs (1.1.3)
    ffi (1.0.11)
    gherkin (2.11.1)
    hoe (3.0.6)
    json (1.7.3)
    libwebsocket (0.1.3)
    mini_magick (3.2.1)
    minitest (1.6.0)
    multi_json (1.3.4)
    nokogiri (1.5.3 x86-mingw32)
    rake (0.8.7)
    rautomation (0.7.2)
    rdoc (2.5.8)
    rubygems-update (1.8.24)
    rubyzip (0.9.8)
    s4t-utils (1.0.4)
    selenium-webdriver (2.25.0, 2.21.2)
    subexec (0.0.4)
    user-choices (1.1.6.1)
    watir (3.0.0)
    watir-classic (3.0.0)
    watir-webdriver (0.6.1)
    watir-webdriver-performance (0.1.3.1)
    win32-api (1.4.8)
    win32-process (0.6.5)
    windows-api (0.4.1)
    windows-pr (1.2.1)
    xml-simple (1.1.1)
    C:\Documents and Settings\Administrator>

    这个LibScreen.rb的例子适合在watir1.6.5版本的,有高手试验过。直接运行LibScreen.rb例子的话,会出现的错误,请过森破的深入分析,需要把脚本中的vkKeyScan.Call()中带问号的修改一下就可以,如下:所有带问号?的都要修改一遍,否则。。

    vkKeyScan.Call(?V)
    替换成
    vkKeyScan.Call("V".getbyte(0))

    ?V输出的是ASCII 86(在低版本中),那在我的高版本中显示的是V,这就是高版本和低版本的区别。

    经过验证,本地保存快照成功。并对LibScreen.rb的例子进行了功能扩展:可以保存.jpg、.bmp、.png、.gif格式的文件;有人说图片比较占用磁盘空间,在脚本中把另存为默认成PNG格式的文件(虽然和保存的格式对不上),因为占用空间小,针对这个我还专门做了对比:

    LibScreen.rb
    class ScreenClass
    def initialize
    require "Win32API"
    end
    #功能说明:
    #- 将文件重命名
    #
     #参数说明:
    #- from:原文件路径,必须带文件名,格式如:c:\\test.txt
    #- to:新文件路径及名称,必须带文件名,格式如:c:\\test_bak.txt,不带该参数时,默认在原文件名后加上日期
    #
     #调用示例: 
    #- $TxtClass.RenameFile("c:\\test.txt","c:\\test_bak.txt")
    #- $TxtClass.RenameFile("c:\\test.txt")
    #
     #返回值说明:
    #- 成功:返回true
    #- 失败:返回false
    def RenameFile(from,to = nil)
    begin
    if (FileTest::exist?(from)) and (File.basename(from) =~ /.*\..*/ )
    if (to == nil)
    extname = File.extname(from)
    filename = File.basename(from,extname)
    new_filename = filename + '.' + Time.now.strftime("%Y%m%d%H%M%S") + extname
    to = File.dirname(from) + '/'+ new_filename
    end
    File.rename(from, to)
    return true
    else
    puts "重命名文件失败,原因:文件不存在,路径为#{from}"
    return false
    end
    rescue StandardError => bang
    puts "Error running script: " + bang
    return false
    end
    end
    #功能说明:
    #- 获取文件的真实路径
    #
     #参数说明:
    #- file_path:原文件路径,如果原文件路径不存在,系统自动创建相应路径
    #- return_file:是否返回路径中的文件名,默认未返回
    #
     #调用示例: 
    #- $TxtClass.GetRealPath("#{File.dirname(__FILE__)}/http://www.cnblogs.com/input/data.xls" )
    #
     #返回值说明:
    #- 成功:返回真实的路径
    #- 失败:返回false
    def GetRealPath(file_path,return_file = 'Y')
    begin
    @@file_name = ''
    @@real_dir_row = []
    if (file_path.include?("\\"))
    file_path = file_path.to_s.gsub('\\','/')
    end
    if (file_path.include?("/"))
    file_basename = File.basename(file_path) #获取文件名
    file_dirname = File.dirname(file_path)
    if (file_basename =~ /.*\..*/)
    file_dirname = File.dirname(file_path)
    else
    file_basename = ''
    file_dirname = file_path
    end
    if (!FileTest::exist?(file_dirname)) #判断目录是否存在,不存在则创建相应目录
     FileUtils.makedirs(file_dirname)
    end
    if (file_dirname[0,2] == './')
    real_dir = Pathname.new(File.dirname(File.dirname(file_dirname[0,2]))).realpath
    real_path = File.join(real_dir,file_dirname[2,file_dirname.length] )
    else
    real_path = file_dirname
    end
    if (real_path.include?(".."))
    temp_row = real_path.split('/')
    temp_row.each do |dir|
    if(dir == "..")
    @@real_dir_row.pop
    else
    @@real_dir_row.push(dir)
    end
    end
    real_path = @@real_dir_row.join('/')
    end
    if (return_file.upcase == 'Y')
    result = File.join(real_path,file_basename)
    else
    result = real_path
    end
    result = result.to_s.gsub('/','\\')
    return result
    else
    puts "获取文件路径失败,原因:#{real_path}路径格式不正确。"
    return false
    end
    rescue StandardError => bang
    puts "Error running script: " + bang
    return false
    end
    end #def GetRealPath
    def ScreenCapture(file_path , active_window_only=false, save_as_bmp=false)
    keybd_event = Win32API.new("user32", "keybd_event", ['I','I','L','L'], 'V')
    vkKeyScan = Win32API.new("user32", "VkKeyScan", ['I'], 'I')
    winExec = Win32API.new("kernel32", "WinExec", ['P','L'], 'L')
    openClipboard = Win32API.new("user32", "OpenClipboard", ['L'], 'I')
    setClipboardData = Win32API.new("user32", "SetClipboardData", ['I', 'I'], 'I')
    closeClipboard = Win32API.new("user32", "CloseClipboard", [], 'I')
    globalAlloc = Win32API.new("kernel32", "GlobalAlloc", ['I', 'I'], 'I')
    globalLock = Win32API.new("kernel32", "GlobalLock", ['I'], 'I')
    globalUnlock = Win32API.new("kernel32", "GlobalUnlock", ['I'], 'I')
    memcpy = Win32API.new("msvcrt", "memcpy", ['I', 'P', 'I'], 'I')
    file_basename = File.basename(file_path) #获取文件名
    if(file_basename.upcase =~ /.*.(JPG|BMP|PNG|GIF)/)
    real_file_path = GetRealPath(file_path) #获取文件的真实路径
    if (FileTest::exist?(real_file_path))
    RenameFile(real_file_path)
    end
    if active_window_only ==false
    keybd_event.Call(0x2C,0,0,0) # Print Screen
    else
    keybd_event.Call(0x2C,1,0,0) # Alt+Print Screen
     end
    winExec.Call('mspaint.exe', 5)
    sleep(1)
    # Ctrl + V : Paste
    keybd_event.Call(0x11, 1, 0, 0)
    keybd_event.Call(vkKeyScan.Call("V".getbyte(0)), 1, 0, 0)
    keybd_event.Call(vkKeyScan.Call("V".getbyte(0)), 1, 0X2, 0)
    keybd_event.Call(0x11, 1, 0X2, 0)
    # Alt F + A : Save As
    keybd_event.Call(0x12, 1, 0, 0)
    keybd_event.Call(vkKeyScan.Call("F".getbyte(0)), 1, 0, 0)
    keybd_event.Call(vkKeyScan.Call("F".getbyte(0)), 1, 0X2, 0)
    keybd_event.Call(0x12, 1, 0X2, 0)
    keybd_event.Call(vkKeyScan.Call("A".getbyte(0)), 1, 0, 0)
    keybd_event.Call(vkKeyScan.Call("A".getbyte(0)), 1, 0X2, 0)
    sleep(1)
    # copy filename to clipboard 复制
    hmem = globalAlloc.Call(0X0002, real_file_path.length+1)
    mem = globalLock.Call(hmem)
    memcpy.Call(mem, real_file_path, real_file_path.length+1)
    globalUnlock.Call(hmem)
    openClipboard.Call(0)
    setClipboardData.Call(1, hmem)
    closeClipboard.Call
    sleep(1)
    # Ctrl + V : Paste粘贴
    keybd_event.Call(0x11, 1, 0, 0)
    keybd_event.Call(vkKeyScan.Call("V".getbyte(0)), 1, 0, 0)
    keybd_event.Call(vkKeyScan.Call("V".getbyte(0)), 1, 0X2, 0)
    keybd_event.Call(0x11, 1, 0X2, 0)
    #快照另存为
    if save_as_bmp == false
    # goto the combo box
    keybd_event.Call(0x09, 1, 0, 0)
    keybd_event.Call(0x09, 1, 0X2, 0)
    sleep(0.5)
    # select the first entry with J 选择另存为的类型,这里以png格式为例,如果另存为gif格式在保存时会提示“失真的信息”
    keybd_event.Call(vkKeyScan.Call("P".getbyte(0)), 1, 0, 0)
    keybd_event.Call(vkKeyScan.Call("P".getbyte(0)), 1, 0X2, 0)
    sleep(0.5)
    end
    # Enter key
    keybd_event.Call(0x0D, 1, 0, 0)
    keybd_event.Call(0x0D, 1, 0X2, 0)
    sleep(1)
    # Alt + F4 : Exit
    keybd_event.Call(0x12, 1, 0, 0)
    keybd_event.Call(0x73, 1, 0, 0)
    keybd_event.Call(0x73, 1, 0X2, 0)
    keybd_event.Call(0x12, 1, 0X2, 0)
    sleep(1)
    puts "快照保存的路径为:#{real_file_path}"
    return true
    else
    puts "保存的文件扩展名不正确,路径必须带文件名且文件扩展名必须为.jpg、.bmp、.png、.gif"
    return false
    end
    end # def ScreenCapture end
    end #class ScreenClass end

    验证:

    require "watir"
    require "LibScreen.rb"
    def test
    ie = Watir::IE.new
    ie.goto("http://www.baidu.com")
    #初始对象
    i = ScreenClass.new
    #截取整个屏幕
    #i.ScreenCapture("c:\\test1.png")
    #截取当前激活的窗口
    i.ScreenCapture("c:\\test1.png",true,false)
    end

    另外watir还有自带的截图工具,路径Ruby\lib\ruby\gems\1.9.1\gems\watir-classic-3.0.0\lib\watir-classic\screen_capture.rb,一样还是需要把所有带问号?的都要修改一遍。这个自带的我们可以直接引用:

    require 'watir-classic/screen_capture'
    include Watir::ScreenCapture
    def test
    ie = Watir::IE.new
    ie.goto("http://www.baidu.com")
    screen_capture("c:\\123111.jpg",true,false)
    end

    算啦 我把自带的screen_capture.rb代码沾上来吧,我已经修改过啦,可以参考:

    screen_capture.rb
    require 'Win32API'
    module Watir
    module ScreenCapture
    KEYEVENTF_KEYUP = 0x2
    SW_HIDE = 0
    SW_SHOW = 5
    SW_SHOWNORMAL = 1
    VK_CONTROL = 0x11
    VK_F4 = 0x73
    VK_MENU = 0x12
    VK_RETURN = 0x0D
    VK_SHIFT = 0x10
    VK_SNAPSHOT = 0x2C
    VK_TAB = 0x09
    GMEM_MOVEABLE = 0x0002
    CF_TEXT = 1
    # this method saves the current window or whole screen as either a bitmap or a jpeg
    # It uses paint to save the file, so will barf if a duplicate filename is selected, or the path doesnt exist etc
    # * filename - string - the name of the file to save. If its not fully qualified the current directory is used
    # * active_window - boolean - if true, the whole screen is captured, if false, just the active window is captured
    # * save_as_bmp - boolean - if true saves the file as a bitmap, saves it as a jpeg otherwise
    def screen_capture(filename , active_window_only=false, save_as_bmp=false)
    keybd_event = Win32API.new("user32", "keybd_event", ['I','I','L','L'], 'V')
    vkKeyScan = Win32API.new("user32", "VkKeyScan", ['I'], 'I')
    winExec = Win32API.new("kernel32", "WinExec", ['P','L'], 'L')
    openClipboard = Win32API.new('user32', 'OpenClipboard', ['L'], 'I')
    setClipboardData = Win32API.new('user32', 'SetClipboardData', ['I', 'I'], 'I')
    closeClipboard = Win32API.new('user32', 'CloseClipboard', [], 'I')
    globalAlloc = Win32API.new('kernel32', 'GlobalAlloc', ['I', 'I'], 'I')
    globalLock = Win32API.new('kernel32', 'GlobalLock', ['I'], 'I')
    globalUnlock = Win32API.new('kernel32', 'GlobalUnlock', ['I'], 'I')
    memcpy = Win32API.new('msvcrt', 'memcpy', ['I', 'P', 'I'], 'I')
    filename = Dir.getwd.tr('/','\\') + '\\' + filename unless filename.index('\\')
    if active_window_only ==false
    keybd_event.Call(VK_SNAPSHOT,0,0,0) # Print Screen
    else
    keybd_event.Call(VK_SNAPSHOT,1,0,0) # Alt+Print Screen
     end
    winExec.Call('mspaint.exe', SW_SHOW)
    sleep(1)
    # Ctrl + V : Paste
    keybd_event.Call(VK_CONTROL, 1, 0, 0)
    keybd_event.Call(vkKeyScan.Call("V".getbyte(0)), 1, 0, 0)
    keybd_event.Call(vkKeyScan.Call("V".getbyte(0)), 1, KEYEVENTF_KEYUP, 0)
    keybd_event.Call(VK_CONTROL, 1, KEYEVENTF_KEYUP, 0)
    # Alt F + A : Save As
    keybd_event.Call(VK_MENU, 1, 0, 0)
    keybd_event.Call(vkKeyScan.Call("F".getbyte(0)), 1, 0, 0)
    keybd_event.Call(vkKeyScan.Call("F".getbyte(0)), 1, KEYEVENTF_KEYUP, 0)
    keybd_event.Call(VK_MENU, 1, KEYEVENTF_KEYUP, 0)
    keybd_event.Call(vkKeyScan.Call("A".getbyte(0)), 1, 0, 0)
    keybd_event.Call(vkKeyScan.Call("A".getbyte(0)), 1, KEYEVENTF_KEYUP, 0)
    sleep(1)
    # copy filename to clipboard
    hmem = globalAlloc.Call(GMEM_MOVEABLE, filename.length+1)
    mem = globalLock.Call(hmem)
    memcpy.Call(mem, filename, filename.length+1)
    globalUnlock.Call(hmem)
    openClipboard.Call(0)
    setClipboardData.Call(CF_TEXT, hmem)
    closeClipboard.Call
    sleep(1)
    # Ctrl + V : Paste
    keybd_event.Call(VK_CONTROL, 1, 0, 0)
    keybd_event.Call(vkKeyScan.Call("V".getbyte(0)), 1, 0, 0)
    keybd_event.Call(vkKeyScan.Call("V".getbyte(0)), 1, KEYEVENTF_KEYUP, 0)
    keybd_event.Call(VK_CONTROL, 1, KEYEVENTF_KEYUP, 0)
    if save_as_bmp == false
    # goto the combo box
    keybd_event.Call(VK_TAB, 1, 0, 0)
    keybd_event.Call(VK_TAB, 1, KEYEVENTF_KEYUP, 0)
    sleep(0.5)
    # select the first entry with J
    keybd_event.Call(vkKeyScan.Call("J".getbyte(0)), 1, 0, 0)
    keybd_event.Call(vkKeyScan.Call("J".getbyte(0)), 1, KEYEVENTF_KEYUP, 0)
    sleep(0.5)
    end
    # Enter key
    keybd_event.Call(VK_RETURN, 1, 0, 0)
    keybd_event.Call(VK_RETURN, 1, KEYEVENTF_KEYUP, 0)
    sleep(1)
    # Alt + F4 : Exit
    keybd_event.Call(VK_MENU, 1, 0, 0)
    keybd_event.Call(VK_F4, 1, 0, 0)
    keybd_event.Call(VK_F4, 1, KEYEVENTF_KEYUP, 0)
    keybd_event.Call(VK_MENU, 1, KEYEVENTF_KEYUP, 0)
    sleep(1)
    end
    end
    end
  • 相关阅读:
    利用vbs设置Java环境变量
    svg translate 操作
    JSTL详解(二)
    [Oracle]
    怎样搭建轻量级架构-设计原则
    数据结构--队列
    opencv中各种矩阵乘的差别
    多重背包
    Linux管理员必须知道的sudo命令
    大二上學期學習生活總結
  • 原文地址:https://www.cnblogs.com/zhuque/p/2801763.html
Copyright © 2020-2023  润新知