Google Search Console은 크롤러가 사이트를 어떻게 보는지 알려줍니다. 하지만 실제로 어떤 URL을 방문했는지, 얼마나 자주 왔는지, 어떤 상태 코드를 받았는지는 알려주지 않습니다. 그 답은 서버 로그에 있습니다.
TL;DR
- Search Console의 크롤 통계는 샘플링 데이터이고, 서버 로그는 전수 데이터
- Nginx 설정 한 줄로 봇 트래픽만 별도 로그로 분리할 수 있음
- 크롤 낭비(Crawl Waste)는 대형 사이트에서 상당한 비중을 차지할 수 있음 — 실제 비율은 로그 분석으로 확인 필요
- 2025년 이후 AI 크롤러(GPTBot, ClaudeBot) 트래픽이 급증하여 별도 모니터링이 필수
왜 Search Console만으로는 부족한가
Google Search Console의 크롤 통계 보고서는 유용하지만 근본적인 한계가 있습니다.
| 항목 | Search Console | 서버 로그 |
|---|---|---|
| 데이터 범위 | 샘플링된 일부 | 전수 데이터 |
| 봇 종류 | Googlebot만 | 모든 크롤러 |
| URL 수준 상세 | 유형별 집계 | 개별 URL |
| 상태 코드 | 제한적 | 전체 HTTP 코드 |
| AI 크롤러 | 미포함 | 모두 포함 |
| 실시간성 | 2-3일 지연 | 실시간 |
핵심은 이것입니다. Search Console은 Google이 "보여주고 싶은 것"을 보여주고, 서버 로그는 "실제로 일어난 일"을 보여줍니다.
2026년 주요 크롤러 식별하기
검색엔진 크롤러
Googlebot: Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)
Bingbot: Mozilla/5.0 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm)
Naver Yeti: Mozilla/5.0 (compatible; Yeti/1.1; +http://naver.me/spd)
AI 크롤러 — 세 가지 유형 구분
AI 크롤러는 2025년을 기점으로 세 가지 유형으로 분화했습니다. 이 구분이 중요한 이유는 robots.txt에서 차등 제어가 가능하기 때문입니다.
| 유형 | User-Agent | 목적 |
|---|---|---|
| 학습용 | GPTBot, ClaudeBot | 모델 훈련 데이터 수집 |
| 검색용 | OAI-SearchBot, Claude-SearchBot, PerplexityBot | AI 검색 결과 생성 |
| 사용자 트리거 | ChatGPT-User | 사용자 요청에 의한 실시간 크롤링 |
트래픽 규모 변화도 주목해야 합니다. 2024~2025년 사이 GPTBot, ClaudeBot 등 AI 학습 크롤러의 요청량이 빠르게 증가했다는 보고가 다수 업계 분석에서 나오고 있어, 구체 수치는 자체 로그로 확인하는 것을 권장합니다.
주의: OpenAI 공식 문서에 따르면 ChatGPT-User는 사용자 요청 기반으로 동작하며, ChatGPT-User/1.0 UA를 사용합니다. 다만 OpenAI는 이 봇이 사용자 트리거형이므로 robots.txt 규칙이 적용되지 않을 수 있다고 명시하고 있습니다.
Googlebot IP 검증
로그에 Googlebot이라고 적혀 있다고 진짜 Googlebot은 아닙니다. 역방향 DNS 조회로 검증해야 합니다.
# 1단계: IP → 호스트명
host 66.249.66.1
# 결과: 1.66.249.66.in-addr.arpa domain name pointer crawl-66-249-66-1.googlebot.com.
# 2단계: 호스트명 → IP (역검증)
host crawl-66-249-66-1.googlebot.com
# 결과: crawl-66-249-66-1.googlebot.com has address 66.249.66.1
유효한 도메인은 googlebot.com, google.com, googleusercontent.com 세 가지입니다. 두 단계를 모두 통과해야 정식 Googlebot입니다.
1단계: 봇 전용 로그 분리 (Nginx)
서버 로그에서 봇만 골라내는 가장 효율적인 방법은 Nginx 설정에서 아예 별도 로그 파일로 분리하는 것입니다.
Nginx 설정
# /etc/nginx/conf.d/bot-logging.conf
# SEO 분석용 로그 포맷 정의
log_format seo_log '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'$request_time';
# 봇 판별 맵
map $http_user_agent $is_bot {
default 0;
"~*Googlebot" 1;
"~*bingbot" 1;
"~*Yeti" 1;
"~*GPTBot" 1;
"~*ClaudeBot" 1;
"~*PerplexityBot" 1;
"~*OAI-SearchBot" 1;
"~*Applebot" 1;
}
# 봇 트래픽만 별도 로그 파일에 기록
access_log /var/log/nginx/bots.log seo_log if=$is_bot;
설정 후 Nginx를 리로드합니다.
sudo nginx -t && sudo systemctl reload nginx
이제 /var/log/nginx/bots.log에는 봇 트래픽만 기록됩니다. 분석 대상 데이터가 전체 로그의 일부로 줄어들기 때문에 grep, awk 처리 속도가 빨라집니다.
2단계: bash 원라이너로 빠른 분석
Python 스크립트를 짜기 전에 bash 한 줄로 핵심 지표를 빠르게 확인할 수 있습니다. 아래 명령어는 모두 /var/log/nginx/bots.log 파일을 대상으로 합니다.
봇별 요청 수 카운트
awk -F'"' '{print $6}' /var/log/nginx/bots.log \
| grep -oE '(Googlebot|bingbot|Yeti|GPTBot|ClaudeBot|PerplexityBot)' \
| sort | uniq -c | sort -rn
출력 예시:
14523 Googlebot
3847 bingbot
2156 GPTBot
1893 ClaudeBot
892 PerplexityBot
341 Yeti
Googlebot이 받은 상태 코드 분포
grep "Googlebot" /var/log/nginx/bots.log \
| awk '{print $9}' | sort | uniq -c | sort -rn
출력 예시:
12847 200
956 301
412 304
198 404
87 500
23 503
404와 500이 많다면 크롤 버짓이 오류 페이지에 낭비되고 있다는 의미입니다.
가장 많이 크롤된 URL 상위 20개
grep "Googlebot" /var/log/nginx/bots.log \
| awk '{print $7}' | sort | uniq -c | sort -rn | head -20
일별 Googlebot 크롤량 추이
grep "Googlebot" /var/log/nginx/bots.log \
| awk '{print $4}' | cut -d: -f1 | tr -d '[' \
| sort | uniq -c | sort -t/ -k3 -k2M -k1n
404를 반환하는 URL 찾기 (크롤 낭비 탐지)
grep "Googlebot" /var/log/nginx/bots.log \
| awk '$9 == 404 {print $7}' | sort | uniq -c | sort -rn | head -20
이 결과가 크롤 낭비를 줄이는 첫 번째 단서입니다. 404를 반환하는 URL이 반복 크롤되고 있다면 robots.txt로 차단하거나 301 리다이렉트를 설정해야 합니다.
Googlebot IP 일괄 검증
# Google 공식 2단계 검증: 역방향 DNS → 정방향 DNS로 IP 일치 확인
grep "Googlebot" /var/log/nginx/bots.log \
| awk '{print $1}' | sort -u \
| while read ip; do
# Step 1: 역방향 DNS
hostname=$(host "$ip" 2>/dev/null | grep -oE '[a-z0-9.-]+\.(googlebot|google|googleusercontent)\.com\.$' | sed 's/\.$//')
if [ -z "$hostname" ]; then
echo "FAKE $ip (역방향 DNS 실패)"
continue
fi
# Step 2: 정방향 DNS로 원래 IP 일치 확인
forward_ip=$(host "$hostname" 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+')
if [ "$forward_ip" = "$ip" ]; then
echo "VALID $ip ($hostname)"
else
echo "FAKE $ip (정방향 DNS 불일치: $forward_ip)"
fi
done
3단계: Python으로 정밀 분석
bash 원라이너로 빠르게 확인한 뒤, 더 정밀한 분석이 필요하면 Python pandas를 사용합니다.
전체 스크립트
#!/usr/bin/env python3
"""
seo_log_analyzer.py - SEO 로그 파일 분석기
사용법: python3 seo_log_analyzer.py /var/log/nginx/bots.log
"""
import re
import sys
from collections import Counter
from datetime import datetime
import pandas as pd
# Combined Log Format 파싱 정규식
LOG_PATTERN = re.compile(
r'(?P<ip>\S+) \S+ \S+ '
r'\[(?P<time>[^\]]+)\] '
r'"(?P<method>\S+) (?P<url>\S+) \S+" '
r'(?P<status>\d{3}) (?P<size>\S+) '
r'"(?P<referer>[^"]*)" '
r'"(?P<ua>[^"]*)"'
)
# 봇 식별 패턴
BOT_PATTERNS = {
'Googlebot': re.compile(r'Googlebot', re.I),
'Bingbot': re.compile(r'bingbot', re.I),
'Yeti': re.compile(r'Yeti', re.I),
'GPTBot': re.compile(r'GPTBot', re.I),
'ClaudeBot': re.compile(r'ClaudeBot', re.I),
'PerplexityBot': re.compile(r'PerplexityBot', re.I),
'OAI-SearchBot': re.compile(r'OAI-SearchBot', re.I),
'Applebot': re.compile(r'Applebot', re.I),
}
def identify_bot(ua: str) -> str:
"""User-Agent 문자열에서 봇 이름을 식별합니다."""
for name, pattern in BOT_PATTERNS.items():
if pattern.search(ua):
return name
return 'Other'
def parse_log(filepath: str) -> pd.DataFrame:
"""로그 파일을 파싱하여 DataFrame으로 변환합니다."""
records = []
with open(filepath, 'r', encoding='utf-8', errors='ignore') as f:
for line in f:
m = LOG_PATTERN.match(line)
if not m:
continue
d = m.groupdict()
d['bot'] = identify_bot(d['ua'])
try:
d['time'] = datetime.strptime(
d['time'], '%d/%b/%Y:%H:%M:%S %z'
)
except ValueError:
continue
d['status'] = int(d['status'])
records.append(d)
return pd.DataFrame(records)
def analyze(df: pd.DataFrame) -> None:
"""핵심 SEO 지표를 출력합니다."""
print('=' * 60)
print(f'총 봇 요청 수: {len(df):,}')
print(f'분석 기간: {df["time"].min()} ~ {df["time"].max()}')
print('=' * 60)
# 1. 봇별 요청 분포
print('\n[1] 봇별 요청 수')
print(df['bot'].value_counts().to_string())
# 2. Googlebot 상태 코드 분포
gbot = df[df['bot'] == 'Googlebot']
if not gbot.empty:
print('\n[2] Googlebot 상태 코드 분포')
status_dist = gbot['status'].value_counts().sort_index()
print(status_dist.to_string())
# 3. 크롤 낭비 계산
waste_codes = [301, 302, 404, 410, 500, 503]
waste = gbot[gbot['status'].isin(waste_codes)]
waste_pct = len(waste) / len(gbot) * 100
print(f'\n[3] Googlebot 크롤 낭비율: {waste_pct:.1f}%')
print(f' ({len(waste):,} / {len(gbot):,} 요청)')
# 4. 가장 많이 크롤된 URL
print('\n[4] Googlebot 최다 크롤 URL (상위 15)')
top_urls = gbot['url'].value_counts().head(15)
for url, count in top_urls.items():
print(f' {count:>6} {url}')
# 5. 크롤되는 404 URL
not_found = gbot[gbot['status'] == 404]
if not not_found.empty:
print('\n[5] 404 반환 URL (크롤 낭비)')
for url, count in not_found['url'].value_counts().head(10).items():
print(f' {count:>6} {url}')
# 6. 일별 크롤량 추이
print('\n[6] 일별 봇 크롤량')
df['date'] = df['time'].dt.date
daily = df.groupby(['date', 'bot']).size().unstack(fill_value=0)
print(daily.to_string())
# 7. AI 크롤러 비중
ai_bots = ['GPTBot', 'ClaudeBot', 'PerplexityBot', 'OAI-SearchBot']
ai_traffic = df[df['bot'].isin(ai_bots)]
if not ai_traffic.empty:
ai_pct = len(ai_traffic) / len(df) * 100
print(f'\n[7] AI 크롤러 비중: {ai_pct:.1f}%')
print(ai_traffic['bot'].value_counts().to_string())
if __name__ == '__main__':
if len(sys.argv) < 2:
print('사용법: python3 seo_log_analyzer.py <로그파일경로>')
sys.exit(1)
df = parse_log(sys.argv[1])
if df.empty:
print('파싱된 레코드가 없습니다. 로그 형식을 확인하세요.')
sys.exit(1)
analyze(df)
실행 방법
pip install pandas
python3 seo_log_analyzer.py /var/log/nginx/bots.log
분석 결과 해석 가이드
| 지표 | 정상 범위 | 조치 필요 |
|---|---|---|
| 크롤 낭비율 | 10% 이하 | 30% 이상이면 robots.txt, 리다이렉트 점검 |
| 404 비율 | 2% 이하 | 5% 이상이면 깨진 링크 정리 필수 |
| 500 에러 | 0%에 가까워야 함 | 1건이라도 있으면 서버 로그 확인 |
| AI 크롤러 비중 | 사이트마다 다름 | 30% 이상이면 robots.txt 제어 검토 |
로그 분석 도구 비교
직접 스크립트를 짜지 않고 전용 도구를 사용할 수도 있습니다.
| 도구 | 가격 | 형태 | 장점 | 단점 |
|---|---|---|---|---|
| grep/awk | 무료 | CLI | 설치 불필요, 즉시 사용 | 복잡한 분석 한계 |
| Python + pandas | 무료 | 스크립트 | 무제한 커스터마이징 | 코딩 필요 |
| Screaming Frog Log Analyser | GBP 99/년 | 데스크톱 | 자동 봇 검증, GUI | 대용량 파일 처리 느림 |
| JetOctopus | $337/월 | 클라우드 | AI 봇 분석기 내장, 크롤 연동 | 비용 부담 |
| Botify | $500-$10,000+/월 | 엔터프라이즈 | 대규모 사이트 전용 | 중소 사이트에 과도 |
중소 사이트라면 이 글에서 소개한 Nginx 봇 분리 + bash/Python 조합으로 충분합니다. 월 수백만 페이지 규모라면 JetOctopus나 Botify를 검토하는 것이 시간 대비 효율적입니다.
한국 호스팅 환경에서의 주의사항
Cafe24에서는 로그 분석이 어렵습니다
한국에서 가장 많이 사용되는 Cafe24(카페24) 웹호스팅은 기본적으로 비root 환경이며, SSH(Shell) 접속은 별도 설정이 필요합니다. 원본 액세스 로그 다운로드 기능은 제한적이며(최근 약 1주일분 요청 시 제공), 봇 트래픽을 분리하여 상시 분석하기에는 제약이 있습니다.
호스팅별 로그 접근성
| 호스팅 | 로그 접근 | 비고 |
|---|---|---|
| Cafe24 웹호스팅 | 불가 | 기본 통계만 제공, SSH 없음 |
| Cafe24 VPS | 가능 | SSH 접속 가능, 직접 설정 필요 |
| NHN Cloud | 가능 | Cloud Log Analytics 서비스 제공 |
| AWS Korea | 가능 | CloudFront, ALB 로그 완전 제어 |
| 가비아 VPS | 가능 | SSH 접속 가능 |
Cafe24 사용자를 위한 우회 방법
Cafe24 웹호스팅을 사용하면서 로그 분석이 필요하다면, Cloudflare(클라우드플레어)를 리버스 프록시로 설정하는 방법이 있습니다.
- 도메인의 네임서버를 Cloudflare로 변경
- Cloudflare Dashboard에서 봇 트래픽 확인 (Bot Management)
- Cloudflare Logpush(Enterprise) 또는 Workers로 로그 수집
무료 플랜에서도 기본적인 봇 트래픽 통계를 확인할 수 있습니다. 다만 개별 URL 수준의 상세 로그는 Enterprise 플랜이 필요합니다.
가장 확실한 방법은 VPS(가상 서버)로 전환하는 것입니다. Cafe24 VPS, NHN Cloud, AWS Lightsail 등에서 월 1-2만 원 수준으로 SSH 접속과 Nginx 직접 설정이 가능합니다.
로그 분석 실전 체크리스트
로그 분석을 처음 시작한다면 아래 순서를 따라가면 됩니다.
1단계: 환경 구축
- Nginx에 봇 전용 로그 분리 설정 적용
- 최소 2주 이상 로그 수집
2단계: 현황 파악
- 봇별 요청 수 확인 (Googlebot이 실제로 오고 있는가?)
- 상태 코드 분포 확인 (200 외에 어떤 코드가 많은가?)
- 크롤 낭비율 계산
3단계: 문제 URL 식별
- 404를 반환하는 URL 목록 추출
- 불필요하게 크롤되는 URL 파악 (필터 파라미터, 페이지네이션, 내부 검색 결과 등)
- 중요한데 크롤되지 않는 URL 확인
4단계: 조치
- 404 URL에 301 리다이렉트 또는 robots.txt 차단 적용
- 불필요한 URL은
noindex또는robots.txt Disallow처리 - AI 크롤러에 대해 허용/차단 정책 수립
5단계: 모니터링
- 조치 후 1-2주 뒤 크롤 패턴 변화 확인
- 월 1회 정기 분석으로 추세 모니터링
정리
서버 로그 분석은 기술 SEO에서 가장 과소평가된 작업입니다. Search Console이 보여주지 않는 크롤러의 실제 행동을 파악할 수 있고, 크롤 버짓 낭비를 수치로 확인할 수 있습니다.
특히 2025년 이후 AI 크롤러 트래픽이 급증하면서, 어떤 봇이 얼마나 자주 방문하는지를 파악하는 것은 robots.txt 정책 수립의 기초 데이터가 됩니다.
Nginx 봇 분리 설정과 bash 원라이너 몇 줄이면 시작할 수 있습니다. 비용은 0원입니다.
크롤 분석이 필요하시면 XEO 무료 진단을 신청하세요.