패밀리카를 검색어로 하여 6개 수집 도구를 돌려봤다 — Google이 막은 자리와 다음 학습 방향

패밀리카 query 6 도구 실측 — Google이 막은 6 layer

패밀리카를 검색어로 하여 6개 수집 도구를 돌려봤다 — Google이 막은 자리와 다음 학습 방향

trend-scout를 1년 운영했다.

다음 단계를 결정해야 할 시점이 왔다.

내 수집 도구를 한 단계 더 깊이 키울지,
아니면 더 넓게 가져갈지.

결정하기 전에
지금 가진 도구가 어디까지 풀어내고
어디서 막히는지 한번 측정해 볼 필요가 있었다.

검색어를 “3인가족 패밀리카 추천”으로 잡았다.

여기에 사이트 6곳을 도구 6개로 돌려보는 매트릭스를 만들었다.

결과는 명확했다.

Google을 통한 자료 수집은 6개 도구가 모두 실패했다.

반대로 Naver는 우회 도구 없이도
본문에 제품명이 9건 그대로 노출됐다.

이 결과가 다음 학습 방향을 정해줬다 — 깊이가 아니라 넓이.

이 글은 그 측정 과정과 거기서 본 것들을 정리한 글이다.


1. 지금의 trend-scout 구성과 측정 준비

trend-scout는 X·Threads·Google Trends 세 곳을 데이터 출처로 삼는다.

한 달에 비용은 0원,
유지 시간은 2~4시간 정도로 굴리는 사이드 수집기다.

이전 글 엔드포인트는 죽는다에서 정리한 운영 규율 세 가지가 있었다.

엔드포인트가 평균 2~3개월이면 죽는다는 점.

출처를 분산해야 한다는 점.

죽음 신호를 자동으로 감지해야 한다는 점.

1년 동안 굴리면서 얻은 학습이었다.

다음에 어디로 학습을 끌고 갈지 후보가 둘 있었다.

  • (깊이) 한 사이트에 우회 계층을 더 쌓는다 — TLS 위장, 브라우저 자동화, CAPTCHA 풀이 도구.
  • (넓이) 출처를 더 넓힌다 — 한국 검색, 커뮤니티, 자동차 전문 사이트.

깊이 쪽으로 가려면
지금 도구가 어디서 막히는지부터 알아야 했다.

그래서 한국어 검색어를 정해 두고,
표준 사이트 6곳에 던져 도구 6개로 풀어 보는 시도를 했다.

측정 준비

  • 검색어: “3인가족 패밀리카 추천”
  • 사이트 6곳: Google 웹 검색, Google 이미지 검색, Naver 검색, YouTube, Danawa 검색, Bobaedream 커뮤니티.
  • 도구 6개: curl 단독, curl_cffi(TLS 프로파일 4종), insane-search 엔진 자동, insane-search에 success_selectors를 강제로 넣은 버전, chrome-devtools MCP, Stealth Playwright와 사전 방문(warmup).
  • 검증 기준: 본문 텍스트에 제품명 신호(팰리세이드·쏘렌토·산타페·카니발·스타리아·EV9·GV80·투싼·패밀리카)가 몇 번 매칭되는지.

2. 봇 차단은 네 개 계층으로 쌓여 있다

봇 차단은 단일 계층이 아니다.

네 층으로 쌓여 있고,
도구마다 어느 층을 풀어낼 수 있는지가 다르다.

계층 무엇을 검사하나 보통 쓰이는 우회 방법
네트워크(Network) IP 호출 빈도 제한, 지역 차단 가정용 프록시 풀, 분산 작업자
전송(Transport) TLS 핸드셰이크 지문(JA3·JA4), HTTP/2 ALPN curl-impersonate, curl_cffi
브라우저(Browser) User-Agent, Sec-CH-UA, canvas·WebGL·폰트 지문, navigator.webdriver undetected-chromedriver, Playwright stealth
행위(Behavior) reCAPTCHA, 마우스·스크롤·타이밍 분석, 세션 쿠키 센서 행위 자동화, CAPTCHA 풀이 도구, 계정 워밍

