top of page

[튜토리얼] 네이버 쇼핑(가격비교) 웹 크롤링 가이드


ree

네이버 쇼핑 크롤링이 어려운 이유

네이버 스크래핑이 왜 이렇게 까다로운지 궁금하시죠?

네이버는 그냥 검색 엔진이 아니에요. 한국 인터넷 생태계의 핵심이라고 보시면 돼요. 그래서 자기들 데이터, 특히 쇼핑 관련 정보에 대한 접근을 정말 엄격하게 관리하고 있어요.

상품 정보나 검색 결과를 긁어오려고 시도해보시면 금방 느끼실 거예요. 네이버가 얼마나 크롤링을 싫어하는지 말이에요. 대부분의 크롤러들이 막히는 이유도 바로 이 때문이에요.

그럼 구체적으로 어떤 부분들이 문제가 되는지 짚어볼게요.


◆ 데이터센터 프록시 즉시 차단

네이버는 데이터센터 IP들을 정말 철저하게 막아버려요.

ree

AWS나 구글 클라우드, 아니면 상업용 프록시 서비스 같은 곳에서 요청을 보내면? 거의 100% 막힌다고 보시면 돼요. 그리고 다음과 에러들을 만나게 될 거예요.

  • 403 Forbidden — 요청 즉시 거부

  • 429 Too Many Requests — 시작도 안 했는데 "너무 많이 보냈다"며 제한

  • 502 Bad Gateway — 방화벽이 개입했을 때 자주 뜨는 에러

정말 첫 단계에서부터 막혀버리는 거죠.

그럼 어떻게 해야 하냐고요? 한국 통신사(SKT, KT, LG유플러스 같은)의 일반 가정용이나 모바일 IP를 써야 해요. 그것도 세션을 계속 유지하고 헤더를 적절히 바꿔가면서 말이에요. 그래야 좀 더 자연스러운 사용자처럼 보이거든요.


◆ JavaScript 렌더링만으로는 불충분

그냥 JavaScript 렌더링만 하면 될 거라고 생각하시면 안 돼요.

아무리 좋은 헤드리스 브라우저(Puppeteer, Selenium 같은)를 써도 빈 페이지만 뜰 수 있어요. 왜냐하면 네이버는 여러 단계의 JavaScript 테스트를 걸어놨거든요. 그것도 지역이나 사용자 행동에 따라 다르게 나오는 거예요.

스크래퍼가 네이버가 기대하는 패턴과 안 맞으면? 브라우저 지문이라든지, TLS 설정, 실행 타이밍 같은 게 이상하면 조용히 실패하거나 무한 로딩에 빠져버려요.

더 교묘한 건, 어떤 페이지들은 200 OK 응답도 주고 멀쩡히 로드된 것처럼 보여요. 하지만 모든 스크립트가 정확한 순서로 제대로 실행되지 않으면 진짜 내용은 안 보여주는 거예요.

ree

이게 네이버가 다른 사이트들과 다른 점이에요. 단순히 "봇인가?"만 체크하는 게 아니라, "한국에서 실제 사용자가 쓰는 브라우저처럼 행동하고 있나?"까지 확인하는 거거든요. 정말 까다롭죠?


◆ 스파이더킴의 문제 해결 방식

직접 네이버를 긁어오려고 하면 페이지가 로드되기도 전에 막혀버려요. 네이버가 어디서 접속하는지, 브라우저가 어떻게 행동하는지, 세션이 자연스러운지까지 다 체크하거든요.

아무리 잘 만든 헤드리스 브라우저라도 적절한 IP랑 세션 설정이 없으면 소용없어요.

스파이더킴은 이런 복잡한 작업들을 다 알아서 처리해줘요. 사용자는 그냥 URL만 보내면 바로 실제 페이지 내용을 받을 수 있거든요.

뒤에서 이런 것들을 자동으로 해줘요.

  • 한국내 일반 가정용 IP 사용

  • 세션을 자연스럽게 유지

  • 헤더랑 TLS 지문을 적절히 바꿔가며 요청

  • JavaScript까지 완전히 렌더링

결국 복잡한 기술적인 부분은 다 맡기고, 여러분은 데이터 추출에만 집중할 수 있다는 얘기죠.



상품 페이지에서 상품 상세 정보 크롤링

가장 흔히 쓰는 방법은 상품 페이지로 바로 가서 이름, 가격 같은 주요 정보들을 뽑아내는 거예요. 처음 차단만 뚫을 수 있다면 꽤 잘 돌아가거든요.

