2주차 Cursor 스터디 - 네이버부동산 서울시 25개구 아파트 전체 단지목록 추출하기

2주차 Cursor 스터디 주제는 뉴스 크롤링이었습니다.

필군님께서 하나하나 꼼꼼하게 설명해 주셔서, 2주차는 따라가는 데 큰 어려움 없이 진행할 수 있었어요.

이번 스터디에서는 SK하이닉스 뉴스 기사를 네이버에서 가져오는 실습을 했습니다.

개발자 도구에서 Element와 Selector를 복사해서 기사 내용을 가져오고, 또 화면에 보이지 않는 영역까지 스크롤하면서 데이터를 수집하는 방법을 배웠습니다.

뉴스 기사 크롤링에 익숙해진 후에는, 이를 응용해서 환율 관련 기사도 검색, 수집해 보았습니다.

조금 더 심화된 단계로는 네이버 뉴스스탠드의 연합뉴스 페이지에서 스크롤 과정을 두 번 반복해 여러 뉴스를 가져오는 실습도 했고, 페이지가 나누어져 있는 경우에는 어떻게 크롤링해야 하는지도 함께 익혔습니다.

스터디 마지막에는 조원분 중 한 분이 한방부동산에서 중개사 정보를 어떻게 가져올 수 있는지 질문을 주셨고, 필군님께서 역시 친절하게 하나하나 방법을 설명해 주셨습니다.

이 내용을 들으면서 “그럼 나는 네이버 부동산에서 아파트 단지 목록을 한번 추출해 볼까?” 라는 생각이 들어, 개인 실습 과제로 잡게 되었습니다.

네이버 아파트 단지목록 구조 파악하기

먼저 서울시 법정동 목록이 필요해서 자료를 찾아보고, 네이버 부동산 모바일 페이지로 이동해 ‘성동구만 보기’를 눌러 아래와 같은 화면을 띄웠습니다.

한국의 어느 도시의 위치를 ​​보여주는 지도

지도를 조금 더 확대하고, 오른쪽 아래에 있는 [단지 목록] 버튼을 누르면 성동구의 아파트 단지 목록이 나타납니다. 성동구에는 총 199개의 단지가 있는 것을 확인할 수 있었습니다.

한국의 어느 도시의 위치를 ​​보여주는 지도

네트워크 패널로 API 구조 파악하기

이제부터는 크롤링을 위해 네이버 부동산이 데이터를 어떻게 받아오는지를 확인했습니다.

크롬 개발자 도구에서 Network 탭을 열어두고 단지 목록을 스크롤하면, 스크롤할 때마다 어떤 요청이 나가는지 확인할 수 있습니다.

도시 지도를 보여주는 웹 브라우저의 스크린샷

각 리스트 항목을 클릭해보면 Request URL이 보이는데, 이게 바로 네이버에 “해당 단지 정보를 보내줘”라고 요청하는 주소입니다.

여러 이미지를 보여주는 웹 브라우저의 스크린샷

이 URL을 복사해서 브라우저 주소창에 붙여넣고 열어보면, 아파트 단지에 대한 상세 정보들이 JSON 형태로 내려오는 것을 확인할 수 있습니다.

여러 숫자를 보여주는 컴퓨터 화면의 스크린샷

여기까지 확인하고 나니 “그럼 이 구조를 활용해서 서울시 전체 아파트 단지 목록을 크롤링해볼 수 있겠다” 는 생각이 들었습니다.

전체적인 흐름을 기획하기 전에, 먼저 ChatGPT에게 크롤링 플로우를 어떻게 잡으면 좋을지 물어보았습니다.

한국어로 된 메시지 스크린샷
한국어 웹사이트 스크린샷

답변을 보니, 국토교통부 공동주택 정보를 활용하는 방법을 제안해 주더라고요. 그래서 실제로 국토부 공동주택 정보를 내려받아 보았습니다.

그 데이터를 보니, 네이버 부동산에서 구와 법정동을 선택했을 때 뒤에 붙는 법정동 코드
국토부 자료에 있는 코드가 일치하는 것을 확인했습니다.

그래서 다운받은 법정동 정보를 엑셀 파일로 정리한 뒤, 이를 읽어와서 해당 구의 단지 목록을 자동으로 가져오는 방식으로 구조를 설계했습니다.

Selenium에서 API 호출 방식으로 전환

처음에는 하나하나를 Selenium으로 직접 가져오는 방식으로 시도했습니다. 하지만 이 방식은 효율도 떨어지고, 에러도 자주 발생하더라고요.

그래서 방향을 바꿔, 앞에서 확인한 API Request URL을 직접 호출해서 데이터를 가져오는 방식으로 변경했습니다.