전제 한 가지.

이번 측정에서 네트워크 계층(프록시)은 손대지 않았다.

즉 모든 시도가 같은 IP에서 실행됐다.

이 점이 5장의 핵심 발견으로 이어진다.


3. 사이트 6곳 × 도구 6개 매트릭스

사이트 6곳을 curl 단독으로 (도구 1)

사이트 응답 코드 본문 크기 제품명 노출 진단
Google web 200 90KB 0 display:none이 적용된 대체 페이지(“여기 클릭” 안내문)
Google image 200 90KB 0 동일
Naver 200 752KB 9 검색 결과가 그대로 노출됨
YouTube 200 1.7MB 0 HTML 본문에는 검색 결과가 없다. 다만 ytInitialData(YouTube가 검색 결과를 페이지 안 자바스크립트 객체로 주입하는 변수)에는 영상 메타데이터 18건이 들어 있다. JSON 정규식으로 따로 뽑아낼 수 있다
Danawa 200 95KB 0 URL 파라미터를 무시하고 메인 페이지를 반환
Bobaedream 200 63B 0 리디렉션 스크립트만 떨어진다(URL 엔드포인트를 다시 잡아야 함)

curl 단독으로 풀린 곳은 Naver 한 곳뿐이었다.

Google과 YouTube는 본문에 검색 결과 텍스트 자체가 들어 있지 않다.

Danawa와 Bobaedream은 URL 형식을 먼저 손봐야 하는 별개 문제다.

Google을 6개 도구로 (각 시도 상세)

도구 1 — curl 단독 (Chrome User-Agent)

$ curl -A "Mozilla/5.0 (Macintosh; ...) Chrome/124.0.0.0" \
       "https://www.google.com/search?q=..."
→ status 200, 90KB
→ body: "table,div,span,p{display:none}
         몇 초 안에 이동하지 않으면 여기 를 클릭하세요"
→ 검색 결과 텍스트 = 0

Google은 정적 HTML 응답에 검색 결과를 애초에 담아 보내지 않는다.

모든 div·span·p에 display:none을 걸어 두고,
자바스크립트 렌더가 없는 클라이언트는 대체 안내문으로 유도한다.

지문 검사로 막는 게 아니라,
응답 정책 자체가 그렇게 짜여 있는 셈이다.

도구 2 — curl_cffi의 TLS 프로파일 4종 (전송 계층)

curl_cffi는 Chrome·Safari·Firefox의 TLS 핸드셰이크 지문(JA3/JA4)을 그대로 복제해서 보낸다.

Akamai·Cloudflare·DataDome처럼 WAF가 TLS 지문으로 봇을 가려내는 사이트에서는 꽤 강력한 우회 도구다.

from curl_cffi import requests
for profile in ["chrome120", "chrome124", "safari17_2_ios", "firefox133"]:
    r = requests.get("https://www.google.com/search?q=...",
                     impersonate=profile)
    # 결과: 4 profile 모두 status 200, 90KB, hits=0

Google에 대해서는 프로파일 4종 모두 같은 대체 페이지를 돌려받았다.

본문 첫 200자에 같은 table,div,span,p{display:none} CSS가 떨어진다.

즉 Google은 TLS 지문을 검사해서 막는 게 아니다.

모든 클라이언트에게 같은 정적 HTML을 보내고,
자바스크립트가 돌지 않으면 검색 결과 페이지를 보여 주지 않는 방식이다.

URL 파라미터를 바꿔 보는 것도 마찬가지였다.

자바스크립트 없는 기본 모드를 노리는 gbv=1,
한국 로케일을 명시한 hl=ko-KR,
한국 지역을 지정한 gl=kr — 결과가 같았다.

전송 계층을 우회하는 도구는 이번 측정 범위 안에서 Google의 응답 정책을 풀어내지 못한다.

도구 3 — insane-search 엔진 자동 (1단계 일반 체인)

fivetaku의 insane-search 0.4.10~3단계 적응형 호출 체계다.

