네이버 위성지도 캡쳐 자동화

소개

부동산 관련 업무상 네이버 지도와 호갱노노 등 지도나 거래사례 등 단순 캡쳐를 반복적(대략 100건 이상)으로하는 작업이 필요합니다.

이에 따라 단순 반복작업인 캡쳐 작업을 vba와 파이썬을 통해 자동화 해보고자 하였습니다.

진행은 claude 와 함께 하였습니다.

진행 방법

  1. 엑셀에서 평가건별 시트복사

    제일 먼저 평가건별 시트복사를 위해 아래와 같은 주소 목록을 준비합니다

    한국어 이름과 숫자가 적힌 스프레드시트

그리고 아래와 같이 프롬프트를 작성했습니다.

엑셀에서 아래목록의 이름을 가진 시트명으로 계속해서 MOA-001 시트의 내용을 복사해서 목록의 갯수만큼 시트를 추가하고 싶은데 어떻게 하면 좋을까?
복사된 각 셀의 b1에는 'sumry'시트의 c열에 있는 '차주번호'가 순서대로 기입되고
복사된 각 셀의 b2에는 'sumry'시트의 d열에 있는 'Property일련번호'가 순서대로 기입되어야해
[clade] 이 작업을 수행하기 위한 Excel VBA 매크로 코드를 작성해드리겠습니다.

[사용 동영상]

https://youtu.be/SFntRG9TckI

  1. 위성지도에서 지도를 캡쳐하기 위한 파이썬 구동

    프롬프트 : 네이버 맵에서 엑셀목록의 주소를 가져와서 검색하고 그걸 위성지도로 변경해서 캡쳐해서 엑셀의 시트마다 분리해서 넣고 싶어

[claude - 파이썬 코드]

import time
import os
import pandas as pd
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from openpyxl import Workbook
from openpyxl.drawing.image import Image as OpenpyxlImage
from PIL import Image as PILImage
from datetime import datetime

# 엑셀 파일 경로 설정
input_excel = R"C:\Users\Rokim\OneDrive\파일이름.xlsx"
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
output_excel = f"output_with_maps_{timestamp}.xlsx"

# 새로운 네이버 지도 URL
NAVER_MAP_URL = "https://map.naver.com/p"

# ChromeDriver 설정
driver_path = R"C:\Users\Rokim\.wdm\drivers\chromedriver\win64\130.0.6723.93\chromedriver-win32\chromedriver.exe"
options = webdriver.ChromeOptions()
options.add_argument("--start-maximized")
options.add_experimental_option('excludeSwitches', ['enable-logging'])
service = Service(driver_path)
driver = webdriver.Chrome(service=service, options=options)
wait = WebDriverWait(driver, 20)

# 엑셀 파일 로드
data = pd.read_excel(input_excel)
addresses = data['주소']

# 캡처 저장 폴더 생성
capture_folder = "captures"
os.makedirs(capture_folder, exist_ok=True)

def wait_and_find_element(driver, by, value, timeout=20):
    """요소를 찾을 때까지 대기하는 함수"""
    try:
        element = WebDriverWait(driver, timeout).until(
            EC.presence_of_element_located((by, value))
        )
        return element
    except Exception as e:
        print(f"요소를 찾지 못했습니다: {value}")
        print(f"에러: {e}")
        return None

