Selenium圖表驗證實戰(zhàn)

年后回來第二周正式開始了2018年度的第一個sprint(敏捷開發(fā)流程概覽見下圖),這也是轉(zhuǎn)入開發(fā)團(tuán)隊參加的第一個sprint,前一周周五的會議上將這個sprint的任務(wù)清單安排的滿滿當(dāng)當(dāng),當(dāng)時心里還在想: 這么多需求,10天能做完嗎?!


敏捷開發(fā)流程概覽

周一上午每日站會上,領(lǐng)了個“難啃”的任務(wù): 爬取某度頁面的指數(shù)數(shù)據(jù),某度反爬技術(shù)果真不是蓋的,想通過接口拉數(shù)據(jù)?no way,不操作頁面無數(shù)據(jù)請求,且接口返回的是加密的數(shù)據(jù)片段圖片,在前端頁面再解密組合成數(shù)據(jù)圖片展示的(見下圖),這腫么搞。。。。


某度指數(shù)

為什么要領(lǐng)這個任務(wù)?以前UI自動化測試做過那么多,有這方面基礎(chǔ),雖然圖表的自動化測試一般都是直接跳過,不過這次想嘗試挑戰(zhàn)一下;其實這種驗證或開發(fā)思路很明確,分2步:

  1. 在圖表上移動鼠標(biāo)指針到對應(yīng)的點,出現(xiàn)數(shù)據(jù)浮標(biāo),截圖保存;
  2. 對截圖做OCR識別,提取出圖片中的數(shù)據(jù);

思路是不是很簡單的感覺?可做起來就不是特么的那么回事了,中間有好幾個大坑等著你跳,下面我把一些技術(shù)難點(大坑)分享出來,對做圖表方面的UI自動化測試可以參考下:

  1. 第一個坑就是鼠標(biāo)移動了,用過WebDriver的都知道可以用Actions,可是這個Action是基于那個元素或控件呢?
    一般第一直覺大家都會選圖表對于的標(biāo)簽元素(如<chart>、<svg>、<graph>、<rect>、<canvas>等等),很坑,用這些標(biāo)簽去定位WebDriver識別不了。。。。根本找不到對應(yīng)的元素(高版本沒有去嘗試了不知道會不會好些,我這里用的2.53.1版本),這時候就要找這個圖表元素外層的第一個div標(biāo)簽(通常圖表外面都會包一層div),鼠標(biāo)移動Action的代碼我也貼一下:
private void move(WebElement element, int x, int y) {
    Actions action = new Actions(driver);
    try {
        //操作
        if (x == 0) {
            action.moveToElement(element, 20, y).perform();
        } else {
            action.moveToElement(element, x, y).build().perform();
        }
    } catch (MoveTargetOutOfBoundsException e) {
        System.out.println(String.format("point(%d, %d) is out of range", x, y));
    }

    System.out.println(String.format("move the cursor to point(%d,%d)", x, y));
    sleep(1000);
}
  1. 第二個坑,移動鼠標(biāo)并不能每次都完美移到位,所以就要加一個數(shù)據(jù)浮標(biāo)出來了才算成功,否則就要在當(dāng)前坐標(biāo)的前后小范圍內(nèi)嘗試;
move(chart, x, y);

File snapshot = snapshotAndSave(chart, genSnapshotName(x, y));
boolean isSuccess = templateMatcher.isMatch(snapshot.getPath(), templateImgFile);

int counter = 0;
int tempX = x > 0 ? x - offset : 10;

while (!isSuccess) {//如果未出現(xiàn)預(yù)期pop,則在區(qū)間[x-10, x+10]內(nèi)重試5次
    if (counter > 4) {
        break;
    }
    snapshot.delete();//刪除無效圖片

    move(chart, tempX, y);

    snapshot = snapshotAndSave(chart, genSnapshotName(tempX, y));
    isSuccess = templateMatcher.isMatch(snapshot.getPath(), templateImgFile);

    tempX += offset / 2; //坐標(biāo)移動offset/2位
    counter++;
}
  1. 區(qū)域截圖?
    WebDriver截圖通常都是截取全瀏覽器的,我現(xiàn)在就只想接圖表區(qū)域那部分,how to do? 相信你們也很想知道,直接看到代碼,注釋很清晰了:
