Как найти элемент по изображению - PullRequest
0 голосов
/ 19 июня 2019

Как мы знаем, селен поддерживает стратегию нескольких локаторов для поиска элемента на веб-странице.

Но мое требование другое, у меня есть несколько сайтов, на которых локаторов, поддерживаемых селеном, недостаточно, чтобы найти элемент уникальным образом.

Поскольку селен позволяет создавать собственную стратегию локатора для поиска элемента, я пытаюсь создать локатор image , который мог бы найти элемент, используя base64 String вспомогательного изображения как appium do.

Точки за локатор изображения:

  1. Запустить браузер с URL
  2. Снимок экрана со страницы
  3. Определить x , y расположение вспомогательного изображения из скриншота
  4. Найти элемент, используя x , y местоположение со страницы

Для решения этой задачи я создаю пользовательский локатор Image, как показано ниже:

public class ByImage extends By {

    String imageBase64String

    /**
     * @param imageBase64String
     */
    public ByImage(String imageBase64String) {
        this.imageBase64String = imageBase64String
    }

    @Override
    public List<WebElement> findElement(SearchContext context) {
        List<WebElement> els = findElements(context)
        if (els) {
            return els.get(0)
        }
        throw new NoSuchElementException("Element not found")
    }

    @Override
    public List<WebElement> findElements(SearchContext context) {
       //Get current screenshot
        byte[] screenshotByte = ((TakesScreenshot)context).getScreenshotAs(OutputType.BYTES))
        byte[] subImgToFindByte = DatatypeConverter.parseBase64Binary(imageBase64String)
        //Convert buffred image to get height and width of subimage
        BufferedImage bufferedSubImgToFind = ImageIO.read(new ByteArrayInputStream(subImgToFindByte ));

        //Here I need a mechanism to get coordinates of sub image from screenshot
        //Suppose I able to find x, y
        double x
        double y

        //Now find element using coordinates
        //Now calculate center point
        int centerX = int(x + (bufferedSubImgToFind.getWidth() / 2))
        int centerY = int(y + (bufferedSubImgToFind.getHeight() / 2))

        JavascriptExecutor js = ((JavascriptExecutor)context)

        return js.executeScript("return document.elementsFromPoint(arguments[0], arguments[1]);", centerX, centerY)
      }   
  }

Теперь контрольный пример выглядит так:

WebDriver driver = new ChromeDriver()
driver.get("<URL>")
WebElement elementByImage = driver.findElement(new ByImage("<Base64 String of the subimage>"))

Я могу добиться всего, кроме лучшей библиотеки для определения точных координат subimage из image для поиска элемента с использованием координат.

Может ли кто-нибудь предложить мне лучший подход для решения этой задачи?

Ответы [ 3 ]

2 голосов
/ 19 июня 2019

Существуют различные варианты, например:

.
  1. Вы можете использовать Java Bindings для OpenCV , чтобы посмотреть подизображение на главном скриншоте, посмотрите статью Template Matching для подробного объяснения и фрагментов кода.
  2. Project Sikuli предоставляет несколько простых API для распознавания / взаимодействия изображений
  3. SeeTest Automation обеспечивает распознавание изображений и хранилище объектов реализация шаблонов для шаблонов изображений
0 голосов
/ 19 июня 2019

Просто добавьте еще один вариант для пользователей, которые не знакомы с привязками Java и OpenCV: Selenium IDE ++ содержит встроенные команды распознавания изображений:

  • XClick (image)
  • XMove (image)
  • и поддержка OCR: XClick (ocr=text)

Подробнее см. На странице Тестирование пользовательского интерфейса . Вы можете вызвать его из Java через командную строку .

0 голосов
/ 19 июня 2019

Как сказал @Dmitri, я собираюсь использовать Java Bindings для OpenCV .

скачайте соответствующий OpenCV и извлеките его в classpath и попытайтесь получить координаты как:

import org.opencv.core.Core;
import org.opencv.core.Core.MinMaxLocResult;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.MatOfByte;
import org.opencv.core.Point;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;

byte[] screenshotByte = ((TakesScreenshot)context).getScreenshotAs(OutputType.BYTES))
byte[] subImgToFindByte = DatatypeConverter.parseBase64Binary(imageBase64String)

System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
Mat source = Imgcodecs.imdecode(new MatOfByte(screenshotByte), Imgcodecs.IMREAD_UNCHANGED);
Mat template = Imgcodecs.imdecode(new MatOfByte(subImgToFindByte), Imgcodecs.IMREAD_UNCHANGED);

int result_cols = source.cols() - template.cols() + 1;
int result_rows = source.rows() - template.rows() + 1;
Mat outputImage = new Mat(result_rows, result_cols, CvType.CV_32FC1);

// Template matching method
Imgproc.matchTemplate(source, template, outputImage, Imgproc.TM_SQDIFF_NORMED);

MinMaxLocResult mmr = Core.minMaxLoc(outputImage);
// Now get the point
Point point = mmr.minLoc;
double x = point.x;
double y = point.y;

//Now get the find the element using x, y after calculating center point.
int centerX = int(x + (bufferedSubImgToFind.getWidth() / 2));
int centerY = int(y + (bufferedSubImgToFind.getHeight() / 2));

WebElement el = js.executeScript("return document.elementFromPoint(arguments[0], arguments[1]);", centerX, centerY);

Надеюсь, это поможет всем.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...