도시아재
도시아재
🗡️ AI 레전드
🚀 SNS 챌린지 달성자
🏅 베스트오브베스트

네이버 부동산 매물 195건을 엑셀로 — 429 차단을 뚫은 하루의 기록

※ 이 내용은 네이버 부동산 관계자가 매우 싫어하실 수 있습니다.
교육차원에서 시도해 본 것이니 너그러이 용서 바랍니다.

소개

안녕하세요. 서울에서 복덕방 운영하고 있는 도시아재 입니다.

Copy as cURL → AI에게 코딩 요청 → 엑셀 흐름으로 네이버 부동산 매물 수집기를 만들어 쓰고 있었습니다. 처음엔 IDE에서 단발성 스크립트로 돌렸는데, 매번 다시 만드는 게 번거로워 Claude Code 기반 프로젝트로 옮겨 관리하고 있었죠.

그런데 어느 순간부터 429 에러가 뜨면서 수집이 전혀 안 되기 시작했습니다.

이런 경우 보통 이렇게들 설명합니다.

네이버는 봇으로 의심되면 차단(429)합니다. cURL 안의 쿠키·토큰이 "나는 봇이 아니다"라는 증명입니다.
어제 되던 게 오늘 안 됨 = 토큰 만료.

그래서 알려진 대로 다 해봤는데도 안 됐습니다. 이 글은 왜 안 됐는지 알아내는 과정과, 결국 어떻게 뚫었는지에 대한 기록입니다.

같은 벽에 부딪히신 분이 계실 것 같아 공유합니다.


진행 방법

1단계. 일단 알려진 방법대로

네이버 부동산에서 조건을 잡고 조회한 뒤, F12 → Network → 매물 목록 요청을 Copy as cURL (bash) 로 복사해 파일로 저장했습니다.

📸 [이미지 1: F12 Network 탭에서 매물 요청 우클릭 → Copy → Copy as cURL (bash) 메뉴]

그리고 실행했더니:

[▶] cURL 파싱 완료 — https://new.land.naver.com/api/articles/complex/22205
    단지 22205 / 파라미터 23개 / 토큰 Bearer eyJhbGci...
[▶] 22205 조회 수집 시작 (요청 파라미터 23개)
    [!] 429 — 3초 대기 후 재시도
    [!] 429 — 6초 대기 후 재시도
    [!] 429 — 9초 대기 후 재시도
    [!] 재시도 실패 — 수집분만 저장합니다
[✔] 총 0건

2단계. 흔히 말하는 우회법을 전부 시도

차단 우회로 흔히 권장되는 방법은 크게 세 가지입니다.

  1. 실제 브라우저와 동일한 User-Agent·Accept 헤더를 붙인다

  2. 응답에서 받은 쿠키(PROP_TEST_KEY, PROP_TEST_ID 등)를 이후 요청에 실어 보낸다

  3. 차단되면 쿠키·토큰을 새로 받아 재시도한다

AI에게 이렇게 요청했습니다.

네이버 부동산 API가 429로 막혀. 브라우저와 동일한 User-Agent, Accept 헤더를
붙이고, 응답 쿠키를 파싱해서 다음 요청에 넘기는 구조로 바꿔줘.
차단되면 쿠키를 자동으로 갱신해서 재시도하게 해줘.

결과는 이랬습니다.

시도한 것

결과

토큰 새로 발급 (유효시간 3시간 중 177분 남음)

429

쿠키 새로 복사 (PROP_TEST_KEY/PROP_TEST_ID 포함)

429

로그인 → 비로그인 → 다시 로그인

429

단지 3곳으로 변경

429

70분 대기 후 재시도

429

7시간 뒤 재시도

429

"토큰 만료"가 아니었습니다. 새 토큰으로도 똑같이 막혔으니까요.

3단계. 우연히 발견한 결정적 단서

포기하기 전에 브라우저 화면을 다시 봤습니다. 그런데 Network 탭에 이렇게 찍혀 있었습니다.

1250?realEstateType=APT%3AABYG%3AJGC...page=1...   200   xhr   7.4 kB   62 ms

📸 [이미지 2: Network 탭에서 API 요청이 Status 200, Size 7.4 kB로 정상 표시된 화면]

같은 IP, 같은 쿠키, 같은 시각에 브라우저는 200을 받고 있었습니다.

이 순간 가설이 무너졌습니다. IP가 차단됐다면 브라우저도 막혔어야 하고, rate limit이라면 시간이 지나면 풀렸어야 합니다. 둘 다 아니었습니다.

💡 에러 코드가 말하는 것을 곧이곧대로 믿으면 안 됩니다.
TOO_MANY_REQUESTS라고 적혀 있어도, 실제 원인은 "요청이 너무 많아서"가 아닐 수 있습니다.
확인해야 할 건 "같은 조건에서 되는 경우가 있는가" 입니다.

4단계. 원인 추적 — 딱 한 번의 진단

브라우저와 제 코드의 차이를 좁히기로 했습니다. Claude Code에 이렇게 요청했습니다.