# 네이버 지도에서 주소 검색 및 캡처
for idx, address in enumerate(addresses):
    try:
        # 네이버 지도 접속
        driver.get(NAVER_MAP_URL)
        print(f"\n{address} 처리 시작...")
        time.sleep(0.7)
        
        # 검색창 찾기 및 검색
        search_box = wait_and_find_element(driver, By.CSS_SELECTOR, "input.input_search")
        if not search_box:
            search_box = wait_and_find_element(driver, By.CSS_SELECTOR, "input[placeholder*='주소']")
        
        if search_box:
            search_box.clear()
            search_box.send_keys(address)
            search_box.send_keys(Keys.RETURN)
            print("주소 검색 완료")
            time.sleep(0.7)
        else:
            print("검색창을 찾지 못했습니다.")
            continue
        
        # 위성지도 버튼 찾기 시도 (여러 방법)
        satellite_found = False
        
        # 1. 클래스로 찾기
        try:
            buttons = driver.find_elements(By.CSS_SELECTOR, "button.sc-xgpg6k")
            for button in buttons:
                if "위성" in button.text:
                    button.click()
                    satellite_found = True
                    print("위성지도 버튼 클릭 완료 (방법 1)")
                    break
        except Exception as e:
            print(f"방법 1 실패: {e}")
        
        # 2. XPath로 찾기
        if not satellite_found:
            try:
                satellite_button = driver.find_element(
                    By.XPATH, "//*[contains(text(), '위성')]//ancestor::button")
                satellite_button.click()
                satellite_found = True
                print("위성지도 버튼 클릭 완료 (방법 2)")
            except Exception as e:
                print(f"방법 2 실패: {e}")
        
        # 3. 모든 버튼 검색
        if not satellite_found:
            try:
                buttons = driver.find_elements(By.TAG_NAME, "button")
                for button in buttons:
                    try:
                        if "위성" in button.text:
                            button.click()
                            satellite_found = True
                            print("위성지도 버튼 클릭 완료 (방법 3)")
                            break
                    except:
                        continue
            except Exception as e:
                print(f"방법 3 실패: {e}")
        
        time.sleep(0.7)  # 위성지도 로딩 대기
        
        # 캡처 저장
        capture_path = os.path.join(capture_folder, f"capture_{idx + 1}.png")
        driver.save_screenshot(capture_path)
        
        # 이미지 크기 조정
        img = PILImage.open(capture_path)
        img = img.resize((800, 600))
        img.save(capture_path)
        
        print(f"'{address}' 처리 완료\n")
        time.sleep(0.7)  # 다음 주소 처리 전 대기
        
    except Exception as e:
        print(f"주소 '{address}' 처리 중 오류 발생: {e}")
        continue

# Selenium 종료
driver.quit()

# 캡처 이미지 엑셀에 삽입
wb = Workbook()
for idx, address in enumerate(addresses):
    sheet_name = f"Sheet_{idx + 1}"
    ws = wb.create_sheet(sheet_name)
    
    ws["A1"] = "주소"
    ws["B1"] = address
    
    capture_path = os.path.join(capture_folder, f"capture_{idx + 1}.png")
    if os.path.exists(capture_path):
        img = OpenpyxlImage(capture_path)
        img.anchor = "A3"
        ws.add_image(img)
    else:
        print(f"이미지를 찾을 수 없습니다: {capture_path}")

# 기본 시트 제거
if 'Sheet' in wb.sheetnames:
    wb.remove(wb['Sheet'])

# 결과 저장
wb.save(output_excel)
print(f"\n엑셀 파일이 저장되었습니다: {output_excel}")

아래와 같이 지도가 캡쳐되었습니다.

도시의 위치를 ​​보여주는 Google 지도

문제가 생깁니다. 지도가 확대가 안되서 너무 작게 보입니다.

                # 줌 레벨 조정
                try:
                    # 줌 인 버튼 찾기
                    zoom_in_button = wait_and_find_element(
                        driver, 
                        By.CSS_SELECTOR, 
                        "button[class*='zoom_in']"
                    )
                    # 3번 확대 (클릭)
                    if zoom_in_button:
                        for _ in range(3):
                            zoom_in_button.click()
                            time.sleep(0.5)
                        print("지도 확대 완료")
                except Exception as e:
                    print(f"지도 확대 실패: {e}")

지도 확대를 요청해서 줌을 3번 댕긴후에 캡쳐해봤습니다.

건물의 위치를 ​​나타내는 지도

너무 큰 것 같아서 2번 확대하는 걸로 변경해보겠습니다.

                    if zoom_in_button:
                        for _ in range(2):
                            zoom_in_button.click()
                            time.sleep(0.5)
                        print("지도 확대 완료")
도시에 있는 건물의 위치를 ​​보여주는 지도

2번 줌 하니 딱 좋습니다.

Google 어스 지도의 스크린샷

엑셀에 위와 같이 시트별로 정리가 됩니다.

근데 gui로 바뀌면서 기존에는 크롬을 열어서 캡쳐하는 과정이 하나씩 다 보였었는데

해당 과정이 보이지 않게 되었습니다. 이를 cursor에게 다시 질문해보았습니다.

한국어 한국어 한국어 한국어 한국어 한국어 한국어 한국어
화면에 한국어가 표시됩니다
코드 편집기의 스크린샷

여기에서 options.add_argument('--headless ') 이 부분을 삭제하면 기존처럼 작업하는 과정이 보인다고 합니다.

그래서 파일 만드는 중에는 보이게 하고 완성이 된 이후에는 headless 를 삽입하면 좋을듯 합니다.

엑셀 시트를 보니 화면에 흰색 주소 검색창과 밑에 광고가 나옵니다.

  1. 흰색부분을 자르기 위하여 클로드에게 요청하였습니다.

[프롬프트]정해진 엑셀파일에서 이미지를 뽑아와서 특정부분만 잘라내서 이미지로 저장해줘

from openpyxl import load_workbook
from PIL import Image as PILImage
import os
from datetime import datetime
from io import BytesIO

