最近在看python的爬虫框架(scrapy),一个词概括就是:"酸爽"!等把selenium自动化版块讲完后,打算写一写关于scrapy相关的知识,打算从源码角度解析下scrapy这个框架。我的想法是它不仅仅是用来爬网页的,更重要的是如何检测一个网站所有页面的健康性...回到正题,我想讲讲这个话题的起因是同事在自动化过程中遇到了flash的点击操作,查阅网上的相关资料也得不到有效解决。今天我想想谈谈这个flash的自动化操作问题!!
随着页面做的越来越炫酷,flash被越来越多的嵌入到html网页中。但是往往由于对flash的简单操作,却阻断了我们整个自动化的测试过程!selenium目前的版本是3.0了对flash操作仍然没有提出解决方案。其实我觉得,不是selenium不作为,而是它无能为力!!为什么这么说呢?我们知道flash是as语言开发的,我们想在网页中操作flash,那么就必须通过js这个媒介来操作,问题是:开发有没有开放操作flash的js接口?我们知道js如果要调用as,那么as源码中必须使用ExternalInterface.addCallback函数,把as的接口绑定给js,这样的话我们可以轻松的调用js以达到控制flash的目的...我们搜索selenium对flash的解决方案:99.99%都是向flex工程注入SeleniumFlexAPI.swc,然后通过调用js的接口来控制flash。
对于一些IT基础比较薄弱的同学来说,始终不知道如何按照网上的步骤来进行下去,这里我对这个方案做个简单的解释如下:
1.这个是需要原flash工程的,不是你得到的一个简单的swf文件就能重新编译的。简单的说就是找你们开发吧,让他把SeleniumFlexAPI.swc加入到被操作Flash(Flex)的工程文件的Build库中,重新Build Flash,然后重新发布到web上。这样你对这个新的flash可能用js进行操作了。
2.SeleniumFlexAPI.swc这个文件以及好久好久没更新了...不知道是否对现在的flash能否操作有效,所以我在1中用了可能。
3.我总觉得这个方法有点脱裤子放屁的感觉,既然找开发帮你引入SeleniumFlexAPI.swc这个文件,还不如给你直接开放js接口,不是更好?
吐槽了网上的方法,来说说站在一个测试者角度的解决方案!
一、利用AutoIt
从某种意义上来说,我有点对这个工具产生依赖。当我在自动化过程中绝望的时候,我就会第一时间想到它,而它也往往能带给我惊喜,就像上篇用fiddler录制接口一样(其实还有很多..)!来说说我用这个工具来操作flash。我所操作的Flash图片如下:
这个Flash是有动画效果的,经过一段动画后出现上面图片的效果。我的任务就是点击上面图片中的小鼠标。下面贴出来AutoIt的脚本(最终转换成exe程序,在控制台中执行):
#include <MsgBoxConstants.au3> Example() Func Example() Local $win = WinWait("[CLASS:MozillaWindowClass;Title:Mozilla Firefox]","",10) WinActivate($win);激活当前窗口 $pos =WinGetPos($win) $high=$pos[3];表示窗口的的实际高度 $weight=$pos[2];表示窗口的实际宽度 $click_x=970*$weight/1382;970表示我在当前电脑分辨率宽度为1382下的X坐标值 $click_y=540*$high/744;744表示我再当前电脑分辨率高度为744下的Y坐标值 $num=1 While 1 $icolor=PixelGetColor($click_x,$click_y) If $icolor==6671717 Or $icolor==1321236 Or $num==5 Then ExitLoop EndIf Sleep(2000) $num=$num+1 WEnd MouseClick("left",$click_x,$click_y,1) EndFunc ;
需要注意的是,由于Firefox中嵌入的flash是非windows标准控件,我们只能用相对坐标来点击。关于以上坐标值得获取,依然用Autoit windows info这个工具获取如下:
而我们当前电脑分辨率下,取得的整个控件的大小信息如下:
上面脚本很简单很简单,你应该明白我什么意思。还有一点说明的就是上面标红的部分。我说过了我的flash是个动画,经过大概5-6后会出现这个小鼠标。那么我们在autoit中如果动态的判断这个小鼠标出现了呢?当然你可以在脚本中Sleep(10000)等待10S钟。但是我觉得这样不太好,我的做法是:在一个循环中实时的取得我所点击区域的颜色值用PixelGetColor这个函数取得(返回的是一个十进制的值)。当我们等待的这个控件出现时,即该区域的颜色值等于某个值时,跳出这个循环,然后对这个控件用坐标进行点击!这个color的值我在第二张中也圈出了,这是个16进制的值,转换成10进制即可!上面的脚本我在2台不同的分辨率大小的电脑上测试过,基本能运行成功!!但是用autoit操作flash也是有一点的缺点。最大的缺点就是相对坐标计算的准确性!不过一般我觉得是没问题的。
上面第一种方案是通过autoit操作flash点击的,当然autoit也可以模拟其他我们人为的操作,比如在输入框中输入、双击某个按钮等...注意的是,对于非标准控件你要尽可能的保证相对坐标计算的准确性!
二、利用Sikuli
这个工具也是个神器,关于他的介绍我不多说了,他的原理大概就是:在当前可视窗口中,寻找与你截图相同的区域,然后操作该区域的中心点坐标。说下他的安装和用法。
1.安装
一般的安装教程网上有(https://launchpad.net/sikuli/+download这上面有全部的sikuli包信息)我的补充如下:
第一、最新的下载地址为: Sikuli-X-1.0rc3 (r905)-win32.exe 。这个应用只有32位的,在32位系统上安装运行应该都没有问题(需要32位jre6之前的环境)。
第二、如果你对这个较为熟悉不需要IDE,你可以仅仅下载 Sikuli-X-1.0rc3 (r905)-win32.zip
第三、如果你非要在64位系统上安装sikuli的IDE,直接运行 Sikuli-X-1.0rc3 (r905)-win32.exe无视弹出的错误信息,不过最终要运行在32位的jre6环境下。
对于32位系统的要注意jre最好是在jre6(包括)之前的,免得可能会出现闪退的情况。对于64位系统的要保证其运行在32位的jre6下!可能有的同学不高兴了,我这已经搭建好了java环境,难不成要卸载了,重新装个32位的开发环境?答案是否定的。我们系统上可以运行多个版本的java环境。我们要做的只是保证其运行环境是32位的jre6就可以了。为了避免你在oracel官网上对jre6进行寻找,我直接给出连接:http://www.oracle.com/technetwork/java/javase/downloads/java-archive-downloads-javase6-419409.html#jre-6u35-oth-JPR这个是jre6第35次编译的,注意的是:你仅仅需要下载运行环境,不需要下载开发环境。也不需要重新配置环境变量之类的操作,你需要的仅仅是更改安装目录下的Sikuli-IDE-w.bat这个dos脚本,将其中JAVA_EXE指向你新安装的32位jre6的安装目录。
说了这么多你应该明白了环境搭建方面的问题,当然如果有任何问题,你可以留言!下面说说这个脚本的编写,首先我们说说java环境下如何用这个脚本来操作flash;再看看如何在python中如何利用sikuli操作flash。在java中你需要干三件事:
1.将sikuli安装目录下的libs文件夹放在系统的环境变量中。
2.将eclipse的运行环境设置为32位jre。(不一定jre6只要32位jre就行。上文sikuli IDE需要jre6的原因是这个IDE应该是在jdk6下开发的,而我们这里只是在eclipse运行sikuli-script.jar包中的相关方法)。
3.引入sikuli-script.jar包
简单的java测试代码如下:
/** * */ /** * @author PF-211X3 * */ package com; import org.sikuli.script.*; public class STest { public static void main(String[] args) throws FindFailed, InterruptedException { Screen s = new Screen(); String imgpath = "D:/img/";
s.wait(imgpath+"firfox.png", 5); s.doubleClick(imgpath+"firfox.png"); System.out.println("end"); } }
这个firfox.png就是我们用任何截图工具截取桌面上firefox快捷图标的照片。上面的操作就可以点击桌面上的firefox快捷图标打开火狐浏览器了。是不是很神奇!!所以我上文说了其实不需要安装sikuli的IDE。只需要sikuli-script.jar包与libs文件下的内容即可,相关的函数的用法你完全可以猜出来不行看看文档介绍!当然你想安装个IDE玩玩也是可以的~~
对于1没问题吧,添加环境变量大家都会。对于只会python完全没有接触过java的同事我给出2,3的步骤,java同学跳过!(我的pc是64位的,且我也已经下载好了32位的jre6的环境。)
如何将eclipse以32位的jre6运行该工程?
一、打开eclipse菜单window-》preferences弹出框,在左边的树形图找到java选项点开后选择Installed JRES在右边的选择框中选择Add添加我们32位jre我的截图如下:
上图大箭头部分是我们新安装的32位jre路径,我们选择改jre并点击Apply。
二、右键点击工程选择Build Path下的子菜单项Add Libraies...添加我们选择的jre
选择我们JRE System library-next->Workspace default JRE(jire6)点击Finish。
3.考虑运行的兼容性(不同版本的jdk与jre配合需要此配置,相同版本的不需要),右击该工程选择菜单项Project->Properties。在弹出框中做一下配置:
如何添加外部包?
选中该工程右键点击该工程选择Build Path->Add External Archives...后导入本地目录下的sikuli-script.jar即可
上面我们从sikuli角度来操作flash。总结下这种解决方案遇到的坑和注意点。
1.32系统上sikuli的环境搭建是问题不大的,除了sikuli ide的运行环境需要配置成jre6。64位系统上有点坑。上文中我也较详细的说明了ide的配置以及如何在eclipse中运行sikuli脚本,我相信你肯定能运行起来。
2.注意点:sikuli对我们截图的匹配查找是在我们当前可视范围内的。这句话怎么理解呢?比如上文中我在桌面上截了一个firefox快捷图标的图片,当运行到点击这个快捷图标时,突然弹出了一段小广告挡住了这个快捷图标,那么我们的sikuli是找不到该图片的。我的解决办法是在运行sikuli脚本之前,最好先运行下AutoIt的一个小脚本,就是上文中我们频繁使用到的WinActivate($hWnd)函数,可以确保某个窗口控件是可视的。
说到这来java部分也就这样了,但是本篇还没有结束,因为我们还没有讲python中如何使用sikuli-script.jar这个包!
sikuli-script.jar是java下的包,python使用java的包最先想到的就是jpython。但是就为了操作个flash把python解析器设置为jpython我认为没人能接受。那么有一种神器可以连接python与java还能保证你的运行环境是cpython的,那这个包就是jpype。
对于32位系统,安装这个是最简单的你可以下载jpype.exe程序直接安装。jpype.exe暂时是没有64位,我们选择安装包安装。路径为:https://pypi.python.org/pypi/JPype1。我们下载后运行python setup.py install。发现可能是有问题的,原因是在windows平台上无法安装python c extension的扩展包,我们下载专用的编译器Microsoft Visual C++ Compiler for Python 2.7就好了下载地址:https://www.microsoft.com/en-us/download/details.aspx?id=44266。
对于jpype的使用也是非常简单的,对于32位系统操作sikuli-script.jar这个包太简单就几行代码:
#coding=utf-8
import jpype
jvmPath = jpype.getDefaultJVMPath()
jpype.startJVM(jvmPath,"-ea",r"-Djava.class.path=D:\\tutorial\\tutorial\spiders\sikuli-script.jar")#jvmPath为jvm.dll的路径可以人为指定并指定外部包的加载路径
JDClass =jpype.JClass("org.sikuli.script.Screen")
s=JDClass()
imgpath = "D:/img/"
s.wait(imgpath + "firfox.png", 5)
s.doubleClick(imgpath + "firfox.png");
jpype.shutdownJVM()
这段代码与我们上文的java代码意义是一样。为什么说对于32位是没有问题的,难道64位python解析器无法这样用吗?
首先,并不是说64位解析器无法通过jpype来启动一个虚拟机,但是问题是我们只能启动一个64位的jvm。但是我们上文说了sikuli-script.jar这个包无法在64位的jre中运行的,我们尝试通过手动给出32位jre下面jvm.dll的路径来启用JVM进而运行sikuli-script.jar这个包。我的尝试代码:
#coding=utf-8
import jpype
jpype.startJVM(r"C:\Program Files (x86)\Java\jre6\bin\client\jvm.dll","-ea",r"-Djava.class.path=D:\\tutorial\\tutorial\spiders\sikuli-script.jar")#jvmPath为32位jre的jvm.dll路径
JDClass =jpype.JClass("org.sikuli.script.Screen")
s=JDClass()
imgpath = "D:/img/"
s.wait(imgpath + "firfox.png", 5)
s.doubleClick(imgpath + "firfox.png");
jpype.shutdownJVM()
发现是无法启动jvm的,原因可能很简单我们在64位的python解析器上运行32位jvm.dll多少有点问题。那么我们在64位上如何使用sikuli呢?没办法我能想到的就只有曲线救国了...对的,就是用python调用控制台来运eclipse里的工程。我的做法如下:
1.导出该工程为jar包。
步骤:选择该工程选择菜单的File->Export,选择JAR File,然后一路向西导出到某个路径下,我直接放桌面了。
2.修改改jar包中的MANIFEST.MF文件。
步骤一、修改改jar包后缀名为zip。比如将abc.jar变成abc.zip
步骤二、修改里面的META-INF中的MANIFEST.MF文件,添加Main-Class: com.STest
步骤三、保存后修改abc.zip为abc.jar
3.修改完jar包后我们直接编写运行这个jar的dos脚本如下:
cmd命令:"C:\Program Files (x86)\Java\jre6\\bin\java" -Djava.ext.dirs=C:\lib -jar C:\Users\PF-211X3\Desktop\\abc.jar
这个简单的说明吧!
一、C:\Program Files (x86)\Java\jre6\\bin\java是我们32位jre的路径下java命令
二、-Djava.ext.dirs命令参数如同jpype中的参数-Djava.class.path一样为我们外部引用包,我这里是把sikuli-script.jar这个包放在C盘的lib下的
三、-jar参数后面跟的是我们刚修改过的jar包
以上只是个例子,具体路径配置按自己个人情况界定。
我们发现在个在cmd中是能正常运行的,那么我们如何在python中运行这个我相信,不需要我多说了吧
import os
cmd="\"C:\Program Files (x86)\Java\jre6\\bin\java\" -Djava.ext.dirs=C:\lib -jar C:\Users\PF-211X3\Desktop\\abc.jar"
os.popen(cmd)
好吧,我们总算通过曲线救国的方式使得python在64系统上用sikuli操作flash。在32位上还是用jpype吧!
最后我们做个简单的总结吧:
我们上面使用Autoit与sikuli方法操作flash,2种方法各有特色吧!当然可能还有其他更好更方便的方法操作flash,希望知道的大神们能写出来~~