cURL 원본 헤더를 순서까지 그대로 재현해서 딱 1회만 요청해줘.
accept-encoding까지 포함해서. 200이면 헤더 문제 확정이고,
429면 더 깊은 층위의 문제야.

결과는 429였습니다. 헤더를 완벽히 맞춰도 막힌 겁니다.

이걸로 원인이 하나로 좁혀졌습니다.

항목

브라우저

파이썬(requests)

HTTP 버전

HTTP/2

HTTP/1.1

TLS 지문

Chrome

OpenSSL

헤더

동일

동일 (맞춰줌)

결과

200

429

💡 헤더는 요청의 내용물이고, TLS 지문은 연결 방식입니다.
흔한 우회법은 내용물만 다루는데, 네이버는 연결 방식까지 보고 있었습니다.
requestshttpx든 파이썬 HTTP 클라이언트로는 이 층위를 넘을 수 없습니다.

5단계. 해결 — 그럼 진짜 브라우저를 쓰자!

답은 의외로 가까이 있었습니다. 웹 자동화에는 보통 두 갈래가 있습니다.

  • 데이터만 필요할 때 → API 호출 (Copy as cURL)

  • 로그인·클릭·입력 같은 행동이 필요할 때 → 브라우저 자동화 (Playwright)

저는 앞쪽을 골랐고 그게 막혔으니, 뒤쪽 도구를 앞쪽 목적에 쓰면 되겠다는 생각이었습니다.

핵심 아이디어는 이겁니다.

Playwright로 단지 페이지를 연다
  → 그 페이지 안에서 fetch()로 API를 호출한다
  → 요청이 진짜 Chrome에서 나가므로 네이버가 구분할 방법이 없다

Claude Code에 이렇게 요청했습니다.

requests로는 헤더를 완벽히 맞춰도 429가 나. 브라우저는 200이고.
원인은 TLS 지문/HTTP2 차이인 것 같아.

Playwright로 단지 페이지를 열고, 그 페이지 컨텍스트 안에서
fetch()로 API를 호출하는 방식으로 수집기를 만들어줘.
- 쿠키는 cURL에서 파싱해서 브라우저에 주입
- 페이지가 발급하는 최신 토큰을 가로채서 사용
- isMoreData가 false일 때까지 자동 페이징, 요청 간격 0.8초

실행 결과:

[▶] 111964 브라우저 수집 시작 (파라미터 23개)
    [i] 페이지에서 최신 토큰을 확보해 사용합니다.
    1p: 20건 (신규 20) / 누적 20건
    2p: 20건 (신규 20) / 누적 40건
    3p: 20건 (신규 20) / 누적 60건
    4p: 20건 (신규 20) / 누적 80건
    5p: 20건 (신규 20) / 누적 100건
    6p: 20건 (신규 20) / 누적 120건
    7p: 20건 (신규 20) / 누적 140건
    8p: 20건 (신규 20) / 누적 160건
    9p: 20건 (신규 20) / 누적 180건
    10p: 15건 (신규 15) / 누적 195건
[✔] 총 195건
[💾] 엑셀 저장 → data/output/조회_단지111964_매물_20260823.xlsx

429가 완전히 사라졌습니다. 10페이지 195건을 자동으로 순회했습니다.

📸 [이미지 3: 터미널 실행 로그 — 위 텍스트로 대체]

6단계. 검증 — 우연이 아닌지 확인

한 번 됐다고 끝낼 수는 없어서, 조건을 바꿔가며 확인했습니다.

단지

페이지

건수

특징

A단지

1p

5건

소규모

B단지

4p

68건

중규모

C단지

10p

195건

대규모, 매매·전세·월세 혼재

필터 조회도 확인했습니다. 네이버 화면에서 매매 + 8억~13억 + 66~132㎡ 세 조건을 걸고 cURL을 떴더니:

195건 (필터 없음)  →  7건 (필터 적용)

조건

결과

거래방식: 매매

7건 전부 매매 (전세·월세 0건)

매매가: 8억~13억

12억 8,000 ~ 13억

면적: 66~132㎡

공급 79㎡

📸 [이미지 4: 네이버 부동산에서 매매/8억~13억/면적 필터가 적용된 화면]

화면에서 잡을 수 있는 조건은 그대로 재현됩니다.

7단계. 산출물

최종적으로 엑셀 한 파일에 7개 시트가 나옵니다.

시트

내용

매물목록

표준 29개 필드 (가격·면적·층·방향·확인방식·중개사 등)

요약

전체 통계

노출순위

광고 노출 순서

내광고순위

내 사무소 매물의 순위와 상위 %

업소별집계

업소 × 거래유형별 광고 건수, 최저·최고가, 평균 노출순위

거래유형별

매매/전세/월세 각각의 매물수·업소수·중위가

수집정보

수집 일시, 건수, 데이터 출처, 주의사항

📸 [이미지 5: 완성된 엑셀 파일의 시트 탭 7개가 보이는 화면]

📸 [이미지 6: 거래유형별 시트 — 매매/전세/월세 각각의 매물수·업소수·중위가]


결과와 배운 점

배운 점

1️⃣ 에러 메시지는 증상이지 원인이 아닙니다!

