AI 기업들은 자체 크롤러를 웹 전반에 보내고, 사이트 운영자는 robots.txt로 응답한다. 이는 자동화된 방문자가 무엇을 가져갈 수 있는지 알려주는 일반 텍스트 파일이다. 주요 AI 기업들은 각자의 크롤러가 응답하는 이름을 공개하므로, 사이트는 검색 엔진은 계속 받아들이면서도 하나, 일부, 또는 전체 크롤러를 차단할 수 있다.
우리는 누가 그렇게 하고 있는지에 대한 현재 그림을 원했다. 2026년 10월 6일, 우리는 Tranco 순위 상위 10,000개 도메인 전체의 robots.txt를 요청하고, 16개 AI 크롤러와 2개 검색 크롤러에 대한 규칙을 평가하여 각 사이트가 홈페이지에서 어떤 크롤러를 허용하는지 기록했다. 이 가이드는 그 결과와 우리가 작성한 평가 도구, 그리고 웹 데이터를 수집하는 모든 이에게 이것이 의미하는 바를 공유한다.
핵심 요약
- 상위 10,000개 도메인 중 5,754개가 읽을 수 있는 robots.txt를 제공했다. 그 중 다섯 개 중 하나, 20.4%가 홈페이지에서 최소 하나의 AI 크롤러를 차단한다.
- 가장 많이 차단되는 크롤러는 Common Crawl의 CCBot(16.2%), ByteDance의 Bytespider(15.3%), OpenAI의 GPTBot(15.1%), Anthropic의 ClaudeBot(14.0%)이다.
- 검색 엔진은 거의 차단되지 않는다. Googlebot은 2.6%, Bingbot은 3.3%만 차단되며, 이 중 대부분은 모든 크롤러를 차단하는 사이트다. 17.3%의 사이트는 두 검색 엔진을 모두 받아들이면서 최소 하나의 AI 크롤러는 차단한다.
- 많은 사이트가 학습용 수집과 응답용 수집을 구분한다. GPTBot을 차단하는 871개 사이트 중 345개는 사람이 ChatGPT에 질문할 때 페이지를 가져오는 ChatGPT-User는 여전히 허용한다.
- 사이트가 클수록 차단 가능성이 높다. 상위 1,000위 중 29.5%가 최소 하나의 AI 크롤러를 차단하는 반면, 5,001위에서 10,000위 사이 사이트는 18.8%에 그친다.
측정 방법
각 도메인에 대해 https://<domain>/robots.txt를 요청했고, 실패하면 www. 호스트로 대체했으며, 우리를 식별하고 사이트 링크를 포함한 User-Agent를 사용해 적당한 속도로 요청했다. 그런 다음 각 크롤러에 대한 규칙을 홈페이지 경로 /에 대해 평가했다.
우리는 대부분의 라이브러리가 취하는 지름길이 아니라 robots.txt 표준인 RFC 9309를 따랐다.
- 크롤러는 자신을 명시한 모든 그룹을 사용하며, 어떤 그룹도 명시하지 않을 때만
*그룹으로 대체한다. - 가장 길게 일치하는 규칙이 우선하며, 동률일 경우
Allow가 이긴다. - 4xx 응답은 규칙이 없음을 의미하고, 5xx 응답은 모든 것이 허용되지 않음을 의미한다.
Python 내장 파서는 가장 긴 규칙이 아니라 처음 일치하는 규칙을 적용하는데, 이는 Disallow: / 다음에 Allow: /$가 오는 흔한 파일을 잘못 해석하게 만든다. 그래서 우리는 자체 평가 도구를 작성하고 표준의 사례들에 맞춰 테스트했다. 우리는 크롤러가 홈페이지를 가져올 수 없을 때 “차단됨”으로 집계했고, 파일이 해당 크롤러를 이름으로 명시했는지 아니면 *를 통해서만 차단했는지를 별도로 기록했다.
10,000개 도메인 중 5,877개가 파싱 가능한 robots.txt를 반환했고, 그 중 5,754개가 고유한 사이트였다. 나머지는 대부분 API 호스트, 콘텐츠 전송 네트워크, 그리고 웹사이트를 제공하지 않는 기타 도메인이었다. 460개는 robots 파일 대신 HTML 페이지로 응답했으며, 이는 표준상 규칙 없음으로 처리된다.
발견한 내용
| 크롤러 | 운영사 | 목적 | 홈페이지에서 차단됨 | 파일에 명시됨 |
|---|---|---|---|---|
| CCBot | Common Crawl | AI 학습에 널리 사용되는 오픈 웹 아카이브 | 16.2% | 15.2% |
| Bytespider | ByteDance | AI 모델을 위한 크롤링 | 15.3% | 13.1% |
| GPTBot | OpenAI | 학습 | 15.1% | 17.7% |
| ClaudeBot | Anthropic | 학습 | 14.0% | 15.1% |
| meta-externalagent | Meta | 학습 및 AI 제품 | 12.5% | 10.8% |
| Google-Extended | Gemini의 학습 및 근거 확보, Search와는 별개 | 12.3% | 13.5% | |
| anthropic-ai | Anthropic | 이전 Anthropic 토큰 | 11.7% | 9.9% |
| Applebot-Extended | Apple | 학습, Applebot과는 별개 | 11.7% | 10.1% |
| Amazonbot | Amazon | Amazon 서비스를 위한 크롤링 | 11.7% | 10.3% |
| cohere-ai | Cohere | AI 제품 | 11.7% | 9.2% |
| PerplexityBot | Perplexity | 답변을 위한 검색 색인 | 10.8% | 12.7% |
| ChatGPT-User | OpenAI | 사용자가 질문할 때 페이지를 가져옴 | 9.4% | 11.7% |
| Perplexity-User | Perplexity | 사용자가 질문할 때 페이지를 가져옴 | 7.7% | 6.2% |
| OAI-SearchBot | OpenAI | ChatGPT 내 검색 결과 | 7.5% | 9.9% |
| Claude-User | Anthropic | 사용자가 질문할 때 페이지를 가져옴 | 7.3% | 6.1% |
| Claude-SearchBot | Anthropic | Claude 내 검색 결과 | 7.2% | 6.1% |
| Bingbot | Microsoft | 웹 검색 | 3.3% | 7.4% |
| Googlebot | 웹 검색 | 2.6% | 9.1% |
비율은 5,754개 사이트를 기준으로 한다. “명시됨”은 차단하든 허용하든 크롤러를 이름으로 지칭한 파일을 집계한 것이며, 두 열이 다른 이유가 바로 여기에 있다. 일부 사이트는 크롤러를 환영하기 위해서만 이름을 명시하며, 153개 사이트는 어떤 이름도 명시하지 않고 *를 통해 모든 크롤러를 차단한다.
세 가지 패턴
AI 크롤러는 차단되지만 검색 엔진은 차단되지 않는다. 17.3%의 사이트는 Googlebot과 Bingbot을 모두 홈페이지에 받아들이면서 최소 하나의 AI 크롤러는 차단한다. Googlebot을 이름으로 차단하는 사이트는 0.2%에 불과하다. 사이트 운영자들은 검색을 위해 색인되는 것과 AI를 위해 수집되는 것 사이에 분명한 선을 긋고 있다.
학습은 응답보다 더 많이 차단된다. 학습 데이터를 수집하는 크롤러는 사람이 질문해서 페이지를 가져오는 크롤러보다 눈에 띄게 더 자주 차단된다. GPTBot은 15.1%의 사이트에서 차단되는 반면 ChatGPT-User는 9.4%, ClaudeBot은 14.0%인 반면 Claude-User는 7.3%다. GPTBot을 차단하는 871개 사이트 중 345개는 여전히 ChatGPT-User를 허용하며, ClaudeBot을 차단하는 806개 사이트 중 390개는 여전히 Claude-User를 허용한다. 다시 말해 많은 사이트가 학습에는 기여하지 않으면서도 AI 답변에는 등장하기를 원한다.
차단은 규모와 함께 증가한다. 상위 1,000개 사이트 중 29.5%가 최소 하나의 AI 크롤러를 차단하고 21.0%가 GPTBot을 차단한다. 5,001위에서 10,000위 사이 사이트에서는 이 수치가 각각 18.8%와 13.9%로 떨어진다. 학습에 가장 가치 있는 콘텐츠를 보유한 대형 퍼블리셔와 플랫폼이 가장 많이 거부하는 쪽이다.
가장 두드러진 5개 AI 크롤러(GPTBot, ClaudeBot, Google-Extended, CCBot, PerplexityBot)를 모두 차단하면서도 Googlebot은 여전히 허용하는 사이트는 5.2%에 불과하다. 대부분의 거부는 선택적이다. 일부 기업은 차단하고 다른 기업은 차단하지 않거나, 학습은 차단하고 응답은 허용하는 식이다.
코드
아래 모듈은 robots.txt 파일을 파싱하고 RFC 9309 규칙에 따라 임의의 크롤러에 대해 평가한다. 외부 의존성은 없다.
import re
from urllib.parse import quote, unquote
def parse_groups(text):
"""Split robots.txt into groups: a list of (user-agent tokens, [(allow, path)])."""
groups, agents, rules, in_rules = [], [], [], False
for raw in text.splitlines():
line = raw.split("#", 1)[0].strip()
if ":" not in line:
continue
key, value = (part.strip() for part in line.split(":", 1))
key = key.lower()
if key == "user-agent":
if in_rules: # a user-agent line after rules starts a new group
groups.append((agents, rules))
agents, rules, in_rules = [], [], False
agents.append(value.lower())
elif key in ("allow", "disallow") and agents:
in_rules = True
if value: # an empty Disallow allows everything
rules.append((key == "allow", value))
if agents:
groups.append((agents, rules))
return groups
def rules_for(groups, product_token):
"""RFC 9309: use every group naming the crawler's product token; otherwise the '*' groups."""
token = product_token.lower()
named = [r for agents, rules in groups for r in rules if token in agents]
if any(token in agents for agents, _ in groups):
return named
return [r for agents, rules in groups for r in rules if "*" in agents]
def _pattern(path):
regex = "".join(".*" if ch == "*" else re.escape(ch) for ch in path.rstrip("$"))
return re.compile(regex + ("$" if path.endswith("$") else ""))
def allowed(groups, product_token, path="/"):
"""Longest matching rule wins; Allow wins a tie (RFC 9309, section 2.2.2)."""
target = quote(unquote(path), safe="/?=&*$%:@!,;~+")
best_len, verdict = -1, True
for allow, rule in rules_for(groups, product_token):
rule = quote(unquote(rule), safe="/?=&*$%:@!,;~+")
if _pattern(rule).match(target):
length = len(rule)
if length > best_len or (length == best_len and allow):
best_len, verdict = length, allow
return verdict
def names(groups, product_token):
"""Does the file address this crawler by name, rather than only through '*'?"""
return any(product_token.lower() in agents for agents, _ in groups)
그리고 사이트를 확인하는 예시로, 우리 자신의 사이트를 사용했다.
import requests
from robots import parse_groups, allowed, names
text = requests.get("https://shifter.io/robots.txt", timeout=15,
headers={"User-Agent": "ExampleSurvey/1.0 (+https://example.com/bot)"}).text
groups = parse_groups(text)
for crawler in ["GPTBot", "ClaudeBot", "Google-Extended", "CCBot", "Googlebot"]:
print(f"{crawler:16} homepage allowed: {allowed(groups, crawler, '/')} named: {names(groups, crawler)}")
우리 파일은 주요 AI 크롤러를 명시하고 명시적으로 허용하므로, 다섯 개 모두 허용으로 돌아오고 Googlebot은 *를 통해 허용된다. 우리는 최장 일치 우선 규칙, 동률 규칙, 와일드카드와 경로 끝 패턴, 병합된 그룹, 빈 파일을 포함한 16가지 사례에 대해 평가 도구를 테스트했다.
데이터 수집에 대한 의미
*뿐 아니라 크롤러별로 robots.txt를 읽어라.*를 통해 모두를 환영하는 사이트도 명시된 특정 크롤러는 여전히 차단할 수 있으며, 점점 더 많은 웹사이트가 정확히 그렇게 하고 있다.- 자신의 수집기를 정직하게 식별하라. robots 규칙은 크롤러가 자신이 누구인지 밝힐 때만 작동한다. 자신의 이름으로 수집한다면 그 이름에 대한 규칙과 수집 목적에 맞는 규칙을 확인하라.
- 사이트가 긋고 있는 구분을 존중하라. 많은 사이트가 이제 검색, 학습, 요청 시 가져오기를 구분한다. 학습 데이터를 수집하는 쪽은 자신의 이름이 명시되어 있지 않더라도 학습 크롤러에 대한 차단이 자신에게도 적용된다고 간주해야 한다.
- 정기적으로 재확인하라. 거부 설정은 사이트가 파일을 갱신하면서 바뀌므로, 6개월 전에 만든 목록은 이미 구식일 수 있다.
robots.txt, AI 거부 및 예약 신호에 대한 우리 가이드는 사이트가 사용하는 다른 신호들과 유럽의 법적 맥락을 다루며, 웹 스크레이핑 모범 사례는 방문하는 사이트에 피해를 주지 않고 수집하는 방법을 다룬다. 가져오는 시점에 거부 설정을 존중해야 하는 학습 데이터 파이프라인은 대규모 학습 데이터셋 구축하기에서 다룬다.
측정의 한계
- 홈페이지에 한함. 우리는 경로
/만 평가했다. 많은 사이트가 기사나 검색 페이지 같은 특정 영역에서는 AI 크롤러를 차단하면서 홈페이지는 열어두므로, 어딘가에서 AI 크롤러를 제한하는 사이트의 비율은 이 수치보다 더 높다. - robots.txt에 한함. 사이트는 HTTP 헤더, 메타 태그, 이용약관을 통해서도 신호를 보내며, 봇 관리를 통해 이를 강제하기도 한다. robots.txt에서 크롤러를 차단하지 않는 사이트도 네트워크 수준에서는 여전히 차단할 수 있다.
- 단일 시점. 이는 2026년 10월 6일, 하나의 네트워크에서 제공된 파일 기준이다.
- 상위 사이트에 한함. 상위 10,000개 도메인이 웹 전체는 아니며, 더 작은 사이트는 다르게 행동할 수 있다.
결론
이제 상위 사이트 다섯 곳 중 하나는 최소 하나의 AI 크롤러에게 홈페이지에 접근하지 말라고 말하는 반면, 거의 모두가 여전히 검색 엔진은 환영한다. 거부는 선택적이다. 학습용 크롤러가 사용자를 위해 페이지를 가져오는 크롤러보다 더 자주 차단되며, 가장 큰 사이트들이 가장 많이 차단한다.
웹 데이터를 수집하는 모든 이에게 실용적인 교훈은, 관련된 구체적인 크롤러와 목적에 맞춰 robots.txt를 읽고, 표준을 따르는 평가 도구를 사용하며, 웹이 계속 이 경계를 다시 그려가는 만큼 이를 정기적으로 재확인해야 한다는 것이다.
출처 및 참고자료
- IETF, RFC 9309: Robots Exclusion Protocol, 2022년 9월.
- Tranco, list Q2K34.
- 상위 10,000개 도메인의 robots.txt 파일, 위 코드를 사용해 2026년 10월 6일 Shifter가 요청함.