Selenium研究之路

1.htmlunit

    动态页面问题:最开始遇到的是获取不到完整的页面代码,然后就知道用htmlunit,他可以支持在你获取页面代码前先执行js,但我试过了编程很不友好,就是没有效果

WebClient webClient= newWebClient(BrowserVersion.CHROME);//设置浏览器
LogFactory.getFactory().setAttribute("org.apache.commons.logging.Log","org.apache.commons.logging.impl.NoOpLog");       
java.util.logging.Logger.getLogger("com.gargoylesoftware.htmlunit").setLevel(Level.OFF);   
java.util.logging.Logger.getLogger("org.apache.commons.httpclient").setLevel(Level.OFF);//这三行是用来去掉警告 
webClient.getOptions().setUseInsecureSSL(true);//支持https
webClient.getOptions().setCssEnabled(false);//设置css是否生效
webClient.getOptions().setJavaScriptEnabled(true);//设置js是否生效
webClient.getOptions().setRedirectEnabled(true);
webClient.getOptions().setThrowExceptionOnScriptError(false);//当JS执行出错的时候是否抛出异常, 这里选择不需要
webClient.getOptions().setThrowExceptionOnFailingStatusCode(false);//当HTTP的状态非200时是否抛出异常, 这里选择不需要
webClient.setAjaxController(newNicelyResynchronizingAjaxController());//设置ajax请求
webClient.getOptions().setTimeout(10000);//设置连接超时时间 ,这里是10S。如果为0,则无限期等待
HtmlPagehtmlPage=webClient.getPage(httpUrl);//访问路径设置
webClient.setJavaScriptTimeout(10000);//设置js运行超时时间
webClient.waitForBackgroundJavaScript(10000);//设置页面等待js响应时间,设置一个运行JavaScript的时间,异步JS执行需要耗时,所以这里线程要阻塞30秒,等待异步JS执行结束
content=htmlPage.asXml(); 
webClient.close();

2.selenium简单版 (ChormeDriver,FireFoxDriver)   

    selenium下载: selenium Mirror

   滚动加载页面问题:我们很常见的一些网站如百度新闻、淘宝页面内容很多,如果一次性加载会很费时间,所以网站会做成当你滚动条下滑时动态加载,当然我用htmlunit试过了不管用,所以我找到了selenium,每次让滚动条滚动底部,等待2s后新的内容加载出来,继续滚动到底部,知道页面全部加载完成。

火狐浏览器

System.setProperty("webdriver.firefox.bin", "D:/Firefox/firefox.exe");//selenium下载的jar包中自己继承了火狐驱动所以可以直接用
WebDriver driver = new FirefoxDriver();

谷歌浏览器

    谷歌驱动下载:http://chromedriver.storage.googleapis.com/index.html

System.setProperty("webdriver.chrome.driver", "chromedriver.exe");//需要自己去下载谷歌驱动,注意你的驱动版本、selenium版本、浏览器版本最好都是最新,不然会出各种不知道为什么的错误
ChromeOptions chromeOptions=new ChromeOptions();
chromeOptions.setBinary("Chrome/Application/chrome.exe");//你的谷歌浏览器的位置
WebDriver driver = new ChromeDriver(chromeOptions);

滚动条下滑

WebElement body=driver.findElement(By.tagName("body"));

int height_old=body.getSize().height;

while(true){
	((JavascriptExecutor)driver).executeScript("window.scrollTo(0,document.body.scrollHeight)");
        Thread.sleep(2000);
	int height_new=driver.findElement(By.tagName("body")).getSize().height;
	System.out.println(height_new+"||"+height_old);
	if(height_new==height_old){
		break;
	}
	height_old=height_new;
}

3.HtmlUnitDriver,PhantomJsDriver,ChormeDriver无头模式

   不显示浏览器窗口问题:selenium是用来做测试工具用的,换句话说在你运行时会有浏览器界面在屏幕上自动操作,但最终为了节省时间我们希望他不显示界面,于是我发现selenium里有一些无界面的驱动如HtmlUnitDriver,PhantomJsDriver

HtmlUnitDriver driver=new HtmlUnitDriver(BrowserVersion.CHROME);
driver.setJavascriptEnabled(true);
String browserPath = "D:/jarbao/phantomjs/phantomjs-1.9.8-windows/phantomjs.exe";//phantomjs需要你取下载
System.setProperty("phantomjs.binary.path", browserPath);
WebDriver driver = new PhantomJSDriver();

可是当我使用他们后我之前写的滚动条下滑的代码不起作用了,几番寻找后我发现了谷歌的无头模式:

System.setProperty("webdriver.chrome.driver", "chromedriver.exe");
ChromeOptions chromeOptions=new ChromeOptions();
chromeOptions.setBinary("Chrome/Application/chrome.exe");
chromeOptions.addArguments("--headless");//关键的这句话
WebDriver driver = new ChromeDriver(chromeOptions);

火狐无头模式:

File pathToFirefoxBinary =new File("D:/Firefox/firefox.exe");
FirefoxBinary firefoxBinary = new FirefoxBinary(pathToFirefoxBinary);
firefoxBinary.addCommandLineOptions("--headless");
System.setProperty("webdriver.gecko.driver", "browser/FireFox/geckodriver.exe");
FirefoxOptions firefoxOptions = new FirefoxOptions();
firefoxOptions.setBinary(firefoxBinary);
WebDriver driver = new FirefoxDriver(firefoxOptions);

