모바일 앱 데이터는 얼핏 단순해 보인다. 앱에는 순위, 평점, 가격, 설명이 있다. 그런데 다른 국가에서 같은 앱을 확인해보면 이 숫자들이 전부 다르다. 모바일 스토어가 하나의 카탈로그가 아니기 때문이다. 스토어는 각기 다른 순위, 다른 가격, 다른 이용 가능 여부, 그리고 각자의 언어로 된 리뷰를 가진 국가별 스토어프론트의 집합이다. 자신의 사무실에서 보는 화면은 백 개가 넘는 스토어프론트 중 하나일 뿐이며, 이를 전체 그림으로 취급하는 것이 모바일 시장 인텔리전스에서 가장 흔한 실수다.
이 때문에 앱 스토어 데이터 수집은 스크래핑 문제이기 이전에 지리적 문제가 된다. 모바일 팀이 무엇을 수집하는지, 어떤 스토어프론트에 도달할지가 왜 요청이 어디에서 오는 것처럼 보이는지에 의해 결정되는지, 그리고 레지덴셜 프록시가 각 시장을 현지 사용자처럼 읽을 수 있게 해주는 방법을 살펴본다.
모바일 팀이 수집하는 데이터
유용한 데이터는 몇 가지 범주로 나뉜다. 먼저 순위가 있다. 카테고리 및 전체 차트에서 앱의 위치, 그리고 특정 키워드에 대한 스토어 검색에서의 위치는 모두 스토어프론트별로 계산되며 매일 변동한다. 다음은 메타데이터로, 제목, 부제, 설명, 스크린샷, 릴리스 노트가 시장별로 현지화되어 있으며 경쟁사가 각 지역에서 어떻게 포지셔닝하는지 이해하는 원재료가 된다. 그다음은 가격이다. 유료 가격과 인앱 구매 등급을 포함하며, 이는 단일 숫자를 현물 환율로 환산한 것이 아니라 시장과 통화에 따라 달라진다.
이용 가능 여부는 사람들이 생각하는 것보다 더 중요하다. 앱은 퍼블리셔의 선택이든 규제 요건이든 특정 국가에서 아예 등록되지 않을 수 있으며, 경쟁사가 어디에 있고 어디에 없는지 아는 것 자체가 하나의 전략적 신호다. 평점과 리뷰도 마찬가지다. 점수와 리뷰 텍스트 모두 스토어프론트별로 다르며, 한 시장의 불만 사항은 다른 시장의 불만 사항과 전혀 다른 경우가 많다. 이 모든 것을 둘러싸는 것이 릴리스 주기와 에디토리얼 배치, 즉 누가 업데이트를 출시하고 누가 피처링되는지에 대한 기록이며, 이 역시 국가별로 다르다.
보이는 스토어프론트가 IP에 의해 결정되는 이유
두 스토어 모두 사용자를 국가별 스토어프론트로 라우팅하며, 이 라우팅은 주로 연결이 어디에서 오는 것처럼 보이는지에 의해 결정되고, 기기 로케일과 웹 엔드포인트의 명시적 국가 매개변수가 이를 보강하지만, 이것이 실제 현지 사용자가 보는 모든 것을 항상 반영하지는 않는다. 실질적인 효과는 한 국가에서의 요청이 던진 모든 질문에 대해 그 국가의 답을 반환한다는 것이다. 순위, 가격, 이용 가능 여부, 리뷰 전부 그렇다.
따라서 단일 위치에서 수집하면 아무리 많은 앱을 다루더라도 하나의 스토어프론트 관점만 얻게 된다. 독일의 순위에서 일본의 순위를 추론할 수 없고, 앱이 이용 가능한 시장을 보고 다른 시장에서 이용 불가능하다는 것을 알 수도 없다. 스토어프론트를 읽으려면 요청이 그 안에서 나와야 한다.
국가 타겟팅이 가능한 레지덴셜 프록시는 정확히 이 역할을 한다. 각 요청을 읽고자 하는 스토어프론트가 있는 시장에 배치하며, 이는 지역별로 달라지는 공개 데이터에 접근할 때 사용되는 것과 동일한 합법적인 지리적 타겟팅이다. 주목할 점은, 소매 및 여행 사례와 다르게 앱 스토어프론트는 국가 단위이므로 국가 타겟팅이 여기서 적절한 세분화 수준이며 도시 단위 타겟팅은 대개 아무런 이점을 주지 않는다는 것이다. 스토어프론트가 실제 현지 사용자가 보는 현지화된 메타데이터를 반환하도록, 접속하는 국가에 맞춰 언어와 로케일을 일치시켜야 한다.
규모: 앱 곱하기 국가 곱하기 매일
이 작업의 물량은 어느 하나의 무거운 쿼리가 아니라 곱셈에서 나온다. 30~40개 스토어프론트에서 추적하는 수백 개의 앱을 매일 새로고침하고, 여기에 키워드 순위 확인까지 더하면 요청 수가 늘어나며, 너무 적은 수의 주소에서 나올 경우 IP당 속도 제한에 즉시 걸리게 된다. 스토어 엔드포인트는 공격적으로 스로틀링을 걸며, 스로틀링된 응답은 단순한 지연이 아니라 나중에 채울 수 없는 일일 시계열의 구멍이 된다.
해법은 분산이다. 각 주소가 제한 내에 머물면서 전체 처리량은 확장될 수 있도록 확인 작업을 풀 전체에 분산시켜야 하며, 이는 고용량 수집기 뒤에 있는 부하 분산 로직이자 무제한 동시 연결이 존재하는 이유다. 실제로 어느 정도의 분산이 필요한지 궁금하다면, 그 근거는 실제로 필요한 프록시 IP 수에 설명되어 있으며, 요약하자면 이는 대표적인 풀 규모 수치가 아니라 스토어프론트별 요청 속도에 달려 있다.
진짜 스토어프론트 응답 받기
스토어 웹 엔드포인트는 방어되어 있으며, 데이터센터 주소 대역은 자동화된 수집 시도가 끊이지 않기 때문에 가혹하게 처리된다. 플래그가 지정된 주소에서 돌아오는 응답은 흔히 깔끔한 차단이 아니라 데이터 품질에 더 나쁜 것, 즉 스로틀링된 응답, 일반적인 페이지, 또는 데이터처럼 보이지만 실제로는 아닌 부분적인 결과다. 이는 데이터셋을 조용히 손상시키기 때문에 설계 단계에서 대비해야 하는 실패 모드다.
레지덴셜 프록시는 각 요청을 실제 가정용 연결을 통해 라우팅하므로, 확인 작업이 자국에서 스토어 페이지를 여는 일반 사용자처럼 보이며, 평판이 좋은 깨끗한 주소는 진짜 스토어프론트를 반환하는 반면 플래그가 지정된 주소는 도전 과제를 받거나 대충 처리된다. IP는 필요조건이지 충분조건이 아니므로, 요청 속도를 합리적으로 조절하고 엔드포인트가 응답한다고 해서 마구 두드리기보다는 차단을 유발하는 신호를 다루어야 한다.
페이지 기반 읽기를 위한 스티키 세션
대부분의 스토어프론트 확인은 단일 요청이며 로테이션해야 한다. 예외는 페이지가 있는 경우이며, 이 작업에서는 대개 리뷰가 여기에 해당한다. 한 국가의 한 앱에 대한 여러 페이지의 리뷰를 순회하는 것은 하나의 시퀀스이며, 그 과정에서 종료 주소가 바뀌면 순서가 일관되지 않거나 항목이 중복되거나 첫 페이지로 리셋될 수 있다. 스티키 세션은 그 순회 동안 하나의 주소를 유지해 페이지네이션이 일관되게 유지되도록 하며, 다음 앱이나 국가는 새로운 세션으로 시작한다. 광범위한 일일 스윕은 로테이션하고, 페이지 기반 읽기 내에서는 스티키를 유지한다.
시계열의 정확성 유지
순위는 시계열이며, 시계열의 품질은 그 안의 빈 구멍에 의해 결정된다. 한 국가에서 하루가 누락되면 그날은 추론할 수 없는 하루가 되므로, 수집 신뢰성을 운영상의 위생 관리가 아니라 데이터 품질 문제의 일부로 다루어야 한다. 파이프라인을 모니터링하되 스토어프론트별로 해야 한다. 한 시장에서 조용히 떨어지는 성공률은 다른 무엇이기 이전에 왜곡된 추세선이기 때문이며, 돌아온 것이 일반 페이지나 스로틀링된 페이지가 아니라 실제로 스토어프론트인지 검증할 가치가 있다. 이는 지속적인 가격 모니터링과 재고 추적에 필요한 것과 동일한 원칙이며, 수집된 결과는 동일한 종류의 대안 데이터 분석에 활용된다.
책임감 있게 수집하기
정직한 경계선이 있으며, 여기서 중요하다. 두 플랫폼 모두 자신의 앱을 위한 공식 리포팅 API를 제공하며, 이는 자신의 성과 데이터를 위한 올바른 소스다. 구조화되어 있고 정확하며 이용약관 범위 내에 있다. 공개 스토어프론트 수집은 경쟁 및 시장 인텔리전스를 위한 것이며, 어떤 API도 다른 사람의 앱에 대해 제공하지 않는 것들을 위한 것이다. 이는 각 플랫폼의 이용약관과 robots 지침을 준수하고 적절한 요청 속도로, 그 국가의 모든 방문자가 볼 수 있는 공개 데이터에 머물러야 한다.
명확히 짚어야 할 두 가지가 있다. 리뷰 데이터는 개인정보를 포함할 수 있는 사용자 생성 콘텐츠이므로, 해당 개인정보 보호 규정에 따라 처리해야 하며 개별 리뷰어의 프로필을 구축해서는 안 된다. 그리고 이는 측정에 한정된다. 순위 데이터를 수집하는 것은 시장 조사이지만, 순위나 설치 수, 리뷰에 영향을 주려는 시도는 조작이며, 모든 플랫폼의 규칙에 위배되고, 프록시가 사용되어서는 안 되는 목적이다. 스토어프론트를 읽는 것이 할 일이고, 손대는 것은 아니다.
최소한의 국가별 읽기
타겟팅은 게이트웨이의 사용자 이름에 담기므로, 스토어프론트를 고정하는 것은 필드 하나면 된다. 언어 헤더를 읽고자 하는 시장에 맞춰라:
import requests
MARKETS = ["us", "gb", "de", "jp", "br"]
def storefront(country, lang):
proxy = f"http://customer-USERNAME-country-{country}:PASSWORD@p.shifter.io:443"
r = requests.get(
"https://apps.example-store.com/app/id123456789",
proxies={"http": proxy, "https": proxy},
timeout=20,
headers={"Accept-Language": lang},
)
r.raise_for_status()
return r.text # 순위, 가격, 이용 가능 여부, 메타데이터 파싱
for country in MARKETS:
html = storefront(country, "en-US" if country in ("us", "gb") else None)
record(country, html) # 스토어프론트별, 일자별로 한 행씩 기록
추적하는 모든 시장에 걸쳐 동일한 읽기를 실행해 스토어프론트별 그림을 만들고, 페이지 기반 리뷰 읽기는 별도의 스티키 세션에서 유지하며, 국가 간 비교가 가능하도록 고정된 일일 일정에 따라 샘플링하라. 일반적인 클라이언트 패턴은 Python으로 레지덴셜 프록시 사용하기 가이드와 이어지며, 리뷰 특유의 관점은 고객 리뷰 모니터링에서 다룬다.
결론
앱은 하나의 순위, 하나의 가격, 하나의 평점을 가지지 않는다. 국가별 스토어프론트마다 다른 값을 가지며, 그 각각은 오직 해당 국가 안에서만 읽을 수 있다. 이 때문에 국가 커버리지가 모바일 시장 인텔리전스의 핵심 요건이 되며, 단일 위치에서 수집하는 것은 부분적이고 오해를 부르는 그림을 보장하는 셈이다. 레지덴셜 프록시는 정확히 이 문제를 해결한다. 국가 타겟팅으로 각 스토어프론트를 현지 사용자처럼 읽고, 큰 풀을 활용해 많은 앱과 시장에 걸친 일일 스윕을 속도 제한에 걸리지 않으면서 분산시키며, 깨끗한 가정용 주소로 돌아오는 응답이 스로틀링된 대체 페이지가 아니라 진짜 스토어프론트가 되도록 하고, 페이지 기반 읽기를 위한 스티키 세션을 제공한다. 자신의 앱에는 공식 API를 사용하고, 경쟁사 수집은 공개 데이터와 각 플랫폼의 이용약관 범위 내에 머물러야 하며, 차트를 측정하는 것에서 그것을 움직이려는 시도로 넘어가서는 안 된다.
이 수집 계층이 바로 레지덴셜 프록시가 제공하는 것이다. 국가 타겟팅과 시퀀스가 필요한 곳에는 스티키 세션을 갖춘, 실제 가정용 IP로 구성된 대규모 풀이다. GB당 가격 체계는 이 작업에 잘 맞는다. 스토어프론트 확인은 작고 빈번하며, 비용은 지켜보는 시장의 수가 아니라 실제로 가져오는 데이터양에 따라 결정되기 때문이다.