엑셀 시트에 검색어를 넣고 매크로를 돌리면 쿠팡 검색 결과의 상품명을 페이지마다 읽어 오는 뼈대 코드입니다. 브라우저를 띄우지 않고 HTTP 요청으로 HTML만 받아서, 엑셀 안에서 DOM처럼 다루는 방식이에요. 완성본이라기보다는 "여기서 상품 정보를 뽑으면 된다"는 지점까지 만들어 둔 틀이라, 실제로 쓸 때는 원하는 항목을 꺼내는 부분을 채워 넣어야 합니다.
Sub 검색()
'/****************** 기존코드
Dim s As Shape
For Each s In ActiveSheet.Shapes
Debug.Print s.Name
If s.Name = "이미지" Then s.Delete
Next
Range("5:10000").ClearContents
'/****************** << 여기까지
'/****************** 변수선언
Dim URL As String, query As String, page As Integer
Dim IE As Object, T As String, Referer As String, Cookie As String
Dim v As Variant, i As Integer
Dim htmlfile As Object, productList As Object, elem As Object
'/****************** 설정
Set IE = CreateObject("WinHttp.WinHttpRequest.5.1")
Set htmlfile = CreateObject("htmlfile") ': htmlfile.Open: htmlfile.Write ""
Cookie = "sid=; " '// 필수 쿠키(없을시 응답 없음, 시간 초과)
query = fn.encode([D2])
'/****************** 무한루프 시작
Do
page = page + 1
URL = "https://www.coupang.com/np/search?"
URL = URL & "rocketAll=false"
URL = URL & "&q=" & query
URL = URL & "&isPriceRange=false"
URL = URL & "&page=" & page
URL = URL & "&filterSetByUser=true"
URL = URL & "&channel=user"
URL = URL & "&rating=0"
URL = URL & "&sorter=scoreDesc"
URL = URL & "&listSize=100"
With IE
.Open "GET", URL
.SetRequestHeader "Host", "www.coupang.com"
.SetRequestHeader "User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/110.0"
.SetRequestHeader "Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8"
If Len(Cookie) Then .SetRequestHeader "Cookie", Cookie
.SetRequestHeader "Origin", "https://www.coupang.com/"
.Send
.WaitForResponse: DoEvents
T = .ResponseText
End With
SetClipboard T: Stop '// 클립보드에 가져온 HTML 소스 넣고 브레이크
'htmlfile.Write T
htmlfile.body.innerHTML = T
Set productList = htmlfile.getElementById("productList"): i = 0
Do
i = i + 1
Set elem = getXPathElement("/li[" & i & "]", productList)
If Not elem Is Nothing Then
'// 이곳에서 상품 크롤링하면 됩니다.
Debug.Print getXPathElement("/a/dl/dd/div/div[2]", elem).innerTEXT '// 상품명 출력
End If
Loop Until elem Is Nothing
Stop '// 브레이크
Loop Until i < 101
MsgBox "모든 상품을 가져왔습니다."
End Sub
'// 클립보드에 텍스트 넣기
Public Function SetClipboard(ByRef sText As String) As Boolean ' ### 리턴값: 성공 여부
On Error GoTo nErr
Static Clipboard As Object
If Clipboard Is Nothing Then Set Clipboard = CreateObject("new:{1C3B4210-F441-11CE-B9EA-00AA006B1A69}") '// Microsoft Forms 2.0 Object Library
Clipboard.SetText sText: Clipboard.PutInClipboard
SetClipboard = True
nErr:
End Function
'// xPath를 이용한 크롤링을 위한 함수
Public Function getXPathElement(sXPath As String, objElement As Object) As Object
On Error GoTo ErrPass
Dim sXPathArray() As String
Dim sNodeName As String, sNodeNameIndex As String
Dim sRestOfXPath As String
Dim lNodeIndex As Long, lCount As Long
sXPathArray = Split(sXPath, "/")
sNodeNameIndex = sXPathArray(1)
If Not InStr(sNodeNameIndex, "[") > 0 Then
sNodeName = sNodeNameIndex
lNodeIndex = 1
Else
sXPathArray = Split(sNodeNameIndex, "[")
sNodeName = sXPathArray(0)
lNodeIndex = CLng(Left(sXPathArray(1), Len(sXPathArray(1)) - 1))
End If
sRestOfXPath = Right(sXPath, Len(sXPath) - (Len(sNodeNameIndex) + 1))
Set getXPathElement = Nothing
For lCount = 0 To objElement.ChildNodes().Length - 1
If UCase(objElement.ChildNodes().Item(lCount).nodeName) = UCase(sNodeName) Then
If lNodeIndex = 1 Then
If sRestOfXPath = "" Then
Set getXPathElement = objElement.ChildNodes().Item(lCount)
Else
Set getXPathElement = getXPathElement(sRestOfXPath, objElement.ChildNodes().Item(lCount))
End If
End If
lNodeIndex = lNodeIndex - 1
End If
Next lCount
ErrPass:
End Function
요청 부분
맨 앞 "기존코드" 블록은 원래 시트에 있던 정리 작업입니다. 이름이 "이미지"인 도형을 지우고 5행부터 아래 데이터를 비웁니다. 검색어는 D2 셀에서 읽어 fn.encode 로 URL 인코딩하는데, fn 은 원래 프로젝트에 있는 별도 모듈이라 여기에는 없습니다. 엑셀 2013 이상이면 WorksheetFunction.EncodeURL([D2]) 로 대신할 수 있습니다.
검색 URL에는 정렬(sorter=scoreDesc), 한 페이지 100개(listSize=100), 페이지 번호가 들어갑니다. 주석에 적어 둔 대로 당시에는 sid= 쿠키가 비어 있기라도 해야 응답이 왔고, 쿠키 헤더가 아예 없으면 응답 없이 시간 초과가 났습니다. 이런 식으로 사이트마다 "이게 없으면 안 되는" 헤더가 있어서, 브라우저 개발자 도구의 요청 헤더를 하나씩 빼 보면서 찾는 수밖에 없습니다.
HTML을 DOM으로 다루기
받은 HTML 문자열을 CreateObject("htmlfile") 로 만든 빈 HTML 문서의 body.innerHTML 에 넣으면, IE 엔진이 파싱해서 getElementById 같은 DOM 메서드를 쓸 수 있게 됩니다. 브라우저 없이 HTML을 구조적으로 읽는 가장 가벼운 방법입니다.
상품 목록은 id="productList" 인 요소 아래에 li 로 하나씩 들어 있어서, getXPathElement("/li[" & i & "]", productList) 로 i번째 상품을 꺼냅니다. getXPathElement 는 진짜 XPath 엔진이 아니라 /태그[번호]/태그... 형태의 경로만 따라 내려가는 간단한 함수입니다. 경로의 첫 단계를 잘라 자식 노드 중 같은 태그명의 n번째를 찾고, 나머지 경로가 있으면 자기 자신을 다시 호출합니다. 찾지 못하면 Nothing 을 돌려주니 Loop Until elem Is Nothing 으로 목록 끝을 판단할 수 있습니다.
페이지 넘김과 Stop
바깥 루프의 종료 조건 Loop Until i < 101 이 페이지 넘김의 핵심입니다. 안쪽 루프가 끝나면 i 는 "찾은 상품 수 + 1"이 됩니다. 한 페이지에 100개가 꽉 차 있으면 i 가 101이라 다음 페이지로 넘어가고, 100개보다 적으면 마지막 페이지로 보고 끝냅니다.
코드에 Stop 이 두 번 들어 있는데 둘 다 디버깅용입니다. 첫 번째는 받은 HTML을 클립보드에 넣고 멈추니, 메모장에 붙여 넣어서 원하는 데이터가 응답에 실제로 들어 있는지 확인할 때 씁니다. 자바스크립트로 나중에 그려지는 내용은 이 HTML에 없으니 이 단계 확인이 중요합니다. 실제로 돌릴 때는 두 Stop 을 지우거나 주석 처리하세요.
상품명 경로 /a/dl/dd/div/div[2] 처럼 태그 구조에 기대는 방식은 사이트가 조금만 바뀌어도 깨집니다. 그리고 쇼핑몰은 자동 수집을 강하게 막는 편이라 짧은 간격으로 반복 요청하면 바로 차단될 수 있으니, 페이지 사이에 충분히 쉬고 이용 약관도 확인하고 쓰는 게 좋습니다.