본문으로 건너뛰기

© 2026 Molayo

Dev.to헤드라인2026. 06. 05. 00:51

10개의 AI 크롤러를 위한 robots.txt 파싱: 와일드카드, 부분 차단, 줄 번호

요약

AI 크롤러의 접근 권한을 확인하기 위한 robots.txt 파서 구축 과정과 기술적 난제들을 다룹니다. 와일드카드, 사용자 에이전트 그룹화, 상태 추적 등 복잡한 파싱 규칙을 처리하는 방법을 설명합니다.

핵심 포인트

  • robots.txt는 단순 텍스트가 아닌 상태 추적이 필요한 그룹화된 구조임
  • GPTBot, ClaudeBot 등 10가지 주요 AI 크롤러 대상 분석
  • 와일드카드 및 사용자 에이전트별 규칙 그룹화 처리의 중요성
  • 단순 허용/차단을 넘어선 세밀한 접근 상태 판별 필요성

robots.txt 파싱은 주말 동안 가볍게 할 수 있는 작업처럼 보입니다. 그것은 평면적인 텍스트 파일입니다. 각 줄은 지시어(directive)입니다. 콜론(:)을 기준으로 분리하고, 사용자 에이전트(user agent)를 매칭하며, 경로가 허용되지 않았는지 확인하면 됩니다. 그게 얼마나 어렵겠습니까.

