티스토리 뷰

원래 목적은 AI agent에게 사람이 하는 것과 같은 방법으로 자료를 조사하고, 원하는 카페를 찾게하기 위해 selenium을 이용해 동적 크롤링을 해보았다.

그런데 정적 크롤링과 달리 하나씩 직접 클릭하며 자료를 얻다 보니 생각보다 시간이 오래 걸려 방법을 바꿔야하지 않나 고민중이다.

 

전에 selenuim을 이용해 크롤링을 했을때는 chromdriver를 크롬 버전에 맞게 따로 설치를 했었는데, 이제는 cmd에 간단히 명령어 입력으로 사용할 수 있었다.

pip install webdriver-manager

 

네이버 지도 api로는 리뷰를 가져올 수 없어 직접 크롤링을 해보았다. 네이버 지도의 경우 iframe을 통해 하나의 웹브라우저 안에 여러개의 html 파일이 중첩되어있는 구조였다. 카페의 이름을 클릭하면 가게의 상세페이지가 들어있는 새로운 iframe이 추가되는데, iframe안에 iframe이 생기는게 아닌, 병렬적으로 추가되었다. 그래서 iframe을 초기화하고 다시 전환을 해줘야 했다. 

 

* iframe이란?

- HTML 문서 내에서 다른 HTML 문서를 삽입할 수 있는 요소

- 웹 페이지 안에 또 다른 웹 페이지를 포함할 수 있게 해주는 HTML 태그

 

 

또 다음 명령어를 실행하기 전에는 time.sleep()을 이용해 데이터가 들어올 때까지 기다려야 했는데, WebDriverWait을 이용해 구현할 수 있엇다.

def naver_place_tool():
    """
    네이버 지도에서 사용자 요청에 맞는 카페를 찾고, 카페의 특징과 분위기, 시그니처 메뉴를 분석하기 위해 사진과 최신 리뷰를 수집
    """
    cafe_info = {}
    # 크롬 드라이버 설정
    options = webdriver.ChromeOptions()
    options.add_experimental_option("detach", True)  # 창이 자동으로 닫히지 않게 설정
    driver = webdriver.Chrome(options=options)

    # 네이버 지도 접속
    url = "https://map.naver.com/v5/search"
    driver.get(url)

    # 검색창 요소 찾기 (WebDriverWait 사용)
    search_box = WebDriverWait(driver, 10).until(
        EC.presence_of_element_located((By.CLASS_NAME, "input_search"))
    )

    # 검색어 입력
    search_box.send_keys("강릉 오션뷰 카페")

    # 검색 실행 (ENTER 키)
    search_box.send_keys(Keys.ENTER)


    # `searchIframe`으로 전환
    try:
        WebDriverWait(driver, 10).until(
            EC.frame_to_be_available_and_switch_to_it((By.ID, "searchIframe"))
        )
    except:
        print("searchIframe을 찾을 수 없음")
        driver.quit()
        exit()

    # 검색 결과 요소 가져오기 (결과가 여러 개일 수도 있으므로 `find_elements` 사용)
    try:
        cafe_list = WebDriverWait(driver, 10).until(
            EC.presence_of_all_elements_located((By.CLASS_NAME, "TYaxT"))
        )
        print(f"{len(cafe_list)}개의 카페를 찾았습니다.")
    except:
        print("cafe_list를 찾을 수 없음")
        driver.quit()
        exit()

    if cafe_list:
        for i in range(7):
            cafe_name = cafe_list[i].text.strip()
            cafe_info[cafe_name] = {"reviews": [], "images": []}  

            cafe_list[i].click()
            driver.switch_to.default_content()

            WebDriverWait(driver, 10).until(
                EC.frame_to_be_available_and_switch_to_it((By.ID, "entryIframe"))
            )
            try:
                # 리뷰 버튼 찾고 클릭
                WebDriverWait(driver, 10).until(
                    EC.element_to_be_clickable((By.XPATH, "//span[text()='리뷰']"))
                ).click()

                # 리뷰 나타날때까지 기다렸다가 스크롤
                time.sleep(2)
                driver.execute_script("window.scrollBy(0, window.innerHeight);")

                # 최신순 버튼 찾고 클릭
                WebDriverWait(driver, 10).until(
                    EC.element_to_be_clickable((By.XPATH, "//a[text()='최신순']"))
                ).click()

                # 최신 리뷰 기다렸다가 크롤링
                time.sleep(2)
                review_list = WebDriverWait(driver, 10).until(
                    EC.presence_of_all_elements_located((By.XPATH, "//div[@class='pui__vn15t2']/a"))
                )

                # 최신 리뷰 10개
                for idx, review in enumerate(review_list):
                    review_text = review.text  # 리뷰 텍스트 가져오기
                    if review_text != "더보기":
                        cafe_info[cafe_name]["reviews"].append(review_text) 

                image_list = WebDriverWait(driver, 10).until(
                    EC.presence_of_all_elements_located((By.XPATH, "//a[@class='place_thumb']/img"))
                )

                # 이미지 10개
                for idx, img in enumerate(image_list):
                    img_url = img.get_attribute("src")  # 이미지 URL 가져오기
                    cafe_info[cafe_name]["images"].append(img_url) 

                driver.switch_to.default_content()
                WebDriverWait(driver, 10).until(
                    EC.frame_to_be_available_and_switch_to_it((By.ID, "searchIframe"))
                )
            except:
                print("리뷰 버튼이 없습니다.")

    result = json.dumps(cafe_info, ensure_ascii=False, indent=4)
    print(result)
    return result

 

 

 

반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/02   »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28
글 보관함