네이버 부동산 구조를 이해하는 데에는 아래 유튜브 영상이 큰 도움이 되었습니다.

https://www.youtube.com/watch?v=Kaa_W0HRB-M&t=696s

단지 목록을 스크롤하면, 화면에는 보이지 않지만 요청 URL 뒤에 &page=1, &page=2 … 이런 식으로 페이지 번호가 붙으면서 호출되는 구조라는 걸 알 수 있습니다.

한 페이지에 20개의 단지 정보가 담겨 있고, 이를 바탕으로 page 파라미터를 늘려가며 반복 요청을 보내면 한 구의 전체 단지 목록을 모두 가져올 수 있다는 결론에 도달했습니다.

서초구가 단지 수가 많은 편이라 테스트 삼아 **최대 page=20 (약 400단지)**까지 가져오는 방식으로 구현해 보았습니다.

네이버에서 차단 이슈 → 법정동 단위로 분할 요청

구 단위로 한 번에 단지 목록을 가져오다 보니, 단지 수가 많은 구를 연속으로 3개 정도 요청하면
네이버 부동산에서 차단에 가까운 반응
을 보이는 것을 발견했습니다.

그래서 전략을 수정했습니다.

  • “구 단위”가 아니라

  • 법정동 단위로 잘게 나눠서 요청하도록 구조를 바꾸고,

  • 각 동별로 단지 목록을 가져온 뒤

  • 이를 다시 하나로 합치는 방식으로 코드를 리팩터링했습니다.

몇 시간의 시행착오 끝에 완성한 GUI 크롤러

몇 시간 정도 삽질(?)을 한 끝에, 아래와 같이 GUI 형태의 크롤러를 완성했습니다. 이제는 원하는 구를 선택해서 해당 구의 단지 목록을 한 번에 엑셀로 내려받을 수 있습니다.

한국어 텍스트가 표시된 컴퓨터 화면의 스크린샷

한국어 텍스트가 표시된 컴퓨터 화면의 스크린샷

한자 숫자가 많은 테이블

코드 구조 정리 (Cursor ASK 요약)

1️⃣ 데이터 정의 (20~525줄)

  • SEOUL_DISTRICTS_BY_GRADE – 서울 25개 구를 1~5급지로 분류

  • SEOUL_DISTRICTS – 전체 구 목록 (검색용)

  • SEOUL_DONG_CODES – 각 구의 법정동 코드 딕셔너리 (하드코딩)

2️⃣ 크롤링 핵심 함수 (528~636줄)

  • get_dong_list_by_district() – 구 이름으로 동 목록 조회

  • fetch_complex_list_by_dong() – 동 1개 크롤링 (최대 20페이지)

  • fetch_complex_list_by_district() – 구 전체 크롤링 (동별 순회)

3️⃣ 데이터 처리 함수 (533~694줄)

  • clean_html_tags() – HTML 태그 제거

  • parse_complex_data() – API 응답을 DataFrame용 딕셔너리로 변환

  • save_to_excel() – 엑셀 파일 저장 + 자동 필터/열 너비 조정

4️⃣ GUI 클래스 (697~910줄)

  • CrawlerGUI

    • create_widgets() – 급지별 라디오 버튼, 로그창, 진행바 생성

    • start_crawling() – 버튼 클릭 시 별도 스레드로 실행

    • crawl_thread() – 실제 크롤링 로직 (비동기 처리)

    • log_message() – 진행 상황 로그 출력

전체 흐름은 다음과 같습니다.

사용자가 GUI에서 구 선택
[크롤링 시작] 버튼 클릭
→ 별도 스레드에서 crawl_thread() 실행
→ 선택한 구의 모든 법정동을 순회
→ 각 동마다 fetch_complex_list_by_dong() 호출 (최대 20페이지)
→ 중복 제거하며 단지 목록 수집
parse_complex_data()로 데이터 정리
save_to_excel()로 엑셀 저장
→ 완료 메시지 표시

이번 실습에서 배운 점 & 느낀 점

  • 처음엔 Selenium만 쓰다가 에러도 많고 속도도 느렸는데, 네이버 부동산의 HTML 구조를 이해하고 보니, 화면을 조작하기보다 API를 직접 호출하는 게 훨씬 단순하고 안정적하다는 걸 알게 됨.

  • Cursor는 결국 내가 시키는 대로만 움직이는 도구라서,일을 맡길 때 정확하고 구체적으로 지시하는 게 중요하다는 걸 느낌. 코드 수정도 방향성을 내가 먼저 잘 잡고, 필요한 부분을 잘라서 명확히 지시하는 능력이 정말 중요하다는 걸 깨달았음.

2
3개의 답글

👉 이 게시글도 읽어보세요