private File snapshotAndSave(WebElement element, String fileName) {
    WrapsDriver wrapsDriver = (WrapsDriver) element;
    File scrFile = ((TakesScreenshot) wrapsDriver.getWrappedDriver()).getScreenshotAs(OutputType.FILE);//截圖整個頁面
    try {
        BufferedImage img = ImageIO.read(scrFile);
        // 獲得元素的高度和寬度
        int width = element.getSize().getWidth();
        int height = element.getSize().getHeight();
        // 創(chuàng)建一個矩形使用上面的高度,和寬度
        Rectangle rect = new Rectangle(width, height);
        // 得到元素的坐標(biāo)
        Point p = element.getLocation();
        BufferedImage dest = img.getSubimage(p.getX(), p.getY(), rect.width, rect.height);
        //存為png格式
        ImageIO.write(dest, "png", scrFile);
        File file = new File(fileName);
        FileUtils.copyFile(scrFile, file);
        return file;
    } catch (Exception e) {
        e.printStackTrace();
    }
    return null;
}
  1. 第4個大坑,怎么驗證那個淺黑色的數(shù)據(jù)浮標(biāo)(popup)?
    這個坑比上面都要難,剛開始我想到的是用sikuli來處理,確實效果很好,識別的很準(zhǔn)確,可是。。。我后來一問,代碼規(guī)范不允許maven項目直接引用jar包,我去。。。。搜索了google半天也沒找到sikuliX.jar的maven依賴方式,沒辦法從頭再來,后面想偷點懶,想找一些現(xiàn)成的圖片驗證方案來處理,找了幾個github上star比較多的項目嘗試了下都不理想,跟我這個需求不匹配,那些處理都是將背景灰化,可是我就是想要驗證這一層浮標(biāo)的背景,灰化之后就沒差異性了。所以還是得自己動手豐衣足食,先確定好思路:
    1> 截圖的時候盡量只截取圖表區(qū)域,排除一些無關(guān)干擾,這個可以去調(diào)整坑3中的截圖坐標(biāo)和高度,就會得到你滿意的效果;
    2> 顏色驗證方案如何做? 看過我文章的童鞋應(yīng)該還記得分享過的UiAutomator2.0移動端的顏色驗證方案,這次思路就是來自那里,并做了算法改進(jìn):
  • 由于浮標(biāo)可以理解是一層懸浮在頁面的div,那么它跟頁面肯定會有交集,如果交集區(qū)域頁面也有顏色就會造成很大的干擾,那么我們就直接取像素點的顏色rgb值驗證就好了,千萬別灰化,用那個就GG;
private boolean assertColor(int rgb) {
    //容錯處理,正常浮標(biāo)數(shù)據(jù)的色度在[-12170676或-11907766]=RGB(74,74,74),所以base取74
    int base = 74;
    int r = (rgb >> 16) & 0xff;
    int g = (rgb >> 8) & 0xff;
    int b = rgb & 0xff;

    boolean isMatch =
            Math.abs(r - base) * 1.0 / base < 0.2 && Math.abs(g - base) * 1.0 / base < 0.2
                    && Math.abs(b - base) * 1.0 / base < 0.2;
    return isMatch;
}
  • 考慮到很多干擾,最后我決定就只找浮標(biāo)的四個頂點,遍歷圖片的像素點(所以截圖不能太大,圖片較大的話壓縮一下尺寸后再遍歷)驗證四個頂點存在即浮標(biāo)出現(xiàn);
BufferedImage sourceImage = readImage(String.valueOf(sourceFile));
int sourceHeight = sourceImage.getHeight();
int sourceWidth = sourceImage.getWidth();

BufferedImage cutImage = null;
Integer counter = 1;
Map<Integer, List<Integer>> points = new LinkedHashMap<Integer, List<Integer>>();//存放頂點坐標(biāo)

for (int i = 0; i < sourceWidth; i++) {
    if (counter > 4) {
        break;
    }
    for (int j = 0; j < sourceHeight; j++) {
        if (isColorRangeMatch(sourceImage, i, j, counter)) {
            if (counter > 4) {
                break;
            }
            points.put(counter, Arrays.asList(new Integer[] { i, j }));
            counter++;
        }
    }
}
  • 四個頂點的查找和驗證,我這里使用了一些小算法,比如如何確定是一個頂點?干擾點如何排除?采用了構(gòu)造3*3矩形點陣、矩形面積和十字交叉驗證等方法;
//構(gòu)造(x,y)坐標(biāo)的矩形點陣
int[][] points = new int[][] { { x - 1, y - 1 }, { x - 1, y }, { x - 1, y + 1 },
                { x, y - 1 }, { x, y }, { x, y + 1 }, { x + 1, y - 1 }, { x + 1, y },
                { x + 1, y + 1 } };
矩陣點陣

如上圖,一個坐標(biāo),構(gòu)造對應(yīng)坐標(biāo)的3x3矩形點陣,紅色點表示顏色匹配的,其他點顏色不匹配,如果符合這個條件就可以基本斷定這是一個頂點了,但是由于界面上還有其他顏色交叉干擾,所以就還需要矩形面積(其實思路也跟上面類似,基于疑似頂點+方向構(gòu)造對應(yīng)的10x10矩陣,計算面積內(nèi)的點都符合即進(jìn)一步判斷是頂點)和十字交叉驗證(基于疑似頂點的x軸和y軸各上下移動一位得到4個點坐標(biāo),其中按照點的方向判斷哪些點顏色符合即可判斷是不是頂點);

最后按照這樣跑完及匹配后切圖,就會得到原圖(x.png)和切出來的數(shù)據(jù)圖(data*.png),如下:

效果

后面再對切出來的數(shù)據(jù)圖做OCR文字識別就可以將數(shù)據(jù)都提取出來了,OCR識別這樣的圖片可以說是毫無壓力了,要是原圖那就亂慘不忍睹了,OCR文字識別這部分可以引用開源的框架或開放的OCR接口,比如百度的OCR文字識別API(有興趣可以自己去了解了,文檔很詳細(xì),步驟很簡單)。

原文來自下方公眾號,轉(zhuǎn)載請聯(lián)系作者,并務(wù)必保留出處。
想第一時間看到更多原創(chuàng)技術(shù)好文和資料,請關(guān)注公眾號:測試開發(fā)棧

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容