# 정해진 엑셀파일에서 이미지를 뽑아와서 특정부분만 잘라내서 이미지로 저장하는 프로그램

def process_excel_images(excel_file, base_output_dir, crop_box=None, new_size=None):
    """
    엑셀 파일의 모든 시트에서 이미지를 추출하고 처리합니다.
    """
    try:
        # 현재 날짜와 시간으로 폴더명 생성
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        output_dir = os.path.join(base_output_dir, f"processed_images_{timestamp}")
        
        # 출력 디렉토리 생성
        os.makedirs(output_dir, exist_ok=True)
        print(f"\n출력 폴더 생성됨: {output_dir}")
        
        # 엑셀 워크북 로드
        wb = load_workbook(excel_file)
        
        processed_count = 0
        for sheet_name in wb.sheetnames:
            ws = wb[sheet_name]
            print(f"\n처리 중: {sheet_name}")
            
            # 시트별 이미지 처리
            for image_idx, image in enumerate(ws._images):
                try:
                    # 이미지 데이터 가져오기
                    image_bytes = image.ref.getvalue()
                    
                    # BytesIO로 이미지 열기
                    with BytesIO(image_bytes) as bio:
                        with PILImage.open(bio) as img:
                            # 이미지 자르기
                            if crop_box:
                                img = img.crop(crop_box)
                            
                            # 이미지 크기 조정
                            if new_size:
                                img = img.resize(new_size, PILImage.LANCZOS)
                            
                            # 처리된 이미지 저장
                            output_path = os.path.join(output_dir, f'{sheet_name}_image_{image_idx}.png')
                            img.save(output_path, 'PNG')
                            processed_count += 1
                            print(f"이미지 저장됨: {output_path}")
                    
                except Exception as e:
                    print(f"이미지 {sheet_name}_image_{image_idx} 처리 중 오류 발생: {str(e)}")
                    # 디버깅을 위한 추가 정보 출력
                    print(f"이미지 타입: {type(image.ref)}")
                    continue
        
        return f"처리 완료: {processed_count}개의 이미지가 {output_dir}에 저장되었습니다."
    
    except Exception as e:
        print(f"오류 발생: {str(e)}")
        return str(e)

if __name__ == "__main__":
    # 현재 스크립트 파일의 디렉토리 확인
    current_dir = os.path.dirname(os.path.abspath(__file__))
    
    # 파일 경로 설정
    excel_file = os.path.join(current_dir, "output_with_maps_20241118_181359.xlsx")
    base_output_dir = current_dir
    
    # 이미지 처리 실행
    result = process_excel_images(
        excel_file=excel_file,
        base_output_dir=base_output_dir,
        crop_box=(200, 0, 800, 600),  # 왼쪽 메뉴 부분을 제외하고 지도만 남김
        new_size=None  # 크기는 그대로 유지
    )
    print(result)

잘려서 잘 보입니다.

gui 로 보면 아래와 같습니다.

  1. 엑셀에서 해당 이미지를 각 시트의 특정 셀로 이동하기

여러 개의 숫자가 적힌 종이 한 장

목록 시트에서 지도를 순서대로 가져옵니다.

Microsoft Excel의 지도 스크린샷

각 시트의 해당 셀로 잘 이동한 것이 보입니다.

결과와 배운 점

글이 너무 길어져 전부다 설명드리진 못했지만 절차는 순서대로

  1. 네이버 지도상의 위성사진을 캡쳐합니다. - 성공

  2. 엑셀 시트별로 캡쳐된 사진의 왼쪽 흰색부분이 지도가 아니라서 그부분을 컷팅하여 이미지 파일로 저장

  3. 엑셀에서 이미지 파일 불러와서 각 이미지를 순서대로 엑셀시트에 갖다붙이기

이렇게 3단계를 거칩니다.

현재 아쉬운 점은 지도상 줌 레벨 설정이 안되어 있고

위의 절차들이 각자의 파이썬 파일로 실행되어 중간에 수작업이 필요합니다.

이를 하나의 파일로 완성하여 주소 목록만 넣으면 위의 3단계를 한번에 처리할 수 있도록 시도해볼 예정입니다.

추가로 네이버 지도 뿐만 아니라 호갱노노 및 지지옥션 등에서 여러 조건값을 만족시키는 캡쳐도 필요해서 추가적으로 작업해볼 예정입니다.

도움 받은 글 (옵션)

참고한 지피터스 글이나 외부 사례를 알려주세요.

https://boringariel.tistory.com/67

https://baka9131.tistory.com/14

3
4개의 답글

👉 이 게시글도 읽어보세요