본문 바로가기

항해99

자바 셀레니움으로 크롤링 하기 (feat.뉴닉)

자동적 웹페이지 크롤링 하기 

 

1. chromedriver을 깐다. 

 

2.build.gradle에 라이브러리를 임포트 한다 

(maven repo를 창에 치고 들어가서 selenium을 치고 사용자가 많은 것을 선택후 그레이들을 선택하여 붙여넣기하세요)

 // https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-java
    implementation group: 'org.seleniumhq.selenium', name: 'selenium-java', version: '3.141.59'

 

 

bean으로 스프링에 주입

@Bean
public CommandLineRunner crawlArticles(ArticleService articleService) {
return (args -> {
Path path = Paths.get(System.getProperty("user.dir"), ("src/main/resources/chromedriver.exe"));

webdriver를 사용하기 위해 c드라이브에 넣고  메인에서 경로 설정을 해줍니다.

// WebDriver 경로 설정
System.setProperty("webdriver.chrome.driver", path.toString());

// WebDriver 옵션 설정
ChromeOptions options = new ChromeOptions();
options.addArguments("headless");
options.addArguments("--start-maximized"); // 전체화면으로 실행
options.addArguments("--disable-popup-blocking"); // 팝업 무시
options.addArguments("--disable-default-apps"); // 기본앱 사용안함
//주의:팝업창 안뜨게 만들기 잊지말기!!! 중요함...


창을 띄울때 원하는 조건에 맞춰서 창을 띄우기 위해 설정을 합니다.

// WebDriver 객체 생성
ChromeDriver driver = new ChromeDriver(options);

// 빈 탭 생성
driver.executeScript("window.open('about:blank','_blank');");

// 탭 목록 가져오기
List<String> tabs = new ArrayList<String>(driver.getWindowHandles());

//첫번째 탭으로 전환
driver.switchTo().window(tabs.get(0));

//웹페이지 요청
driver.get("https://newneek.co/");

이번에 크롤링한 웹페이지는 sbslr이라는 동적 웹페이지를 크롤링 하였기 때문에

스피너가 돌아가서 시간을 주고 loadmore라는 아이디가 나올때 까지 기다리게 하였습니다.

*기다리지 않으면 에러가 나서 크롤링을 할 수 없었습니다.

WebDriverWait wait = new WebDriverWait(driver, 20);
wait.until(ExpectedConditions.visibilityOfElementLocated(By.className("loadmore")));

뉴닉 메인펭지에 있는 더보기를 15번 정도를 눌러 페이지를 열고 크롤링을 할 생각이어서 

for문을 사용하여 15번을 눌렀습니다. 하지만 연속적으로 버튼이 15번 눌리기 때문에 wait을 주어 시간을 준뒤 다시 버튼을 누르도록 설정해주었습니다.

for (int i = 0; i < 15; i++) {
driver.findElementByClassName("loadmore").sendKeys(Keys.ENTER);

String waitTargetSelector = String.format(".card:nth-child(%d)", 12 + 12 * (i + 1));
wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector(waitTargetSelector)));
}

크롬드라이버가 카드로 들어갔을 때 크롤링 하려는 특정 태그의 위치를 Xpath로 찾아 기다렸다가 

그 태그로 들어가서 크롤링하게 했습니다.

//각 카드 href로 들어가기
List<WebElement> webElements = driver.findElementsByXPath("//*[@id=\"root\"]/div/section/div/a");
List<String> detailsUrlList = new ArrayList<>();
for (int i = 0; i < webElements.size(); i++) {
String url = webElements.get(i).getAttribute("href");
detailsUrlList.add(url);
}

각 페이지에 원하는 태그들을 크롤링 해오기 위해 태그들이 로딩 될때까지 기다리게 만들었다.

//각 url에 들어가서 제목, 카테고리, 내용 가지고 오기
for (int i = 0; i < detailsUrlList.size(); i++) {

driver.get(detailsUrlList.get(i));

final String TITLE_SELECTOR = "#root > div > section > div > header > h2";
final String CATEGORY_SELECTOR = "#root > div > section > div > header > a";
final String CONTENTS_SELECTOR = "#root > div > section > div > div";
final String DATE_SELECTOR = "#root > div > section > div > header > time";
final String IMAGE_SELECTOR = "#root > div > section > div > div > div.post-body-thumb > img";

wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector(TITLE_SELECTOR)));
wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector(CATEGORY_SELECTOR)));
wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector(CONTENTS_SELECTOR)));

 

try&catch로 이미지가 없는 부분을 예외처리 해주었고 

ArticleRequestDto에 저장 할 수 있도록 밖에서 String으로 변수를 만들었다 

String title = "";
String categoryName = "";
String image = "";
String contents = "";
LocalDate date;

//제목가지고 오기
WebElement postWebElement = driver.findElementByCssSelector(TITLE_SELECTOR);
title = postWebElement.getText();

//카테고리 가지고 오기
WebElement cateWebElement = driver.findElementByCssSelector(CATEGORY_SELECTOR);
categoryName = cateWebElement.getText();

//날짜 가지고 오기
WebElement dateWebElement = driver.findElementByCssSelector(DATE_SELECTOR);
String dateText = dateWebElement.getText();
date = LocalDate.parse(dateText, DateTimeFormatter.ofPattern("yyyy/MM/dd"));

//이미지 가지고 오기 /이미지가 없을 때를 대비
try {
WebElement imageWebElement = driver.findElementByCssSelector(IMAGE_SELECTOR);
image = imageWebElement.getAttribute("src");

} catch (NoSuchElementException e) {
}

//내용 가지고 오기
WebElement contentWebElement = driver.findElementByCssSelector(CONTENTS_SELECTOR);
contents = contentWebElement.getAttribute("innerHTML");

크롤링한 값들을 ArticleRequestDto에 저장했다. 

ArticleRequestDto requestDto = new ArticleRequestDto(title, image, contents, categoryName);
ArticleCrawlRequestDto crawlRequestDto = new ArticleCrawlRequestDto(requestDto, date);
articleService.create(crawlRequestDto);
}

그리고 크롬 브라우저 창 닫기

 

driver.close();
driver.quit();

});
}

'항해99' 카테고리의 다른 글

[항해99 - chapter01] 미니 웹 프로젝트(Starting Assignment)  (0) 2021.03.01