공식 API → curl_cffi 격자 → Playwright 대체 호출 순으로 자동으로 단계를 올린다.

진입점은 단 하나, fetch(url)이다.

from engine import fetch
result = fetch("https://www.google.com/search?q=...")
# 결과: ok=True, verdict=weak_ok, profile=None, attempts=1, hits=0

success_selectors를 안 주고 호출하면 엔진이 네 단계 검증을 거쳐 약식 통과(weak_ok)로 판정해 버린다.

이게 거짓 통과다.

Google의 대체 페이지는 Just a moment...·DataDome·Access Denied 같은 상용 WAF 마커를 명시적으로 쓰지 않는다.

대신 응답 자체에 결과를 안 담는 방식으로 막는다.

엔진 검증기는 상용 WAF 마커에 맞춰져 있다 보니,
Google이 직접 띄우는 자체 대체 페이지를 잡지 못한다.

도구 4 — insane-search에 success_selectors 강제 (1단계 격자 + Playwright 대체 발동)

result = fetch("https://www.google.com/search?q=...",
               success_selectors=["#search", "#rso", ".g",
                                  "div[data-snhf]", "h3", ".tF2Cxc"])

선택자를 강제로 넣으면 검증기가 매번 차단(CHALLENGE)으로 판정한다.

격자 시도를 끝까지 돌린 뒤,
Playwright 대체 호출까지 자동으로 발동한다.

14 attempts trace:
  [1]    probe       curl_cffi  safari        → CHALLENGE (no_success_selector)
  [2-12] grid (11회) curl_cffi  safari/chrome/firefox/safari_ios → 모두 CHALLENGE
  [13]   fallback    playwright_mcp           → unknown (Claude session 호출 필요)
  [14]   fallback    playwright_real_chrome   → unknown (local Node + chrome 필요)

curl_cffi 격자를 11번(safari·chrome·firefox·safari_ios × url_transform=original) 돌렸지만 전부 실패했다.

Playwright 대체 호출 두 가지가 발동되긴 했지만,
둘 다 엔진 바깥의 시스템을 호출해야 한다.

→ 엔진의 fetch()만으로는 Google을 풀 수 없다.

3단계 외부 실행기(MCP 또는 로컬 Node + Chrome) 도입이 필수다.

도구 5 — chrome-devtools MCP (raw Chrome 자동화)

mcp__chrome-devtools__navigate_page로 직접 시도해 봤다.

→ navigate to Google search URL
→ final URL = https://www.google.com/sorry/index?continue=...
→ a11y snapshot:
    "Google의 시스템이 컴퓨터 네트워크에서 비정상적인 트래픽을 감지했습니다."
    Iframe "reCAPTCHA 보안문자 2분 후 만료"
    "자동차가 포함된 이미지를 모두 선택하세요"

아무것도 안 입힌 Chrome도 곧바로 자동화로 감지됐다.

chrome-devtools MCP는 Chrome DevTools Protocol(CDP)을 그대로 노출하는데,
Google은 CDP가 켜진 흔적(navigator.webdriver = true 같은 것)을 검사해서 즉시 reCAPTCHA Enterprise 화면으로 보내 버린다.

도구 6 — Stealth Playwright와 사전 방문 hop (브라우저 계층의 정점)

puppeteer-extra-plugin-stealth를 입히고,
insane-search의 playwright_real_chrome.js 패턴을 그대로 따랐다.

사전 방문(warmup) hop과 지속 세션(Persistent Context, 브라우저 세션과 쿠키를 디스크에 보존하는 Playwright 옵션)이 핵심이다.

const { chromium } = require('playwright-extra');
chromium.use(require('puppeteer-extra-plugin-stealth')());

// Warmup: Google root 먼저 방문, sensor JS 실행 시간 줌
await page.goto("https://www.google.com/", { waitUntil: 'domcontentloaded' });
await page.waitForTimeout(3500);

// Main URL
await page.goto(searchUrl);
→ final URL = https://www.google.com/sorry/index?continue=...
→ body 6.3KB (정상 SERP는 90KB+)
→ "비정상적인 트래픽 감지" 메시지