하지만 실제 파일들을 입력하기 시작하면 상황이 달라집니다. 세 개의 User-agent 줄로 시작하여 하나의 규칙 블록(rule block)이 이어지는 그룹을 마주하게 됩니다. 작성자가 생각했던 것보다 더 많은 의미를 담고 있는 Disallow: /*?를 마주하게 됩니다. HTTPS에서는 404 오류가 발생하지만 HTTP에서는 로드되는 파일을 마주하게 됩니다. 줄 중간에 있는 주석, 혼용된 대소문자, 그리고 뒤에 아무것도 없는 Disallow:를 마주하게 됩니다. 주말 동안 끝내려던 작업이 점점 까다로워집니다.

우리는 단 하나의 좁은 질문에 잘 답하기 위해 AI 크롤러 체커(AI Crawler Checker)를 구축했습니다: 특정 도메인에 대해 주요 AI 크롤러 중 어떤 것이 읽을 수 있고, 어떤 것이 읽을 수 없는가? 우리는 다음의 10가지 특정 사용자 에이전트(user agents)를 기준으로 평가합니다:

  • GPTBot: ChatGPT 및 OpenAI, 학습 및 검색
  • ChatGPT-User: ChatGPT 실시간 브라우징
  • Google-Extended: Gemini 및 Google AI Overviews 근거 자료(grounding)
  • Googlebot: Google 검색 및 AI Overviews
  • PerplexityBot: Perplexity
  • Anthropic-AI: Claude 학습
  • ClaudeBot: Claude 웹 크롤러
  • Bytespider: ByteDance 및 TikTok
  • CCBot: 많은 AI 학습 세트에 데이터를 제공하는 Common Crawl
  • Applebot-Extended: Apple Intelligence

이 글은 결코 사소하지 않았던 부분들에 대한 기록입니다.

사용자 에이전트별 지시어 그룹화

단순한 파서(parser)를 곤란하게 만드는 점은 robots.txt가 규칙의 평면적인 목록이 아니라는 것입니다. 그것은 그룹의 연속입니다. 하나의 그룹은 하나 이상의 User-agent 줄로 시작하며, 그 뒤에 따르는 규칙 줄들은 해당 시작 부분에 명시된 모든 사용자 에이전트에 적용됩니다. 따라서 다음과 같은 경우:

User-agent: GPTBot
User-agent: CCBot
Disallow: /private/

이는 두 개의 별개 그룹이 아니라, 두 개의 봇이 공유하는 하나의 규칙 그룹입니다. * 그룹은 자체 그룹이 없는 모든 에이전트에 적용되는 폴백(fallback)입니다. 그룹화를 잘못하면 모든 규칙을 잘못 할당하게 됩니다.

우리가 결정한 파서(parser)는 읽어 들이는 동안 상태(state)를 추적합니다. User-agent 줄을 읽는 동안에는 이름들을 누적합니다. User-agent가 아닌 첫 번째 지시어(directive)가 에이전트 목록을 닫고, 그들 모두에 대한 규칙 수집을 시작합니다. 간략하게 표현하면 다음과 같습니다.

def parse_groups(lines):
    groups = []
    agents, rules = [], []
...

이는 예시일 뿐 실제 프로덕션 코드(production code)는 아니지만, 그 형태는 실제와 같습니다. 가치를 증명하는 핵심적인 디테일은 읽히는 순간부터 모든 규칙에 전달되는 lineno(줄 번호)입니다. 이에 대한 자세한 내용은 아래에서 다룹니다.

두 개가 아닌 세 가지 판결

명백한 모델은 이진적(binary)입니다. 봇이 허용되거나 차단되는 것입니다. 하지만 실제 파일은 그렇게 깔끔하게 나뉘지 않으므로, 우리는 세 가지 상태를 보고합니다: 허용(allowed), 차단(blocked), 그리고 부분 차단(partial)입니다.

차단(Blocked)은 포괄적인 Disallow: /입니다. 봇은 아무것도 가져갈 수 없습니다:

User-agent: Bytespider
Disallow: /

부분 차단(Partial)은 범위가 지정된 차단(scoped disallow)입니다. 봇은 사이트의 대부분을 읽을 수 있지만 특정 경로에서는 차단됩니다:

User-agent: Googlebot
Disallow: /admin/
Disallow: /cart/

이것은 '차단'이라기보다 '부분 차단'이며, 이 구분이 핵심입니다. /admin/에서만 차단된 봇은 괜찮습니다. 하지만 /docs/에서 차단된 봇은 당신이 읽기를 원하는 바로 그 콘텐츠로부터 차단될 수도 있습니다. 부분 차단을 차단으로 합쳐버리면 잘못된 경보(cry wolf)를 울리는 것이 되고, 허용으로 합쳐버리면 실제 문제를 숨기게 됩니다. 세 가지 상태는 진실을 말해주는 가장 작은 모델이기에, 우리는 이를 보고하며 모든 부분 차단에 대해 일치하는 경로를 함께 보여줍니다.

줄 번호 할당 (Line-number attribution)

이것은 가장 중요했던 UX(사용자 경험) 결정이었으며, 파서의 형태를 결정지었습니다.

"GPTBot: 차단됨"이라는 판결은 기술적으로는 맞지만 운영 측면에서는 무용지물입니다. 이를 읽는 사람은 이제 robots.txt를 열고, 훑어보고, 어떤 그룹이 GPTBot에 적용되는지 파악한 뒤, 문제가 되는 줄을 찾아내야 합니다. 공유 그룹과 와일드카드(*)가 포함된 긴 파일의 경우, 이는 몇 분간의 그레핑(grepping) 작업이 필요하며 잘못된 줄을 수정할 가능성도 상당히 높습니다.

"GPTBot: line 42에서 Disallow: /에 의해 차단됨"이라는 판정은 차원이 다른 문제입니다. 이는 특정 한 줄을 지목합니다. 해결책은 단 한 번의 수정입니다. 더 이상 조사할 것이 없습니다.

이것을 가능하게 하는 구현상의 유의점은 다음과 같습니다. 파싱(parse)하는 동안 줄 번호를 추적해야 하며, 파싱이 끝난 후에 재구성해서는 안 됩니다. 파일을 그룹과 규칙으로 정규화(normalize)하고 나면 원래의 줄 위치 정보는 사라지며, 문자열을 다시 매칭하여 위치를 찾으려는 시도는 파일에 중복된 지시어(directive)가 있는 순간 취약해집니다. 따라서 줄 번호는 첫 번째 읽기 단계부터 각 규칙과 함께 따라다녀야 하며, 위 튜플(tuple)의 lineno와 같이 유지되어야 합니다. 이를 들고 다니는 데는 비용이 들지 않지만, 나중에 이를 복구하는 것은 불가능합니다. 이것이 바로 작업을 사전에 처리해야 하는 핵심적인 이유입니다.

Fetch 폴백(fallbacks)과 혼란스러운 중간 단계

무엇인가를 파싱하기 전에 먼저 파일을 가져와야(fetch) 하며, 가져오는 과정에서 실제 환경의 혼란이 시작됩니다.

우리는 먼저 HTTPS를 시도하고, 그다음 일반 HTTP로 폴백(fallback)합니다. 왜냐하면 상당수의 사이트가 한 프로토콜에서는 robots.txt를 올바르게 제공하지만, 다른 프로토콜에서는 404 오류를 반환하기 때문입니다. HTTPS만 시도하는 체크 도구는 규칙이 아주 많은 사이트에 대해서도 "규칙 없음"이라고 보고하게 됩니다.

다음은 파일이 없는 경우입니다. 만약 robots.txt가 아예 존재하지 않는다면, 명세(spec)는 명확합니다. 부재는 허용을 의미합니다. 파일이 없다는 것은 모든 것에 대한 권한이 있다는 뜻이므로, 두 프로토콜 모두에서 404가 발생하면 이는 에러가 아니라 10개의 봇 모두에 대해 "기본 허용(allowed-by-default)"으로 해결됩니다.

그리고 파일 자체도 깨끗한 경우가 드뭅니다. 유효한 줄의 끝에 주석(comment)이 나타나므로, 지시어를 파싱하기 전에 첫 번째 #부터 제거해야 합니다. 필드 이름(field name)은 모든 대소문자 조합으로 들어오므로, User-agent, user-agent, USER-AGENT가 모두 일치해야 합니다. 이것이 파서(parser)가 필드를 소문자로 변환하는 이유입니다. 이 중 어느 것도 개별적으로는 어렵지 않습니다. 문제는 이러한 요소들이 쌓이면서 단순한 플랫 파일(flat-file) 파서를 실제 환경에서 캡처한 파일들을 대상으로 실제로 테스트해야 하는 복잡한 대상으로 만든다는 점입니다.

이 방법이 볼 수 없는 것

도구에 숨겨져 있지 않고 명시적으로 밝히는 정직한 경계는 다음과 같습니다: 이 도구는 robots.txt만을 읽으며 그 외의 것은 읽지 않습니다. robots.txt는 허가 (permission)를 의미하는 것이지 발견 (discovery)을 의미하는 것이 아니며, 허가는 액세스 제어 (access control)의 한 계층일 뿐입니다.

만약 사이트가 CDN이나 WAF, 또는 IP 차단이나 봇 관리 제품 (bot-management product)을 통해 크롤러를 차단한다면, 그 중 어떤 것도 robots.txt에 존재하지 않습니다. 그런 일은 네트워크 엣지 (network edge)에서 발생하며, 우리의 검사기는 이를 결코 볼 수 없습니다. 따라서 깨끗한 보고서가 나왔다는 것은 귀하의 robots.txt가 봇을 차단하고 있지 않다는 의미입니다. 그것이 봇이 귀하에게 도달할 수 있다는 것을 증명하지는 않습니다. 우리는 초록색 체크 표시가 과도한 주장을 하게 두는 대신 결과에 정확히 그 내용을 명시합니다. 자신이 아는 것을 조용히 과장하는 도구는 도구가 없는 것보다 더 나쁘기 때문입니다.

직접 시도해 보세요

귀하의 도메인을 직접 실행해 보고 싶다면, AI Crawler Checker는 무료이며 회원 가입 없이 루트 도메인 (root domain)만 입력하면 됩니다. 10개의 모든 크롤러에 대해 봇별 판정, 지시문 (directive), 그리고 줄 번호 (line number)를 확인할 수 있습니다.

발견 (discovery) 측면에서의 보완 도구는 Sitemap Checker로, 귀하의 사이트맵 (sitemap)이 발견 가능하고 건강한지 검증합니다. 허가 (permission)와 발견 (discovery)은 서로 다른 문제이며, robots.txt에서 허용한 봇이라 할지라도 여전히 귀하의 페이지를 찾을 수 있어야 합니다. Geology는 풀스택 SEO 및 GEO 에이전시이며, 이 무료 도구들은 우리가 고객 감사 (client audits) 시 수행하는 것과 동일한 검사 항목들을 귀하가 직접 실행할 수 있도록 분리해 놓은 것입니다.

Mehul Jain은 AI 기업가이자 제품 빌더입니다. 그는 GEO 플랫폼인 Geology에서 활동하고 있습니다.

AI 자동 생성 콘텐츠

본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0