카페(업체) 대표사진들의 url을 크롤링해와야 함.
카페 이미지url 크롤링 로직을 기존 로직 안에 추가 한 이후로
네이버 지도의 검색결과인 n개의 카페의 데이터를 크롤링해오지 못하고
오직 하나의 카페의 데이터만 크롤링한 후 NoSuchElementException 에러 발생.
(이미지url크롤링 로직 추가 전에는 n개의 카페들의 정보를 모두 크롤링 해올 수 있었다)
NoSuchElementException
- 해당 요소를 찾지 못함
- 웹페이지가 예상대로 로드되지 않았을 가능성
- (가능성 있음) 왜?
- 셀레늄으로 데이터를 가져오는데 시간이 오래걸린다.
- 그래서 셀레늄에서는 웹 요소가 로드되기를 기다리는 다양한 대기 방법을 제공한다.
- Thread.sleep() 메서드는 일정한 시간 동안 프로그램을 일시적으로 멈춰서 크롤링이나 웹 페이지의 로딩이 완료되기를 기다릴 수 있습니다. - Fluent Wait는 Explicit Wait와 유사하지만, 조건을 만족할 때까지 주기적으로 대기하는 동안 일정한 주기로 또는 특정 예외가 발생할 때까지 대기할 수 있습니다. - WebDriverWait를 사용하면 특정 조건이 충족될 때까지 대기할 수 있습니다. 이를 통해 웹 요소의 가시성, 클릭 가능성, 존재 여부 등을 기다릴 수 있습니다.- 요소가 변경 되었을 가능성
- (가능성 없음) 왜?
- 이미지url 크롤링 로직을 사용하지 않으면 카페의 정보들은 사실상 제대로 가지고 온다. 즉, 요소가 변경되었을리가 없다.
카페 대표이미지를 보여주는 html 소스와 나의 기존 크롤링 코드를 모두 챗GPT한테 주고, 이미지 url을 크롤링 할 수 있도록 로직을 짜보라고 했더니
이런 로직을 주었다!
List<WebElement> imageElements = driver.findElements(By.cssSelector("div.K0PDV._div"));
for (int i = 0; i < 5 && i < imageElements.size(); i++) {
WebElement imageElement = imageElements.get(i);
String styleAttribute = imageElement.getAttribute("style");
String imageUrl = styleAttribute.split("url\\(")[1].split("\\)")[0].replaceAll("'", "").replaceAll("\"", "");
System.out.println("Image URL: " + imageUrl);
}
이번엔 1개의 카페가 아닌 두군데의 카페의 정보와 이미지 url을 가져온다!
한개에서 두개로 늘었다!
그리고 에러메세지도 짧다~ (짧으니 뭔가 간단한 에러일 것 같은 너낌)
144번째 줄에 ArrayIndexOutOfBoundsException 오류가 뜨면서 크롤링을 멈췄다.
ArrayIndexOutOfBoundsException
- ArrayIndexOutOfBoundsException 오류는 배열의 인덱스를 벗어나는 값에 접근하려고 할 때 발생함
114번째 줄.. url을 split해서 가져오는 부분인데..
String imageUrl = styleAttribute.split("url\\(")[1].split("\\)")[0].replaceAll("'", "").replaceAll("\"", "");
아무래도 img url 파싱 후 추출해서 배열에 담는부분에서 문제가 발생했던 것 같다.
그.러.면. 네이버 지도의 업체 대표 이미지 5개를 보여주는 소스를 통채로 다시 분석해보자.
<div class="uDR4i">
<div class="CEX4u">
<div class="fNygA"><a href="#" target="_self" role="button" class="place_thumb QX0J7" id="_autoPlayable">
<div class="K0PDV _div" style="width: 100%; height: 100%; background-position: 50% 0px; background-image: url("");" id="ibu_1"><span class="place_blind">업체</span></div>
</a></div>
</div>
<div class="CEX4u">
<div class="hEm4D">
<div class="CEX4u">
<div class="fNygA"><a href="#" target="_self" role="button" class="place_thumb QX0J7">
<div class="K0PDV _div" style="width: 100%; height: 100%; background-position: 50% 0px; background-image: url("https://search.pstatic.net/common/?autoRotate=true&type=w278_sharpen&src=https%3A%2F%2Fldb-phinf.pstatic.net%2F20231216_153%2F1702716167403SgcbV_JPEG%2FIMG_20231214_162649_658.jpg");" id="ibu_2"><span class="place_blind">업체</span></div>
</a></div>
</div>
<div class="CEX4u">
<div class="fNygA"><a href="#" target="_self" role="button" class="place_thumb QX0J7">
<div class="K0PDV _div" style="width: 100%; height: 100%; background-position: 50% 0px; background-image: url("https://search.pstatic.net/common/?autoRotate=true&type=w278_sharpen&src=https%3A%2F%2Fldb-phinf.pstatic.net%2F20231216_258%2F1702716166842xW2oR_JPEG%2FIMG_20231128_121415_474.jpg");" id="ibu_3"><span class="place_blind">업체</span></div>
</a></div>
</div>
</div>
<div class="hEm4D">
<div class="CEX4u">
<div class="fNygA"><a href="#" target="_self" role="button" class="place_thumb QX0J7">
<div class="K0PDV _div" style="width: 100%; height: 100%; background-position: 50% 0px; background-image: url("https://search.pstatic.net/common/?autoRotate=true&type=w278_sharpen&src=https%3A%2F%2Fldb-phinf.pstatic.net%2F20231216_104%2F1702716165793ODV8U_JPEG%2F20231122_141020.jpg");" id="ibu_4"><span class="place_blind">업체</span></div>
</a></div>
</div>
<div class="CEX4u">
<div class="fNygA"><a href="#" target="_self" role="button" class="place_thumb QX0J7">
<div class="K0PDV _div" style="width: 100%; height: 100%; background-position: 50% 0px; background-image: url("https://search.pstatic.net/common/?autoRotate=true&type=w278_sharpen&src=https%3A%2F%2Fldb-phinf.pstatic.net%2F20231216_67%2F17027161665024joxF_JPEG%2FIMG_20231203_165411_362.jpg");" id="ibu_5"><span class="place_blind">업체</span></div><span class="xez5V"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" class="rReOU">
<path d="M12.1 4.7c0 .6-.4 1-1 1s-1-.4-1-1 .4-1 1-1 1 .5 1 1zm-2.5 7.2l2.6-2.6 2.1 2.1V9.6l-2.1-2.1-2.6 2.6-3.7-3.8-4.2 4.2v1.8l4.2-4.2 3.7 3.8zM13 .4H3C1.5.4.4 1.5.4 3v10c0 1.5 1.2 2.7 2.6 2.7h10c1.5 0 2.7-1.2 2.7-2.7V3c0-1.5-1.2-2.6-2.7-2.6zm0 13.9H3c-.7 0-1.4-.6-1.4-1.3V3c0-.7.6-1.4 1.4-1.4h10c.7 0 1.3.6 1.3 1.4v10c0 .7-.6 1.3-1.3 1.3z"></path>
</svg><span class="place_blind">이미지 갯수</span>+182</span>
</a></div>
</div>
</div>
</div>
</div>
K0PDV _div라는 class의 style속성안에 url이 있으니까K0PDV _div class가 감싸는 태그만 있어도 충분 할 것 같다.
// 이미지 url 5개 가져오기
List<WebElement> imageElements = driver.findElements(By.cssSelector("div.K0PDV._div"));
for (WebElement imageElement : imageElements) {
String styleAttribute = imageElement.getAttribute("style");
// 스타일 속성에서 URL 추출
String imageUrl = extractImageUrlFromStyleAttribute(styleAttribute);
System.out.println("Image URL: " + imageUrl);
}
// 스타일 속성에서 이미지 URL 추출하는 메서드
private String extractImageUrlFromStyleAttribute(String styleAttribute) {
String imageUrl = "";
if (styleAttribute != null && styleAttribute.contains("background-image: url(")) {
int startIndex = styleAttribute.indexOf("url(") + 4;
int endIndex = styleAttribute.indexOf(")", startIndex);
imageUrl = styleAttribute.substring(startIndex, endIndex).replaceAll("'", "").replaceAll("\"", "");
}
return imageUrl;
}
크롤링이 시작되면,
위의 로직이 실행되어 style 요소에서 이미지의 url만 파싱 -> 추출을 하고
추출한 값을 문자열 변수에 담아
다른 카페의 정보들과 함께 콘솔에 출력한다. 성공!