429 TOO_MANY_REQUESTS를 보고 "요청이 많아서 막혔구나 → 기다리자"고 판단했습니다. 그래서 70분을 기다렸고, 7시간 뒤에 또 시도했습니다. 전부 헛수고였습니다.

진짜 단서는 "브라우저는 되는데 내 코드만 안 된다"는 사실이었고, 이건 처음부터 확인할 수 있었습니다. 에러 코드를 믿기 전에 "되는 경우와 안 되는 경우의 차이가 뭔가"를 먼저 봤어야 했습니다.

2️⃣ 알려진 해법은 출발점이지 정답지가 아닙니다!

널리 쓰이는 우회 방법(헤더 맞추기 + 쿠키 갱신)은 한때는 통했을 것입니다. 하지만 네이버가 그 사이 탐지를 강화했고, 지금은 안 통합니다.

중요한 건 그 방법이 왜 그렇게 하라고 했는지를 이해하는 것이었습니다. "브라우저인 척하라"는 원리를 이해하니, "그럼 아예 진짜 브라우저를 쓰면 되잖아"라는 답이 나왔습니다.

3️⃣ 답은 이미 배운 것 안에 있었습니다!

Playwright는 "로그인·클릭 자동화"용으로 알고 있던 도구였습니다. 데이터 수집브라우저 자동화를 별개 영역으로 생각한 게 함정이었습니다.

두 기술을 섞으니 풀렸습니다. 배울 때 "이건 A용, 저건 B용"으로 칸막이를 치지 않는 게 좋겠습니다.

4️⃣ AI에게 "왜 안 되는지 알아내 달라"고 시키는 게 더 효과적입니다!

처음엔 "429 해결해줘"라고만 했더니, AI도 저처럼 "기다리자"는 답만 반복했습니다.

방향을 바꿔서 "브라우저는 200인데 우리는 429야. 차이를 찾아줘"라고 하니 그때부터 진짜 진단이 시작됐습니다. AI에게 결론을 요구하기 전에, 관찰한 사실을 먼저 주는 게 중요하다는 걸 배웠습니다.

5️⃣ 부수적으로 얻은 것 — 토큰 자동 갱신

브라우저로 페이지를 여는 김에, 페이지가 발급한 최신 토큰을 가로채서 쓰도록 만들었습니다. 원래 Bearer 토큰은 3시간이면 만료돼서 매번 cURL을 다시 떠야 했는데, 이제 그 부담이 줄었습니다.

시행착오

❌ 재시도가 오히려 독이었습니다

처음 코드는 429를 만나면 3초·6초·9초 간격으로 3번 재시도했습니다. 서버 오류(500번대)와 똑같이 처리한 거죠.

그런데 429는 재시도할수록 차단이 길어지는 종류입니다. 실행 한 번에 요청을 12번씩 더 보내면서 스스로 상황을 악화시키고 있었습니다.

지금은 429가 뜨면 1회 요청 후 즉시 중단하고 안내 메시지를 띄웁니다.

❌ HAR 파일은 답이 아니었습니다

429가 안 풀릴 때 "Copy all listed as HAR"로 전체를 받아보려 했습니다. 그런데:

  • sanitized HAR은 응답 본문을 아예 제외합니다

  • 일반 HAR은 요청마다 JS 콜스택이 수백 줄씩 붙어서 실용성이 없습니다

결국 페이지별 Copy response가 더 나았습니다.

❌ 면적 단위에서 헷갈렸습니다

네이버 필터에 66~132㎡를 넣었는데 화면엔 "20평~40평"으로 표시됐습니다. 그런데 엑셀엔 같은 매물이 17.9평으로 나왔습니다.

원인은 공급면적 vs 전용면적이었습니다. 네이버 필터와 평형 표기는 공급면적 기준인데, 엑셀엔 전용면적만 평으로 환산해 두었던 거죠.

지금은 네 가지를 나란히 표시합니다.

공급면적(㎡)

공급(평)

전용면적(㎡)

전용(평)

79

23.9

59

17.85

❌ 대화창에 응답 데이터를 붙여넣다 잘렸습니다

429가 안 풀릴 때 우회책으로 Copy response 결과를 AI 대화창에 붙여넣었는데, 매물 20건 JSON이 3만 자쯤 되다 보니 중간에 잘렸습니다. 파일로 저장해서 경로만 알려주는 게 훨씬 확실했습니다.

앞으로의 계획

  • 토큰 만료 후 재사용 검증 — cURL 토큰이 만료된 뒤에도 자동 갱신이 동작하는지 확인 (되면 cURL 한 번으로 계속 쓸 수 있음)

  • 주기 실행 — 특정 시간에 특정 단지를 자동 수집해서 파일로 쌓기

  • 월별 호가 추이 그래프 — 스냅샷이 쌓이면 시세 흐름 시각화

  • 공인중개사 대상 실습 자료로 정리 — 이 과정을 비개발자도 따라 할 수 있게.😃


도움 받은 글


2
1개의 답글
밀어주고 끌어주는

온·오프라인 AI 스터디

AI로 어디까지 할 수 있는지
직접 확인하실 분만 신청하세요.