이번 튜토리얼에서는 Python이랑 스파이더킴을 써서 SteelSeries 헤드셋 상품 페이지를 긁어와 볼 거예요.


◆ 사전 준비물


  • requests: HTTP 요청 보낼 때 쓸 거예요

  • re: 받아온 HTML에서 원하는 부분 찾을 때 필요해요

  • 스파이더킴 API 토큰: 차단 안 당하고 페이지에 접근하려면 이게 있어야 해요.

requests가 없다면 이렇게 설치하시면 돼요.


pip install requests



◆ 첫 번째 요청 보내기

상품 페이지에 접근해서 제대로 된 응답이 오는지 확인해볼게요. super=true 옵션을 꼭 써주세요. 이건 프리미엄 프록시 라우팅을 켜주는 건데, 일반 IP들이 금방 막히는 네이버에서는 정말 중요해요.

요청 보내는 방법은 이렇게 하시면 돼요.

import requests import urllib.parse # Your Spiderkim token token = "<your_token>" # Naver product URL target_url = "https://brand.naver.com/steelseries/products/11800715035" encoded_url = urllib.parse.quote_plus(target_url) # Spiderkim API endpoint with super=true for premium proxy routing url = f"https://api.spiderkim.com?token={token}&url={encoded_url}&super=true" # Send the request response = requests.get(url) # Print status code print(response)


이렇게 하면 차단 없이 실제 페이지 내용을 받아볼 수 있어요.

<Response [200]>

이게 바로 네이버가 요청을 허용했다는 뜻이에요. 이제 데이터를 뽑아낼 준비가 다 된 거죠!



◆ 상품명과 가격 추출

제대로 된 응답을 받은 걸 확인했으니까, 이제 페이지 소스에서 상품 이름이랑 가격을 직접 뽑아낼 수 있어요.

❗ 보통은 스크래핑할 정보를 페이지에서 찾고 검사를 눌러서 필요한 요소를 찾는데, 이번엔 그 방법이 안 통해요. 페이지 소스로 직접 가서 거기서 찾고 있는 정보를 찾아야 해요.

HTML 응답을 쭉 훑어보시면, 네이버가 모든 상품 정보를 큰 JSON 블록에 박아넣은 걸 발견할 수 있어요. 이게 네이버 내부 상태 객체의 일부인데, 상품 제목을 나타내는 "dispName"이랑 페이지에 표시되는 최종 가격인 "dispDiscountedSalePrice" 같은 필드들이 들어있어요.

ree

전체 JSON을 파싱할 필요는 없이 간단한 정규표현식으로 충분해요.

import requests import urllib.parse import re # Your Spiderkim token token = "<your_token>" # Target URL target_url = urllib.parse.quote_plus("https://brand.naver.com/steelseries/products/11800715035") # Spiderkim API endpoint with premium proxy routing url = f"https://api.spiderkim.com?token={token}&url={target_url}&super=true" # Send the request response = requests.get(url) # Extract the values via regex html = response.text product_name = re.search(r'"dispName":"([^"]+)"', html).group(1) discounted_price = int(re.search(r'"dispDiscountedSalePrice":([0-9]+)', html).group(1)) # Print product name and price print("Product Name:", product_name) print("Price:", f"{discounted_price:,}₩")


결과는 이런 식으로 나올 거예요.

Product Name: [QcK Heavy M 증정] 스틸시리즈 Arctis Nova 5 무선 게이밍 헤드셋 - 블랙 / 화이트 Price: 176,000


짜잔! 네이버에서 상품 스크래핑을 성공했네요. 하지만 제 경험상 이 방법은 일관성이 좀 떨어져요. 네이버 보안이 정말 빡빡하거든요! 그래서 네이버 API 엔드포인트를 사용하는 좀 다른 방법을 찾아봤어요.



네이버 API 엔드포인트로 상품 정보 크롤링

뭔가 더 빠르고, 안정적이고, 파싱하기 쉬운 걸 원한다면 네이버 자체 API가 더 나은 선택이에요. 깔끔한 JSON을 돌려주고, 로딩도 빠르고, 상품마다 일관성도 좋거든요.

단, 문제는? API 요청을 직접 만들어야 한다는 거예요.

두 가지만 있으면 생각보다 쉬워요.

  • channelUid: 스토어 식별자 (브랜드나 판매자 같은 거)

  • productNo: 상품 ID (이미 URL에 있어요)

그리고 어차피 네이버를 스크래핑한다면 특정 스토어들을 타겟으로 할 가능성이 높잖아요? 그럼 channelUid를 수십 개, 수백 개 상품에 재사용할 수 있어서 더 편해요.