stealth 플러그인, 사전 방문, 지속 세션, Chromium 바이너리 — 이번 측정에 넣어 본 항목은 전부 실패했다.

같은 IP에서 바로 직전에 돌린 chrome-devtools MCP 시도가 reCAPTCHA 화면으로 보내졌고,
그 직후 stealth 시도도 똑같이 같은 화면으로 갔다.

여기서 시간 순서로 세워 본 가설은 이렇다 — Google이 IP를 한동안 표시해 두고, 어떤 클라이언트가 와도 challenge로 보낸다.

이번 측정만으로 단정할 수는 없다(다른 IP에서 비교해 보는 측정은 하지 않았다).

다만 IP 자체는 확인했다 — 211.248.191.35, KT 가정용 회선(AS4766), 프록시 여부 false, 호스팅 여부 false(ip-api.com 조회 기준).

즉 깨끗한 가정용 IP에서도,
자동화 흔적이 한 번 노출되면 stealth 도구로는 풀리지 않았다.

stealth 도구가 “아무것도 안 입힌 Chrome이 자동화로 감지되는” 문제를 푸는 건 이론상 가능하다.

다만 IP가 한 번 표시된 시점부터는 stealth로도 풀리지 않는 흐름이 이번 측정에서 관측됐다.

네트워크 계층 우회(가정용 프록시 회전)가 먼저 깔려 있어야 stealth가 의미가 있다는 추정으로 이어진다.


4. 매트릭스 종합

도구 Google에서의 결과 막힌 계층
1. curl 단독 display:none 대체 페이지 응답 정책(브라우저 계층이 필요)
2. curl_cffi 4 profile 동일 대체 페이지 전송 계층 우회로는 풀 수 없음 — 응답 정책의 문제
3. insane-search 자동 거짓 통과(weak_ok) 엔진 검증기의 사각지대
4. insane-search + selector 강제 14번 시도 끝에 대체 호출(외부 의존) 1단계의 한계 — 3단계가 필요
5. chrome-devtools MCP reCAPTCHA Enterprise(/sorry/)로 이동 아무것도 안 입힌 Chrome이 즉시 감지됨
6. Stealth Playwright + warmup reCAPTCHA Enterprise(동일) IP가 한 번 표시되면 stealth도 풀어내지 못함

Google은 이번 측정에서 도구 6개에 전부 막혔다.

계층 하나만 더 학습해서 풀어낼 수 있는 문제가 아니라고 본다.

다른 사이트들은 다음과 같다.

사이트 가장 가벼운 작동 방법 들어간 계층 비용
Naver curl 단독 계층 0
YouTube curl + ytInitialData JSON 정규식 추출 전송 계층까지면 충분
Danawa curl + URL 엔드포인트 정정(search.danawa.com/dsearch.php) 계층 0
Bobaedream URL 엔드포인트 추가 검증 필요(POST? 다른 경로?) 미정
Google web 단일 계층 우회로는 이번 측정에서 풀리지 않음 시스템 전체(프록시 + 풀이 도구 + 워밍)
Google image 동일 동일

5. 발견 — 차단을 푸는 건 도구가 아니라 시스템

Google 자료 수집을 풀려면 조합된 시스템이 필요하다.

항목별 가격은 공식 가격 페이지의 시장가 기준이다.

  1. 가정용 프록시 풀 — IP를 돌리는 용도. Decodo 기준 최저 GB당 $2. 검색어 하나당 응답이 평균 100KB라고 보면 1,000건 정도가 $0.2, 한 달 100,000건이면 $20 정도다. 단 Bright Data·Oxylabs 같은 상위 업체는 더 비싸고, 안정적으로 굴리려면 시범 운영이 필요하다.
  2. CAPTCHA 풀이 API2captcha 기준으로 일반 reCAPTCHA는 1,000건에 $0.5(호출당 $0.0005), 이미지 보안문자는 1,000건에 $2.99(호출당 $0.003). 호출 빈도에 따라 한 달 $5~$50 수준.
  3. 계정 워밍 — 로그인된 Google 계정 풀. 계정마다 휴면이나 차단을 관리하는 운영 부담이 붙는다. 가격은 추정하기 어렵다(직접 굴리거나 그레이 마켓에서 사거나). 여기에다, 어떤 IP로 어떤 검색어를 어떤 빈도로 던질지 자동화하는 코드까지 따로 붙여야 한다 — 모니터링과 실패 감지 인프라까지 묶어서.

