파서가 8KB의 JSON 응답을 위해 400KB의 HTML을 끌어옵니다. 50배의 차이는 "아름다운 코드"에 관한 것이 아니라, 기가바이트당 비용을 지불하는 레지던트 프록시 요금에 관한 것입니다. 내부 API를 찾는 방법, 2026년에 이를 반복하는 데 방해가 되는 것, 그리고 이 아이디어를 포기해야 할 때를 살펴봅니다.
HTML이 이미 파싱되고 있다면 숨겨진 API를 찾는 이유는?
거의 모든 현대 인터페이스 — React, Vue, Angular, Next.js — 는 먼저 페이지의 뼈대를 로드하고, 데이터를 별도의 요청으로 자신의 엔드포인트에 가져옵니다. 이러한 엔드포인트는 문서화되어 있지 않지만 존재하며, 순수 JSON으로 응답하고 headless 브라우저 없이도 접근 가능합니다.
이 엔드포인트로 전환하면 얻는 것:
- 트래픽이 급격히 감소합니다. 전형적인 상품 결과를 분석할 때 HTML 페이지는 약 400KB의 크기를 가지며, 마크업, 스타일 및 트래커를 포함하고, 해당 JSON 엔드포인트는 약 8KB로, 내부 ID, 재고, 상품 옵션과 같은 더 많은 필드를 포함합니다.
- 브라우저가 필요 없습니다. JavaScript 렌더링이 사라지고, 그에 따라 메모리, 프로세서 및 글꼴 및 분석을 위한 수십 개의 추가 요청이 필요하지 않습니다.
- 데이터가 이미 구조화되어 있습니다. CSS 클래스 변경으로 인해 깨지는 선택자가 없습니다.
- 요청 수가 줄어들면 차단될 이유도 줄어듭니다. 브라우저에서 카탈로그 페이지 하나를 렌더링하는 것은 사이트에 대한 수십 개의 요청을 의미합니다; 동일한 양의 데이터를 API를 통해 요청하면 하나의 요청으로 끝납니다.
레지던트 프록시 프로젝트의 경우 이는 직접적인 비용 절감입니다: 요금은 기가바이트 단위로 계산되며, 렌더링에서 JSON으로 전환하면 일반적으로 청구서가 더 많이 줄어듭니다. 관련 주제는 파서 트래픽을 5배 줄이는 방법입니다.
단계별: 엔드포인트 찾기
- 먼저 공식 API가 없는지 확인하세요. 목표 사이트의
/developers,/api,/docs를 확인하세요. 공개 문서화된 API는 버전 관리가 되며, 비공식 API는 조용히 변경됩니다. - DevTools를 열고 (F12) Network 탭으로 이동하여 기록이 활성화되어 있는지 확인하세요.
- Fetch/XHR 필터를 활성화하세요. 이 필터는 이미지, 글꼴 및 분석 요청을 차단하고 데이터 요청만 남깁니다.
- 목록을 정리하세요 초기 로딩의 잡음을 제거합니다.
- 필요한 데이터를 유도하세요: 결과를 스크롤하고, "다음 페이지"를 클릭하고, 필터를 적용하고, 카드 정보를 엽니다. 관심 있는 요청이 동작하는 순간 나타납니다.
- 당신의 데이터가 포함된 응답을 찾으세요. 가장 빠른 방법은 Network 패널에서 Ctrl+F를 사용하여 화면에서 보이는 고유한 값을 검색하는 것입니다 (아티클, 정확한 가격, 이름의 일부) 그리고 어떤 요청이 그것을 생성했는지 확인하세요.
- 요청을 전체적으로 복사하세요: 행을 오른쪽 클릭 → 복사 → cURL로 복사. 이후 curlconverter를 통해 코드를 변환하세요 — 이렇게 하면 헤더를 잃지 않습니다.
먼저 살펴봐야 할 전형적인 경로: /api/, /v1/, /v2/, /search, /products, /listings, /graphql.
특별한 경우: Next.js 사이트
여기서 데이터는 종종 별도의 요청이 필요하지 않습니다 — HTML에 바로 포함되어 있습니다. 구형 Pages Router에서는 __NEXT_DATA__ 블록입니다. App Router(Next.js 13 이상)에서는 데이터가 여러 script 노드에서 self.__next_f.push() 호출로 분산되어 있습니다 — 이는 React Server Components의 직렬화된 페이로드입니다. 수동으로 분석하는 것은 불편합니다: 청크는 $ 접두사를 통해 서로를 참조하며 문자열 중간에 잘릴 수 있습니다. Python에는 HTML에서 Flight-payload와 원시 RSC 응답을 파싱하는 nextflight 라이브러리가 있으며, 키 이름으로 검색할 것을 제안합니다 — 이렇게 하면 파서가 사이트의 재배포를 견딜 수 있습니다.
파라미터 리버스: 페이지네이션 및 필터
발견된 엔드포인트는 거의 항상 파라미터화되어 있습니다. 세 가지 스킴이 있습니다:
- 페이지별:
?page=3&per_page=20 - 오프셋 및 제한:
?offset=40&limit=20 - 커서:
?after=<token>&limit=20— 다음 페이지의 토큰은 이전 응답 본문에 포함됩니다.
디버깅 시간을 절약하는 세 가지 규칙:
- 미리 계산된 페이지 수가 아닌 빈 배치에서 멈추세요: 비공식 API의
total카운터는 자주 잘못된 정보를 제공합니다. - 실제 배치 크기를 확인하세요. 100을 요청했는데 20이 왔다면, 엔드포인트에 자체 한도가 있으며 페이지 수에 대한 계산이 잘못되었습니다.
- 500 페이지에 접근하지 마세요. 깊은 페이지네이션은 거의 모든 곳에서 서버에 의해 잘립니다; 대신 필터를 통해 선택을 잘라내세요 — 카테고리별, 가격 범위별, 날짜별.
브라우저에서 cURL이 작동하고 코드가 작동하지 않는 이유
가장 흔한 실패 지점이며, 이유는 거의 항상 하나입니다: 헤더가 손실되었습니다. 복사된 cURL은 요청의 모든 컨텍스트를 포함하고, 사용자 정의 클라이언트는 그렇지 않습니다.
일반적으로 필수적인 것:
X-접두사가 있는 사용자 정의 헤더 —X-CSRF-Token,X-Requested-With: XMLHttpRequest및 다양한X-*-Token은 프론트엔드에서 자동으로 추가됩니다. 이들이 없으면 400–500 범위의 응답을 받게 됩니다.Referer— 사용자 행동에 의해 생성되는 컨텍스트 헤더입니다. 많은 엔드포인트는 요청이 "자신의 페이지에서 왔는지" 확인합니다.Authorization: Bearer <JWT>— 짧은 수명의 토큰으로, 일반적으로 15–60분 동안 유효합니다. 이를 하드코딩하는 것은 의미가 없습니다: 최신 토큰을 얻는 방법을 알아야 합니다.- 세션 쿠키 — 이를 세션 객체에 보관하고 수동으로 복사하지 마세요.
- POST에 대한 올바른
Content-Type—application/json및application/x-www-form-urlencoded는 본문을 다르게 인코딩하며, 선언된 유형과 불일치하면 요청이 조용히 실패합니다.
쿠키에 없으면 토큰을 찾을 수 있는 곳: <script> 내부의 HTML 소스 (알려진 값을 통해 Ctrl+F로 검색), JavaScript 번들, localStorage 또는 IndexedDB — DevTools의 Application 탭에서 확인하세요.
늦게 알게 되는 함정
비공식 API는 예고 없이 변경됩니다. 버전 관리, 호환성 및 지원 약속이 없으며: 프론트엔드 팀이 목요일 저녁에 필드를 이름을 바꾸면, 당신의 파서는 빈 값을 수집합니다. 보호는 "신뢰할 수 있는 선택자"가 아니라 구조를 제어하는 것입니다: 필수 필드가 제자리에 있고 올바른 유형인지 확인하세요; 빈 값의 비율과 실행 중 레코드 수를 모니터링하세요; 손상된 레코드는 пропускайте, 그러나 결함이 10%를 초과하면 경고를 올리세요; 원시 응답을 저장하여 나중에 비교할 수 있도록 하세요.
API는 종종 페이지보다 더 강력하게 보호됩니다. 정기적으로 발생합니다: HTML은 문제없이 제공되지만, /api/에는 TLS 핑거프린트와 헤더 조합을 확인하는 안티봇이 있습니다. 그러면 트래픽 절약이 실패한 요청의 비율 증가로 이어지고, 이익이 사라집니다.
서명된 요청. 파라미터에서 sign, hash 또는 _s와 같은 것이 보이면, 프론트엔드는 JavaScript에서 서명을 계산합니다. 이를 재현하는 것은 별도의 프로젝트이며, 종종 HTML에 남아 있는 것이 더 저렴합니다.
빈도 제한. 비공식 엔드포인트는 흐름을 처리하도록 설계되지 않았습니다: 초당 1–2 요청을 유지하고, 연결 및 읽기에 대해 별도의 타임아웃을 설정하세요 (예: 5초 및 30초), 그리고 트랜지언트 오류 — 429, 500, 502, 503, 504 — 만 반복하고 401 및 404는 건드리지 마세요. 지터가 있는 지수 지연이 필수적이며, 그렇지 않으면 모든 워커가 동시에 두 번째 라운드로 돌진합니다. 자세한 내용은 프록시를 위한 타임아웃 및 재시도 로직 분석에서 확인하세요.
법적 프레임워크. 공개 비인증 엔드포인트는 한 상황이고, 계정에 로그인하는 것은 본질적으로 다른 상황입니다: 등록은 사용자 계약의 수락을 의미합니다. 개인 데이터는 얼마나 쉽게 접근할 수 있든지 GDPR의 적용을 받습니다. 사실 — 가격, 특성, 재고 — 는 저작권으로 보호되지 않지만, 텍스트와 이미지는 보호됩니다.
HTML에 남아 있어야 할 때
숨겨진 API는 항상 이득이 아닙니다. 페이지 분석을 유지하세요, 만약:
- 사이트가 서버 기반이고 내부 API가 전혀 없다면;
- 엔드포인트가 서명을 요구하거나 토큰 회전을 필요로 한다면 — 이를 유지하는 것이 페이지보다 비쌉니다;
- API에 공개 페이지보다 더 강력한 보호가 있다면;
- 프론트엔드가 여러 출처에서 수집한 최종 결과가 필요하다면;
- 여러 사이트를 운영하고 있다면: 단일 HTML 파이프라인이 개별적인 특성을 가진 비공식 API의 동물원보다 더 잘 확장됩니다.
API 파싱을 위한 프록시 유형 선택하기
JSON으로 전환하면 계산이 변경됩니다. 왜냐하면 병목 현상이 이동하기 때문입니다: 트래픽은 줄어들고 IP 품질 및 세션 안정성에 대한 요구는 증가합니다.
- 인증 없이 안티봇이 없는 공개 엔드포인트. 여기서는 데이터센터 프록시가 충분합니다: 데이터 양이 적고 레지던트에 대한 비용을 지불할 필요가 없습니다.
- 안티봇 뒤에 있는 엔드포인트 또는 세션에 묶인 엔드포인트. 레지던트 프록시가 필요하며, 세션이 고정되어 있어야 합니다: 토큰, 쿠키 및 IP는 체인의 모든 부분에서 일치해야 하며, 그렇지 않으면 서버가 두 번째 요청에서 세션을 재설정합니다. 이 경우 청구서는 여전히 적당하게 유지됩니다 — JSON 모드에서 기가바이트는 천천히 소모됩니다.
- 모바일 애플리케이션의 데이터. 웹 버전이 닫혀 있고 애플리케이션이 동일한 데이터를 더 쉽게 제공한다면, 엔드포인트는 트래픽 가로채기를 통해 찾습니다 — 이는 mitmproxy를 통한 모바일 애플리케이션의 숨겨진 API 검색에 대한 기사에서 설명된 별도의 절차입니다.
간단히 말해서
DevTools에서 20분은 종종 headless 브라우저와의 싸움에서 며칠을 대체합니다: Fetch/XHR 필터, 보이는 값으로 검색, cURL로 복사 — 그리고 당신은 작동하는 요청을 손에 쥐게 됩니다. 이후에는 세부 사항을 해결합니다: 모든 헤더를 전송하고, 페이지네이션 스킴을 분석하고, 응답 유효성을 검사하고, 엔드포인트가 페이지보다 더 강력하게 보호되고 있지 않은지 냉정하게 평가하세요. 비공식 API가 작동하는 곳에서는 트래픽 양과 요청 수를 줄여 — 즉, 프록시 비용과 차단 가능성을 동시에 줄입니다.