어떻게 찾는지 보여드릴게요.

◆ Find channelUid

channelUid를 찾는 가장 쉬운 방법은 페이지 소스를 확인하는 거예요. 상품 페이지 아무 곳이나 우클릭하고 검사를 누르거나, F12를 누르세요. 개발자 도구가 열리면 Ctrl + F를 누르고 이걸 검색하세요.


channelUid

그럼 일반 텍스트로 보일 거예요. 이런 식으로 나올 거예요.

ree

바로 이 값이 필요한 거예요. 이 ID는 스토어마다 고유해요 (이 예시의 경우엔 SteelSeries). 그 스토어의 모든 상품 페이지에서 동일하게 유지되거든요. 한 번만 찾아놓으면 그 판매자의 상품 몇 개든 재사용할 수 있어요.



◆ 상품 ID 찾기

상품 ID 찾기 이건 더 쉬워요. 그냥 URL만 보시면 돼요.


11800715035가 바로 상품 ID예요. 네이버 API에서는 productNo라고 부르는 거죠. 뭘 검사할 필요도 없어요. 상품 URL만 있으면 이미 ID를 가지고 있는 거예요.

이제 channelUidproductNo를 둘 다 얻었으니까, API 요청을 만들어볼게요.


◆ 요청 보내기

이제 필요한 두 가지를 다 얻었어요.

  • channelUid: 2sWE13PU92zxrIFi44IbY

    • productNo: 11800715035

이 두 값만 있으면 네이버 내부 API를 호출할 수 있어요. 여기에 withWindow=false도 붙여서 불필요한 UI 데이터는 건너뛰고 더 가볍고 깔끔한 JSON 응답을 받을 거예요.

스파이더킴을 사용해서 요청을 만들고 보내는 방법은 이렇게 해요.

import requests import urllib.parse # Your Spiderkim token token = "<your_token>" # Product identifiers channel_uid = "2sWDw6fJMaeiT9eyhAmGd" product_id = "11800715035" # Naver API target target_url = f"https://brand.naver.com/n/v2/channels/{channel_uid}/products/{product_id}?withWindow=false" encoded_url = urllib.parse.quote_plus(target_url) # Spiderkim API endpoint api_url = f"https://api.spiderkim.com?token={token}&url={encoded_url}&super=true" # Send the request response = requests.get(api_url) # Print response status print(response)


모든 게 잘 작동하면 이렇게 나올 거예요.

<Response [200]>

이건 네이버가 전체 상품 데이터로 응답했다는 뜻이에요. HTML도 없고, 잡음도 없고, 다음에 작업할 수 있는 깔끔한 JSON만 있어요.



◆ 파싱과 내보내기

네이버 API에서 성공적인 200 응답을 받으면, 나머지는 정말 쉬워요. 뽑아낼 5가지 주요 필드는 다음과 같아요.

  • 상품명 → dispName

  • 할인된 가격 → discountedSalePrice

  • 할인율 → benefitsView.discountedRatio

  • 이미지 URL → representImage.url

  • 재고 수량 → stockQuantity

먼저 이것들을 출력해볼게요.

import requests import urllib.parse # Your Spiderkim token token = "<your_token>" # Product identifiers channel_uid = "2sWDw6fJMaeiT9eyhAmGd" product_id = "11800715035" # Build the Naver API URL target_url = f"https://brand.naver.com/n/v2/channels/{channel_uid}/products/{product_id}?withWindow=false" encoded_url = urllib.parse.quote_plus(target_url) api_url = f"https://api.spiderkim.com?token={token}&url={encoded_url}&super=true" # Send the request response = requests.get(api_url) data = response.json() # Extract fields name = data["dispName"] price = data["discountedSalePrice"] discount = data["benefitsView"]["discountedRatio"] image = data["representImage"]["url"] stock = data["stockQuantity"] # Print the results print("Product Name:", name) print("Price:", f"{price:,}₩") print("Discount:", f"{discount}%") print("Image URL:", image) print("Stock Quantity:", stock)


이렇게 출력될 거예요.

Product Name: [QcK Heavy M 증정] 스틸시리즈 Arctis Nova 5 무선 게이밍 헤드셋 - 블랙 / 화이트 Price: 176,000₩ Discount: 11% Image URL: https://shop-phinf.pstatic.net/20250507_71/1746586488548DMoJN_PNG/1170543923217933_1817156307.png Stock Quantity: 968

값들이 정확한 걸 확인했으니까, 이제 .csv 파일로 내보내서 나중에 데이터를 재사용하거나 대규모로 분석할 수 있게 해볼게요. 내보내기 기능이 포함된 최종 버전이에요.