가격만 보면 사이드로 혼자 굴려도 한 달 $50~$100 안에서 가능해 보인다.

그런데 본질은 돈이 아니라 운영 부담이다.

계정이 차단됐을 때 대응하고,
프록시 품질이 들쭉날쭉한 걸 받아내고,
CAPTCHA 풀이 도구의 정확도가 흔들리는 걸 보정하고,
검색어 패턴까지 관리해야 한다.

사이드 trend-scout(한 달 0원, 2~4시간)에서 다음 단계로 옮기는 순간,
유지 비용이 한 자릿수 배수로 늘어난다.

이전 글에서 정리한 규율은 입구였다.

본체는 시스템을 굴리는 일이다.

입구만 있는 사이드가 본체에 도달하려면 운영 방식 자체를 바꿔야 한다.

5.1 AI 에이전트가 7번째 도구가 될 가능성

이 측정은 2026년 5월 시점의 도구 6개에 한정된 결과다.

앞으로 1~2년 안에 7번째 도구 후보가 보인다 — Claude·GPT의 컴퓨터 사용(computer-use) 류 에이전트다.

사람처럼 페이지를 이동하고, 스크롤하고, 타이밍까지 따라 하는 에이전트는 stealth Playwright 위에 행위 계층까지 자동으로 처리할 수 있다.

에이전트가 사람과 구분되지 않는 탐색 패턴을 만들어 내면,
네트워크 계층을 우회하지 않고도 Google이 challenge를 내보내지 않을 가능성이 있다.

이렇게 되면 5장의 시스템 비용(프록시 + 풀이 도구 + 워밍)이 호출당 에이전트 토큰 비용으로 바뀐다.

이 글의 결론(시스템 비용은 못 감당하겠다)이 AI 에이전트 토큰 비용이 의미 있게 떨어지는 시점까지의 한정된 결론이라는 점을 분명히 해 둔다.

이 가능성은 이번 측정에는 포함되지 않았다.

별도 측정 후보로 남겨 둔다.


6. trend-scout의 다음 계층 결정 — 4가지 축으로 본 근거

이 측정으로 다음 학습 방향이 정해졌다.

결정 근거가 한 축에 쏠리지 않도록 네 축으로 펼쳐서 본다.

Google 깊이 학습 Naver와 한국 사이트 넓이 학습
비용 시스템 비용에 운영 부담까지(한 달 $50~$100, 운영 방식 자체를 바꿔야 함) 거의 0(이미 계층 0에서 작동)
법적 자료 수집은 Google 이용약관 위반. 수집 규모가 커지면 위험도 같이 커진다 Naver는 검색 페이지를 일반적으로 접근하는 수준이라, 지금 도구 묶음과 같은 위험 수준
시점 지금 쓸 곳이 없다. 한국어 검색어 카테고리는 Naver가 감당해 준다 바로 쓸 곳이 있다(Naver의 다른 서비스, 추가할 한국 사이트들)
재방문 조건 (a) 영어 검색어나 글로벌 브랜드 추적을 의뢰하는 클라이언트가 생긴다, (b) AI 에이전트 토큰 비용이 의미 있게 떨어져 시스템 비용을 대체할 수 있게 된다, (c) 사이드에서 제품으로 가는 결정이 내려져 쓸 시점이 분명해진다 (a) Naver 정책이 바뀌어 다른 사이트로 분산해야 할 필요가 생긴다

탈락: Google 자료 수집을 깊이 쪽으로 학습하기.

네 축 모두 부정적이었다.

