2024-03-12 (63일차) - 카페 이미지 크롤링하기

·2024년 3월 12일

프로젝트

목록 보기
26/57

📅 2024-03-12, 63일차


네이버지도 카페 대표이미지 url 크롤링

나의 요구사항

카페(업체) 대표사진들의 url을 크롤링해와야 함.

문제상황

카페 이미지url 크롤링 로직을 기존 로직 안에 추가 한 이후로
네이버 지도의 검색결과인 n개의 카페의 데이터를 크롤링해오지 못하고
오직 하나의 카페의 데이터만 크롤링한 후 NoSuchElementException 에러 발생.
(이미지url크롤링 로직 추가 전에는 n개의 카페들의 정보를 모두 크롤링 해올 수 있었다)

NoSuchElementException

  • 해당 요소를 찾지 못함
    • 웹페이지가 예상대로 로드되지 않았을 가능성
    • (가능성 있음) 왜?
      • 셀레늄으로 데이터를 가져오는데 시간이 오래걸린다.
      • 그래서 셀레늄에서는 웹 요소가 로드되기를 기다리는 다양한 대기 방법을 제공한다.
      - Thread.sleep() 메서드는 일정한 시간 동안 프로그램을 일시적으로 멈춰서 크롤링이나 웹 페이지의 로딩이 완료되기를 기다릴 수 있습니다.
       - Fluent Wait는 Explicit Wait와 유사하지만, 조건을 만족할 때까지 주기적으로 대기하는 동안 일정한 주기로 또는 특정 예외가 발생할 때까지 대기할 수 있습니다.
       - WebDriverWait를 사용하면 특정 조건이 충족될 때까지 대기할 수 있습니다. 이를 통해 웹 요소의 가시성, 클릭 가능성, 존재 여부 등을 기다릴 수 있습니다.
    • 요소가 변경 되었을 가능성
    • (가능성 없음) 왜?
      • 이미지url 크롤링 로직을 사용하지 않으면 카페의 정보들은 사실상 제대로 가지고 온다. 즉, 요소가 변경되었을리가 없다.

원인이 뭘까?

추측 1

  1. 실행하면 하나의 카페의 정보만 나오고 그 다음 카페들의 데이터는 안나오는 오류가 생김.
  2. 혹시 네이버지도 검색 결과 frame에서 상세정보 frame으로 이동하여 크롤링 한 후 두번째 검색결과인 카페를 선택하기위한 이전 frame으로 되돌아가는 행위를 하지 못해서 그런거 아닐까?
  3. 검색결과 frame <---> 선택한 카페의 상세정보 frame 간 왔다 갔다 잘 되야 할 것 같은데..
  4. 이게 되지 않으니까 첫번째 카페의 데이터들만 크롤링하는 것 아닌가?
    결론: 하나의 카페 데이터를 크롤링 한 후 최초의 frame으로 되돌아가서 그 다음 카페를 선택 후 두번째 frame으로 이동하여 선택자를 찾아보자!

시도해본 방법

  • 프레임 간 이동 후에 기본 컨텐츠(최초의 frame)로 다시 전환하지 않은 것을 문제의 원인으로 보고, WebDriver는 두번째 frame 안에서만 요소를 찾으려고 시도하기 때문에 최초의 frame에서 다른 카페의 요소를 찾을 수 없게 된다.
    따라서 각 카페의 정보를 크롤링한 후에는 driver.switchTo().defaultContent();를 사용하여 기본 컨텐츠로 전환해보자.
    해결 안됨.

시간을 거슬러 올라가보기로 함.

추측 2

  1. 이미지url을 크롤링해오는 로직을 추가 하기 전에는 잘 가지고 왔다
  2. 이미지url을 크롤링해오는 로직이 추가되면서 이런 에러가 발생했다.
  3. 그럼 애초에 이미지 url을 크롤링해오는 로직에서 잘못된 것 아닐까?
    결론: 기존 이미지 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 오류는 배열의 인덱스를 벗어나는 값에 접근하려고 할 때 발생함

오랜만에 만난 ArrayIndexOutOfBoundsException.

추측 3

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(&quot;&quot;);" 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(&quot;https://search.pstatic.net/common/?autoRotate=true&amp;type=w278_sharpen&amp;src=https%3A%2F%2Fldb-phinf.pstatic.net%2F20231216_153%2F1702716167403SgcbV_JPEG%2FIMG_20231214_162649_658.jpg&quot;);" 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(&quot;https://search.pstatic.net/common/?autoRotate=true&amp;type=w278_sharpen&amp;src=https%3A%2F%2Fldb-phinf.pstatic.net%2F20231216_258%2F1702716166842xW2oR_JPEG%2FIMG_20231128_121415_474.jpg&quot;);" 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(&quot;https://search.pstatic.net/common/?autoRotate=true&amp;type=w278_sharpen&amp;src=https%3A%2F%2Fldb-phinf.pstatic.net%2F20231216_104%2F1702716165793ODV8U_JPEG%2F20231122_141020.jpg&quot;);" 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(&quot;https://search.pstatic.net/common/?autoRotate=true&amp;type=w278_sharpen&amp;src=https%3A%2F%2Fldb-phinf.pstatic.net%2F20231216_67%2F17027161665024joxF_JPEG%2FIMG_20231203_165411_362.jpg&quot;);" 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>
  1. 이미지의 url이 우리가 알던 img src 태그 안에 있는 것이 아니라
    style 속성 안에 있고 style 속성에서 url을 뽑아내야 한다.
  2. 잘 보면, 공통적으로 K0PDV _div라는 class의 style속성안에 url이 있으니까
    K0PDV _div class가 감싸는 태그만 있어도 충분 할 것 같다.
  3. 이 class 태그를 gpt한테 줘서, style 속성에서 이미지 url만 추출하는 메서드를 만든다.
  4. url 추출 -> 파싱 하는 메서드 만들어서 리턴받은 url을 보여주는 로직

// 이미지 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만 파싱 -> 추출을 하고
추출한 값을 문자열 변수에 담아
다른 카페의 정보들과 함께 콘솔에 출력한다. 성공!

  • 아직 나에게 남아있는 문제: 10개의 카페만 크롤링 함
profile
hello world

0개의 댓글