4.模拟登陆

    (1)无法根据id获取元素问题(iframe切换):

        当获取input元素时提示 :

        no such element: Unable to locate element: {"method":"id","selector":"inputId"}

        这是因为此内容时放在iframe里面的故查不到,需要先进入到iframe里面

        driver.switchTo().frame("iframe名称");

        driver.findElement(By.id("inputId")).click();

    (2)页面跳转:

    String currentWindow=driver.getWindowHandle();//得到当前窗口
    Set<String> handler=driver.getWindowHandles();//获取所有窗口
    Iterator<String> lt=handler.iterator();    
    while(lt.hasNext()){
        if(currentWindow==lt.next()){
    		continue;
    	}
        driver.switchTo().window(lt.next());//跳转到新窗口
    }

     (3)  识别验证码问题

        方法一:最开始我使用了Tesseract取做二维码识别(只能识别最简单的二维码)

        下载:http://digi.bib.uni-mannheim.de/tesseract/tesseract-ocr-setup-4.00.00dev.exe

        配置环境变量:

               

                

    测试是否配置成功:

     

    之后你就可以在cmd任意目录下执行tesseract指令了,然后在java中去调用它,但精度很不好:(有的文章说精度不准可以通过一个工具jTessBoxEditor学习机制,去创建自己的识别库,我试了很难很机械!)

Runtime.getRuntime().exec("cmd /C tesseract D://yzm.png D://tmp")//去D盘下识别yzm.png并把结果保存到D盘下tmp.txt文件中
StringBuffer result=new StringBuffer();
BufferedReader br=new BufferedReader(new InputStreamReader(new FileInputStream(new File("D://tmp.txt")),"utf-8"));
String line="";
while((line=br.readLine())!=null){
     result.append(line);
}

 方法二:然后准备自己做验证,网上查了很多最后得到一个理论:

    -----灰度化------->  ------二值化------>  ------去杂点------> ------字符拆分------>      

   ------与标准库比较------>RTN6

(以下理论均来自于互联网)

 灰度化有俩种方法

        1 :取平均数作为灰度值

            灰度化后的R=(处理前的R+ 处理前的G +处理前的B)/ 3

            灰度化后的G=(处理前的R + 处理前的G +处理前的B)/ 3

            灰度化后的B=(处理前的R + 处理前的G +处理前的B)/ 3

       2 :  按一定的比例来作为灰度值(经对比推荐第二种)

            灰度化后的R=  处理前的R * 0.3+ 处理前的G *0.59 +处理前的B * 0.11

            灰度化后的G=  处理前的R * 0.3+ 处理前的G *0.59 +处理前的B * 0.11

            灰度化后的B=  处理前的R * 0.3+ 处理前的G *0.59 +处理前的B * 0.11

灰度化原理(彩色有255*255*255中,使用灰度话公式可以让RGB三种颜色相同从而范围减少为255种,方便后续的操作)

二值化方法:

       1:取阀值为127(相当于0~255的中数,(0+255)/2=127),让灰度值小于等于127的变为0(黑色),灰度值大于127的变为255(白色),这样做的好处是计算量小速度快,但是缺点也是很明显的,因为这个阀值在不同的图片中均为127,但是不同的图片,他们的颜色分布差别很大,所以用127做阀值,白菜萝卜一刀切,效果肯定是不好的。

        2:计算像素点矩阵中的所有像素点的灰度值的平均值avg,(像素点1灰度值+...+像素点n灰度值)/ n = 像素点平均值avg,然后让每一个像素点与avg一 一比较,小于等于avg的像素点就为0(黑色),大于avg的 像         素点为255(白色),这样做比方法1好一些。

去杂点方法:

        8邻域算法降噪法(简单的说就是:除了最外围的一圈像素点,以每个像素点为中心,如果其外围临近8个像素点中为黑的个数>阀值1(如7个)并且此点为白色我就把它换成黑色;同理如果是其外围临近8个像素点中为黑的个数<阀值2(如3个),并且此点为黑色我就把它换成白色)

public BufferedImage removeWastePoint(int rNum,int fNum,BufferedImage image) throws Exception{     //rNum,fNum为阀值
        int width = image.getWidth();  
        int height = image.getHeight();
        
        for(int x=0;x<width;x++){    
        	image.setRGB(x, 0, Color.WHITE.getRGB());
        	image.setRGB(x, height-1, Color.WHITE.getRGB());
        }
        for(int y=0;y<height;y++){
        	image.setRGB(0, y, Color.WHITE.getRGB());
        	image.setRGB(width-1, y, Color.WHITE.getRGB());
        }
        
        for (int x = 1; x < width-1; ++x) {  
            for (int y = 1; y < height-1; ++y) {  
            	if(getColorBright(image.getRGB(x, y))==0){
            		count=0;
            		for(int a=x-1;a<=x+1;a++){
            			for(int b=y-1;b<=y+1;b++){
            				if(getColor(image.getRGB(a, b))==0){
            					count++;
            				}
            			}
            		}
            		if(count<rNum){
            			image.setRGB(x, y, Color.WHITE.getRGB());
            		}
            	}else{
            		count=0;
            		for(int a=x-1;a<=x+1;a++){
            			for(int b=y-1;b<=y+1;b++){
            				if(getColor(image.getRGB(a, b))==0){
            					count++;
            				}
            			}
            		}
            		if(count>=fNum){
            			image.setRGB(x, y, Color.BLACK.getRGB());
            		}
            	}
            }  
        }  
        return image;
}
public static int getColor(int colorInt) {  
     Color color = new Color(colorInt); 
     return color.getRed() + color.getGreen() + color.getBlue();  
} 

字符串拆分:把经过处理的二维码图片截成单个字符的图片

与标准库做比较:标准库就是已经准备好的0-9 A-Z的单个数字字符的图片集,比如(用ps做的花了半天功夫,真的累)

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值