채택: 한국어 사이트를 넓이 쪽으로 확장하기.

  • Naver의 다른 서비스(블로그·뉴스·카페·지식인) — 같은 계층 0.
  • 한국 사이트 후보 추가(Bobaedream·디시·클리앙) — URL 엔드포인트를 정정한 뒤 계층 0~1.
  • YouTube ytInitialData JSON 정규식 — 전송 계층까지면 충분.

6.1 “넓이 채택”의 약점 — Naver 한 도메인에 쏠리는 의존

이 결정에는 분산 원칙과의 모순이 있다.

이전 글 엔드포인트는 죽는다에서 정리한 규율 중 하나는 어떤 사이트가 죽어도 다른 사이트가 받쳐줄 수 있게 분산하라였다.

Naver의 서비스 5개를 더 학습하는 건 한 도메인 안에서 분산이지,
진짜 사이트 분산은 아니다.

Naver가 정책을 바꾸거나 검색을 막기 시작하면 서비스 5개가 동시에 죽는다.

이 약점을 인지한 채 채택한다.

이유는 셋이다.

  1. 지금 쓰는 곳이 한국어 검색어에 묶여 있다. 글로벌 사이트까지 분산할 동기가 지금은 없다.
  2. Naver 서비스를 학습하는 것 자체가 한국어 카테고리의 깊이 학습이라, 진짜 사이트 분산은 다음 단계(예를 들어 다음 카테고리의 클라이언트가 생기면)다.
  3. 한 도메인 의존을 인지하고 있으니, 정책 변경을 조기에 감지할 수 있다 — 이전 글 규율 세 가지 중 #3(죽음 신호 자동 감지)을 Naver 검색의 응답 스키마·응답 코드·본문 크기 변동에 적용하고, 매달 한 번 다른 사이트 후보(Bobaedream·디시·클리앙)가 계층 0에서 작동하는지 점검하는 일을 실행 항목으로 둔다.

즉 최선이 아니라,
지금 시점에서 가장 합리적인 선택이다.

분산 우선이 아니라 깊이 먼저,
분산은 그다음 순서다.

6.2 학습 시점과 사용 시점

Google 자료 수집은 정말로 필요한 클라이언트가 생기면 그때 시스템 전체 도입을 결정한다.

사이드 단계에서 미리 학습해 두는 건 학습 시점과 사용 시점이 어긋나서,
그만큼 가치가 새 나간다.

이번엔 측정해 보고서야 결정했다.

다음엔 측정에 들어가기 전에 ROI 추정만으로 같은 답이 나오는지 한 번 더 시뮬레이션해 보고 들어간다.


7. 시리즈에서의 위치

[2026-04-23] 엔드포인트는 죽는다 — 무료 수집을 유지하는 규율 3가지
              ↑ 운영 관점 (1년 학습)

[2026-05-10] (이 글) 6 도구 실측 — Google이 막은 6 layer와 다음 학습 결정
              ↑ 측정 관점 · 다음 단계 결정

[다음 후보]
- Naver 카페·지식인 추가 source 학습
- Bobaedream/디시 URL endpoint 정정 후 추가
- 또는 YouTube ytInitialData JSON regex 정착

마무리

사이드 도구 묶음의 다음 계층을 결정짓는 건 도구가 얼마나 강한가가 아니라,
학습 시점과 사용 시점이 맞물리느냐다.

Google 자료 수집은 도구만 강하면 풀린다.

다만 사이드의 사용 시점에는 도달하지 못한다.

이번 측정이 층을 더 쌓을 때가 아니라는 것을 데이터로 보여 줬다.

엔드포인트는 죽는다.

그리고 이번 측정이 다음 단계를 정해 줬다.

댓글

이 블로그의 인기 게시물

Claude Opus 4.7 출시 총정리 — 뭐가 달라졌고 지금 써야 하나

맥 스튜디오 M4 Max 128GB 로컬 LLM 4개 속도 비교 — gemma4·llama3.3·qwen3 실측

Claude Code로 블로그 발행 15분을 1줄로 — 해고 후 첫 자동화 경험