import requests import urllib.parse import csv # Your Spiderkim token token = "<your_token>" # Product identifiers channel_uid = "2sWDw6fJMaeiT9eyhAmGd" product_id = "11800715035" # Build request target_url = f"https://brand.naver.com/n/v2/channels/{channel_uid}/products/{product_id}?withWindow=false" encoded_url = urllib.parse.quote_plus(target_url) api_url = f"https://api.spiderkim.com?token={token}&url={encoded_url}&super=true" # Request and parse response = requests.get(api_url) data = response.json() # Extract details name = data["dispName"] price = data["discountedSalePrice"] discount = data["benefitsView"]["discountedRatio"] image = data["representImage"]["url"] stock = data["stockQuantity"] # Export to CSV with open("naver_product_data.csv""w", newline="", encoding="utf-8-sig"as f: writer = csv.writer(f) writer.writerow(["Product Name""Price""Discount""Image URL""Stock Quantity"]) writer.writerow([name, price, f"{discount}%", image, stock]) print("Data saved to naver_product_data.csv")


이렇게 나올 거예요.

데이터가 naver_product_data.csv에 저장되었습니다


이렇게 해서 네이버 내부 API에서 바로 가져온 깔끔하고 신뢰할 수 있는 상품 데이터를 얻었어요.



차단 가능성

요청이 실패한다면 — 특히 403, 429, 또는 빈 페이지 — 보통 두 가지 중 하나 때문이에요.


◆ 지역 차단

네이버 상품 페이지랑 API는 지역별로 접근을 제한해요. IP가 한국에서 오는 게 아니라면 막히거나 불완전한 내용만 보일 가능성이 높아요.

이걸 해결하려면 스파이더킴 요청 URL 끝에 &geoCode=kr만 추가하시면 돼요. 그럼 최종 요청은 이렇게 생겨야 해요.


이렇게 하면 스파이더킴이 한국내 일반 가정용 IP를 통해 요청을 보내라고 알려주는 거예요. 네이버에 안정적으로 접근하려면 이게 필요하거든요.


◆ API 엔드포인트가 바뀐 경우

네이버는 자기들 내부 API를 공식적으로 문서화하지 않아요. 그리고 가끔씩 실제로 바꾸기도 해요. API 요청이 갑자기 작동하지 않는다면, 엔드포인트를 다시 확인해야 해요.

  1. 크롬에서 상품 페이지 열기

  2. F12 눌러서 개발자 도구 열기

  3. Network 탭으로 가기

  4. 페이지 새로고침하기

  5. "Filter" 입력창에 product ID plus ?withWindow=false 입력하기(예: 11800715035?withWindow=false)

  6. 일치하는 요청 클릭하기

  7. 전체 Request URL이 바로 내부 API 엔드포인트예요

이게 실제로 사용해야 하는 진짜 URL이고, 네이버의 현재 아키텍처에 따라 바뀔 수 있어요. 확실하지 않을 때는 언제든 이 방법으로 돌아가서 API 요청을 다시 만들면 돼요.



결론

네이버 쇼핑은 크롤링하기에 정말 까다로운 타겟이에요. 지역 차단, 헤드리스 렌더링 함정, 계속 바뀌는 내부 구조 때문에 대부분의 크롤러들이 200 응답도 받기 전에 실패해버려요.

하지만 channelUid 추출하는 방법, 내부 API 사용법, 적절한 프록시를 통한 요청 라우팅을 알게 되면 간단하고 반복 가능해져요.

그리고 스파이더킴을 사용하면 이런 걱정은 안 해도 돼요.

  • 프록시 로테이션이나 지문 인식

  • 세션 헤더나 TLS 설정

  • JavaScript 렌더링이나 CAPTCHA 해결


그냥 요청만 보내면 깔끔하고, 빠르고, 차단 없는 중요한 데이터 접근이 가능해요.




ree


댓글


사업자등록번호 : 426-86-00939 | 대표 : 김재훈 | 개인정보관리책임자 : 황재준 | 통신판매업신고번호 : 2020-대전유성-0339 사업자 정보확인

  • 자산 3
  • Facebook
  • Instagram
  • YouTube

02-562-8901 (평일 10:00-19:00) | support@spiderkim.com

(본사) 대전광역시 유성구 대학로 99 대전팁스타운 408호 | (연구소) 서울 강남구 테헤란로2길 27 패스트파이브 빌딩 1011호

ⓒ 2022 upennsolution Co., Ltd. All rights reserved.

bottom of page