Selenium2015. 10. 22. 02:39
반응형

 본 아티클에서는 웹 크롤러를 개발하거나 산출물 작성을 위해 웹 페이지의 스크린샷을 찍어야 하는 경우 Selenium(셀레니움)을 이용하여 캡쳐를 자동화 하는 방법에 대해서 소개하도록 하겠습니다. 사실 Java Swing 혹은 JavaFX의 웹뷰를 이용하면 별도의 라이브러리를 추가하지 않고도 필요한 기능을 구현할 수 있지만 웹뷰의 경우 최근의 웹 페이지가 제대로 렌더링 되지 않거나 사용법의 복잡한 관계로 브라우저를 직접 핸들링하는 오토메이션 툴인 Selenium을 이용하도록 하겠습니다.




Gradle을 이용하여 의존관계 추가

...
//FireFox용 드라이버
compile('org.seleniumhq.selenium:selenium-firefox-driver:2.48.2')
...


 본 아티클에서는 Selenium에서 별다른 설정없이도 잘 동작하는 FireFox드라이버를 이용하도록 하겠습니다. 소스코드를 동작시킬 단말 혹은 서버에 FireFox가 설치되어 있어야하며 Linux환경과 같은 경우는 xwindow의 display를 사용할 수 있도록 설정되어 있어야 합니다. display사용이 어려운 경우에는 PhantomJS와 같은 headless 브라우저를 이용하면 동일한 결과를 얻을 수 있습니다.




Selenium을 이용하여 스크린샷 취득하는 코드

WebDriver driver = null;
try {
    //드라이버 초기화
    driver = new FirefoxDriver();
    //캡쳐할 웹 페이지로 이동
    driver.get("https://www.google.com");
    //저장할 파일을 지정하여 캡쳐후 파일로 출력
    Path capture = Paths.get("screenshot.png");
    byte[] bytes = ((TakesScreenshot) driver).getScreenshotAs(OutputType.BYTES);
    Files.write(capture, bytes);
} catch (IOException e) {
    //Exception handling
} finally {
    if (driver != null) {
        driver.close();
    }
}


 위와 같이 소스코드 작성하여 실행하면 파이어폭스가 실행되면서 지정한 웹 페이지의 스크린샷이 캡쳐됩니다. 여기서 한가지 고려해야 할 점은 소스상에서 캡쳐할 웹 페이지로 이동하기 위해서 사용한 WebDriver#get메소드는 http get메소드를 실행한 것과 동일하므로 응답이 오면 즉시 리턴되어 이미지, 자바스크립트 등을 이용하여으로 별도로 핸들링되어 로딩되는 요소들은 렌더링되지 않은 상태에서 스크린샷이 캡쳐될 가능성이 있다는 것입니다. 이와 같은 문제를 회피하기 위한 방법에 대해서 알아보도록 하겠습니다.




고정된 시간만큼 지연시키는 방법


 첫번째 방법은 Java의 스레드 실행을 지연시켜서 뒤늦게 렌더딩되는 요소들도 스크린샷에 쩩히게 하는 방법입니다.하지만 이 방법은 네트워크 문제 혹은 복잡한 Dom핸들링으로 인해 설정한 시간보다 더 지연되어 로딩되는 요소들을 표시할 수 없다는 단점이 있습니다. 하지만 적정시간을 지정한다면 별다른 고민없이도 범용적으로 사용할 수 있다는 장점이 있습니다.

//초기화 코드
...
driver.get("스크린샷을 찍을 웹 페이지 URL");
try {
    Thread.sleep(3000);
} catch (InterruptedException e) {
}
...
//캡쳐 코드




화면의 특정 요소가 렌더링될때까지 대기


 두번째 방법은 화면의 특정 요소가 렌더링 될 때까지 대기했다가 스크린샷을 찍는 방법입니다. 화면의 요소를 기준으로 하기때문에 렌더링 여부를 정확하게 판단하여 스크린샷을 찍을 수 있다는 장점이 있지만 페이지의 구조를 파악해야 하기때문에 다양한 외부 사이트를 대상으로 하는 경우에는 사용하기 어려울 수 있습니다. 이와 같은 경우는 위에서 언급한 일정시간 대기하는 방법이 좀더 효율적일 듯 합니다. 내부 웹 페이지를 대상으로 하는 경우에는 사전에 렌더링 완료여부를 가늠할 수 있는 요소를 삽입해 둔다면 웹 페이지의 구조를 파악하는 수고를 덜 수 있습니다.

//초기화 코드
...
driver.get("스크린샷을 찍을 웹 페이지 URL");
//id가 element인 요소가 렌더링 되는 것을 기다림
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
driver.findElement(By.id("element"));
...
//캡쳐 코드

※역으로 생각해보면 외부 공개용의 웹 페이지를 작성할 때는 최초 로딩시점에 최대한 많은 요소들이 렌더링 되도록 해야 크롤링 등에 유리하다고 생각할 수 있겠습니다.




  위에서 소개한 방법을 이용하면 웹 페이지의 스크린샷 취득을 자동화할 수 있습니다. 물론 복잡할 웹 페이지를 핸들링하기 위해서는 Selenium의 일반적일 사용법에 대한 지식도 필요합니다. 이러한 부분에 대해서는 별도의 아티클을 통하여 소개하도록 하겠습니다.

 


※주의 : 외부 웹 사이트의 스크린샷을 찍을때는 해당 웹 사이트의 robots.txt 설정을 준수하여 크롤링이 허용되어 있는 페이지만 스크린샷을 찍도록 하고 robots.txt에 딜레이 옵션이 없다고 하더라도 요청후 다음 요청까지 일정시간 간격을 두어 해당 웹 사이트에 부하가 걸리지 않도록 주의해야 합니다.



Posted by Reiphiel