프록시를 설정할 때 가장 먼저 드는 생각은 자신과 가장 가까운 위치를 고르는 것이다. 그러면 가장 빠를 것 같은 느낌이 들지만, 실제로는 잘못된 데이터를 얻게 되는 경우가 많다. 웹사이트는 사용자가 어디에 앉아 있는지 알지 못한다. 웹사이트가 보는 것은 출구(exit)이며, 따라서 레지덴셜 프록시를 사용할 때는 출구 국가가 어떤 버전의 사이트를 받게 될지를 결정한다.
이 가이드에서는 무엇을 알아내려 하는지에 따라 출구 국가를 어떻게 선택하는지, 사이트가 애초에 반응하는지 어떻게 확인하는지, 그리고 가장 가까운 출구가 실제로 올바른 선택인 경우는 언제인지를 다룬다.
먼저 물어야 할 질문
자신이 어디에 있는지 묻지 마라. 누구의 시점이 필요한지를 물어라.
| 하려는 작업 | 선택해야 할 출구 |
|---|---|
| 경쟁사 가격 모니터링 | 고객이 구매하는 시장 |
| 검색 순위 확인 | 검색하는 사람이 있는 위치, 필요하다면 도시 단위까지 |
| 광고 검증 | 캠페인이 타기팅하는 국가 |
| 현지화된 사이트 테스트 | 판매하는 모든 시장을 하나씩 |
| 자체 지역 리디렉션 확인 | 규칙이 적용되는 각 국가, 그리고 적용되지 않는 국가 하나 |
| 변하지 않는 콘텐츠 수집 | 대상에 가까운 곳, 풀이 두터운 곳 |
독일에 있는 팀이 미국 가격을 추적한다면 독일 출구로는 쓸모 있는 것을 전혀 얻지 못한다. 유로화로 표시되고 어쩌면 다른 카탈로그가 보일 것이며, 게다가 데이터는 완벽하게 정상으로 보일 것이다.
사이트가 반응하는지 테스트하라
모든 사이트가 IP에 따라 달라지는 것은 아니다. 출구 국가를 중심으로 계획을 세우기 전에 먼저 측정하라. 아래 스크립트는 여러 국가에서 페이지를 요청하고, 각 요청이 실제로 어디로 나갔는지 확인한 다음, 페이지가 무엇을 보여주었는지 기록한다. 이 스크립트는 Python 3.9 이상과 requests에서 실행된다. 자격 증명은 환경 변수에서 가져오므로 코드에 포함시키지 않는다.
from __future__ import annotations
import os
import re
import requests
GATEWAY = "p.shifter.io:443"
USER, PASSWORD = os.environ["PROXY_USER"], os.environ["PROXY_PASS"]
def session_for(country):
proxy = f"http://{USER}-country-{country}:{PASSWORD}@{GATEWAY}"
s = requests.Session()
s.proxies = {"http": proxy, "https": proxy}
s.headers["User-Agent"] = ("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
"(KHTML, like Gecko) Chrome/130.0 Safari/537.36")
return s
def signals(url, country):
"""What this page shows a visitor from one country, and where they really exited."""
s = session_for(country)
try:
exit_country = s.get("https://ip-info.com/json", timeout=30).json().get("country")
r = s.get(url, timeout=30)
except (requests.RequestException, ValueError) as exc:
return {"exit": country.upper(), "error": type(exc).__name__}
lang = re.search(r'<html[^>]*\blang=["\']?([\w-]+)', r.text, re.I)
currency = re.search(r'priceCurrency["\']?\s*(?:content=|:)\s*["\']([A-Z]{3})', r.text)
price = re.search(r'itemprop=["\']price["\']\s+content=["\']([\d.,]+)', r.text)
return {"exit": exit_country, "status": r.status_code, "final_url": r.url,
"lang": lang.group(1) if lang else None,
"currency": currency.group(1) if currency else None,
"price": price.group(1) if price else None}
if __name__ == "__main__":
for url in ("https://www.apple.com/shop/buy-iphone",
"https://store.steampowered.com/app/620/Portal_2/"):
print(url)
for country in ("us", "de", "gb", "br"):
s = signals(url, country)
print(f" exit {s['exit']} {s.get('status')} lang={s.get('lang')} "
f"{s.get('currency')} {s.get('price') or ''}".rstrip())
2026년 11월 4일에 Shifter 테스트 계정으로 실행한 결과는 다음과 같으며, 가격은 시간이 지나면서 바뀔 것이다.
https://www.apple.com/shop/buy-iphone
exit US 200 lang=en-US USD
exit DE 200 lang=en-US USD
exit GB 200 lang=en-US USD
exit BR 200 lang=en-US USD
https://store.steampowered.com/app/620/Portal_2/
exit US 200 lang=en USD 9.99
exit DE 200 lang=en EUR 9,69
exit GB 200 lang=en GBP 8.19
exit BR 200 lang=en BRL 33,99
이 두 사이트는 알아야 할 두 가지 경우를 보여준다.
Apple은 IP에 반응하지 않는다. 모든 출구에서 동일한 미국 페이지가 USD로 표시되었다. Apple은 현지화를 URL에 담아 둔다. /de/shop/buy-iphone은 독일 스토어를 제공한다. 이 페이지의 경우 출구 국가는 아무런 차이를 만들지 못했으므로, 지리적 위치로 출구를 고르는 것은 아무 의미가 없었을 것이다.
Steam은 반응한다. URL과 언어는 동일하게 유지되었지만, 통화와 가격은 출구에 따라 달라졌다. USD 9.99, EUR 9,69, GBP 8.19, BRL 33,99. 잘못된 국가에서 가격을 확인하면 깔끔하고 그럴듯하지만 틀린 숫자를 얻게 되며, 이를 경고해 줄 오류는 전혀 발생하지 않는다.
스크립트가 하듯이 페이지뿐 아니라 출구도 확인하라. 잘못된 위치는 나중에 데이터에서 발견하는 것보다 여기서 잡는 것이 훨씬 쉽다.
가장 가까운 출구가 잘못된 선택일 때
- 대상 청중이 다른 곳에 있는 경우. 가장 흔한 경우이며, 위의 예시가 그 이유를 보여준다.
- 이웃 나라가 다른 시장인 경우. 독일과 오스트리아는 언어는 같지만 가격이 항상 같지는 않으며, 통화가 같다고 해서 카탈로그가 같은 것도 아니다. 이들을 별개로 취급하라.
- 시장이 지역 단위인 경우. 일부 결과는 국가 단위만큼이나 도시나 주 단위로도 달라진다. 도시 단위 타기팅이 중요한 경우에 대한 가이드에서 이를 구분하는 방법을 다룬다.
- 요청의 나머지 부분이 일치하지 않는 경우. 미국 출구에 독일어 브라우저 언어가 설정되어 있으면 이상하게 섞인 결과를 얻을 수 있다. 지역, 시간대, 로케일은 서로 일치해야 하므로, 이들을 함께 설정하라.
가장 가까운 것이 맞을 때, 그리고 무엇에 가까워야 하는가
Apple의 URL처럼 사이트가 어디서나 동일한 콘텐츠를 제공한다면, 지리적 위치는 더 이상 정확성의 문제가 아니라 성능의 문제가 된다. 그렇다 해도 중요한 거리는 사용자의 책상에서부터의 거리가 아닌 경우가 많다. 프록시를 거친 요청은 클라이언트에서 게이트웨이로, 그다음 출구로, 그다음 대상으로 이동한다. 대상에 가까운 출구는 사용자가 얼마나 멀리 있든 마지막 구간을 단축시킨다.
따라서 콘텐츠가 변하지 않는다면, 사용 가능한 IP가 충분한 대상 근처의 출구를 선택하고 이를 측정하라. 작은 국가일수록 풀이 얇으므로, 위치가 정말로 중요하지 않은 경우에는 인기 있는 인접 시장이 더 안정적일 수 있다.
흔한 실수
- 한 국가만 테스트하고 나머지도 같을 것이라고 가정하기. 한 페이지에서 IP를 무시하는 사이트가 결제나 검색 같은 다른 페이지에서는 반응할 수 있다. 관심 있는 페이지를 테스트하라.
- 깔끔한 응답을 신뢰하기. 잘못된 통화로 표시된 페이지도 여전히 200을 반환한다. 예상하는 통화나 언어에 대한 확인을 추가하라.
- 모든 단계가 출구를 따른다고 가정하기. 일부 사이트는 IP뿐 아니라 DNS나 계정 설정에 따라서도 경로를 정하며, DNS가 출구 국가에서 해석되지 않을 수도 있다. 중요하다면 실제로 받는 페이지를 확인하라.
- 출구와 거주지를 혼동하기. 출구는 요청이 네트워크를 떠나는 지점이다. 데이터가 어디에 저장되는지에 대해서는 아무것도 말해주지 않는다.
- 출구를 허가로 취급하기. 테스트나 조사를 위해 사이트에 다른 국가의 화면을 보여주는 것과, 라이선스, 제재, 사이트 약관을 우회하는 데 사용하는 것은 별개의 문제다. 먼저 법무팀에 확인하라.
결론
누구의 시점이 필요한지에 따라 출구를 선택하라, 자신이 어디에 있는지가 아니라. 사이트가 애초에 IP에 반응하는지 테스트하고, 각 요청이 실제로 어디로 나갔는지 확인하고, 예상하는 통화나 언어에 대한 확인을 추가하라. 콘텐츠가 어디서나 동일한 경우에만 거리가 중요해지며, 그때 중요한 것은 대상까지의 거리다.