에러 메세지
selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate element: {"method" : "css selector", "selector" : ".gs_citr"}
(Session info: chrome=1.2.3.4);
원인
className = gs_citr의 요소를 찾을 수 없음.
Crawler 제작 중에 NoSuchElementException이 간헐적으로 발생하여
대략 데이터 100건 중 2~3건은 전부 값을 읽지 못해 공백으로 insert되는 issue
해결
해결을 위해 따로 공식문서를 찾아보며 공부 진행하였고 포스팅하였음.
셀레니움 공식문서의 3가지 해결방법 중 Explicit Wait(명시적 대기)를 사용하여, 조건을 주어 해결
기존 코드
private static void selenium(String[] dataset, Connection mysql, String[] selenium, int idx) throws Exception {
log.writeLogMsg("[selenium start]", path);
if (mysql.isClosed()) {
mysql = dbConf.connectDB("REFDB");
}
ChromeOptions options = new ChromeOptions();
options.setPageLoadStrategy(PageLoadStrategy.NORMAL);
options.setHeadless(true);
System.setProperty(selenium[0], selenium[1]);
WebDriver driver = new ChromeDriver(options);
String pre = "";
try {
driver.get(current_url);
List<WebElement> elem = driver.findElements(By.cssSelector("h3.gs_rt > a"));
WebElement quoto_btn = elem.get(idx).findElement(By.xpath("..")).findElement(By.xpath("following-sibling::*[3]")).findElement(By.cssSelector("a.gs_or_cit"));
quoto_btn.click();
WebElement title = driver.findElement(By.cssSelector("div.gs_citr"));
dataset[1] = title.getText().substring(title.getText().indexOf("\"")+1, title.getText().lastIndexOf("\"")-1);
WebElement BibTeX = driver.findElement(By.cssSelector("a.gs_citi"));
BibTeX.click();
wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("pre")));
pre = driver.findElement(By.cssSelector("pre")).getText();
//PUB_YEAR
if(pre.contains("year={")) dataset[5] = pre.substring(pre.indexOf("year={")+"year={".length(), pre.indexOf("}", pre.indexOf("year={")));
Runtime.getRuntime().exec("taskkill /F /IM chromedriver.exe /T");
}catch(NoSuchElementException e){
log.writeLogMsg("[seenium NoSuchElementException]" + dataset[0] + "\t" + dataset[1] + "\t" + dataset[2] + "\t" + dataset[3] + "\t" + dataset[4] + "\t" + dataset[5], path);
}catch(Exception e){
log.writeLogMsg("[seenium error]" + dataset[0] + "\t" + dataset[1] + "\t" + dataset[2] + "\t" + dataset[3] + "\t" + dataset[4] + "\t" + dataset[5], path);
}finally {
driver.quit();
}
}
위의 코드에서의 문제는 click시에 발생하였는데
click 시 로딩 시간이 있는데, 코드 내부에서 이를 기다려주지 않고 바로 계속 동작을 수행하기 때문에
로딩 시간이 코드 실행 시간보다 더 길면 아무 것도 읽지 못한다(NULL)
final WebDriverWait wait = new WebDriverWait(driver, 10);
이를 위해 DriverWait 설정을 해 주었으며 최대 10초동안 기다린다.
여기서도 문제가 있는데, 만약 10초를 초과할 경우 timeoutException이 발생 할 것이다. 이 부분은 컴퓨터 성능이나 Crawling을 진행하는 웹의 서버 이슈 등 모든 상황을 고려해야 할 것이다.
어짜피 조건을 모두 수행하면 넘어가기 때문에 크게 신경쓰지 않아도 된다고 생각하긴 하지만, 100% 장담은 못하겠다...
List<WebElement> elem = wait.until(ExpectedConditions.visibilityOfAllElementsLocatedBy(By.cssSelector("h3.gs_rt > a")));
new WebDriverWait(driver, 10).until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("div.gs_citr")));
또한 해당 Element를 읽을 수 있도록, wait를 걸어서, 조건을 내가 찾고자하는 Element의 cssSelect을 사용하여 className으로 지정하였다. 조건은 원하는 대로 작성하자. 위의 포스팅에도 간략하게 어떤 조건을 사용할 수 있는지 등을 기록해 놓았음.
전체 코드
private static void selenium(String[] dataset, Connection mysql, String[] selenium, int idx) throws Exception {
log.writeLogMsg("[selenium start]", path);
if (mysql.isClosed()) {
mysql = dbConf.connectDB("REFDB");
}
ChromeOptions options = new ChromeOptions();
options.setPageLoadStrategy(PageLoadStrategy.NORMAL);
options.setHeadless(true);
System.setProperty(selenium[0], selenium[1]);
WebDriver driver = new ChromeDriver(options);
final WebDriverWait wait = new WebDriverWait(driver, 10);
String pre = "";
try {
driver.get(current_url);
List<WebElement> elem = wait.until(ExpectedConditions.visibilityOfAllElementsLocatedBy(By.cssSelector("h3.gs_rt > a")));
WebElement quoto_btn = elem.get(idx).findElement(By.xpath("..")).findElement(By.xpath("following-sibling::*[3]")).findElement(By.cssSelector("a.gs_or_cit"));
quoto_btn.click();
new WebDriverWait(driver, 10).until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("div.gs_citr")));
WebElement title = driver.findElement(By.cssSelector("div.gs_citr"));
dataset[1] = title.getText().substring(title.getText().indexOf("\"")+1, title.getText().lastIndexOf("\"")-1);
new WebDriverWait(driver, 10).until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("a.gs_citi")));
WebElement BibTeX = driver.findElement(By.cssSelector("a.gs_citi"));
BibTeX.click();
new WebDriverWait(driver, 10).until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("pre")));
pre = driver.findElement(By.cssSelector("pre")).getText();
//PUB_YEAR
if(pre.contains("year={")) dataset[5] = pre.substring(pre.indexOf("year={")+"year={".length(), pre.indexOf("}", pre.indexOf("year={")));
Runtime.getRuntime().exec("taskkill /F /IM chromedriver.exe /T");
}catch(NoSuchElementException e){
System.out.println(e.getMessage());
log.writeLogMsg("[seenium NoSuchElementException]" + dataset[0] + "\t" + dataset[1] + "\t" + dataset[2] + "\t" + dataset[3] + "\t" + dataset[4] + "\t" + dataset[5], path);
}catch(Exception e){
System.out.println(e.getMessage());
log.writeLogMsg("[seenium error]" + dataset[0] + "\t" + dataset[1] + "\t" + dataset[2] + "\t" + dataset[3] + "\t" + dataset[4] + "\t" + dataset[5], path);
}finally {
driver.quit();
}
}
2023.04 ~ 백엔드 개발자의 기록
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!