如何在伺服器日誌中找出 AI 爬蟲
在存取日誌的 user agent 欄位中搜尋 GPTBot、OAI-SearchBot、ClaudeBot、Claude-SearchBot 和 PerplexityBot 等 token,再查看它們收到的狀態碼。光憑 user agent 證明不了任何事,所以要把每個來源 IP 與業者公布的 IP 清單比對;對 Google 與 Apple,則使用反向與正向 DNS 驗證。
Robots.txt 說明的是你要求爬蟲做什麼。存取日誌則顯示實際發生了什麼:哪些 AI 爬蟲來過、請求了哪些頁面,以及你的伺服器如何回應。這是你手邊最直接的證據,只需要日誌檔和一個終端機。以下範例使用 nginx 與 Apache 預設採用的 combined 日誌格式。
本頁內容
存取日誌中的 AI 爬蟲造訪長什麼樣子?
在 combined 格式中,每一行包含用戶端 IP、時間、請求行、狀態碼、回應大小、referrer 與 user agent。nginx 將其定義為 $remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent",Apache 的 combined 格式有相同的欄位。來自 OpenAI 訓練爬蟲的一次造訪如下:
20.171.206.5 - - [12/Nov/2026:10:00:01 +0000] "GET /pricing HTTP/1.1" 200 5120 "-" "Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko); compatible; GPTBot/1.4; +https://openai.com/gptbot"
要找的是各業者公布的 token:GPTBot、OAI-SearchBot 與 ChatGPT-User(OpenAI);ClaudeBot、Claude-SearchBot 與 Claude-User(Anthropic);PerplexityBot 與 Perplexity-User(Perplexity);Googlebot、Applebot、meta-externalagent、meta-webindexer 與 CCBot。你永遠不會看到 Google-Extended 或 Applebot-Extended。Google 表示 Google-Extended 沒有獨立的 user agent 字串,Apple 表示 Applebot-Extended 不爬取內容;兩者都只是 robots.txt token。
如何統計 AI 爬蟲的造訪次數?
依雙引號字元拆分每一行,user agent 就位於第 6 個欄位。只比對這個欄位,可以避免因 URL 恰好包含某個機器人的名稱而誤判。下列指令會統計目前日誌,以及已輪替、已壓縮日誌中每個爬蟲的造訪次數:
zcat -f /var/log/nginx/access.log* \
| awk -F'"' '{print $6}' \
| grep -Eo 'GPTBot|OAI-SearchBot|ChatGPT-User|ClaudeBot|Claude-SearchBot|Claude-User|PerplexityBot|Perplexity-User|Googlebot|bingbot|Applebot|meta-externalagent|meta-webindexer|CCBot' \
| sort | uniq -c | sort -rn
請依 Apache 調整路徑,通常是 /var/log/apache2/access.log* 或 /var/log/httpd/access_log*。zcat -f 可以同時讀取一般檔案與 gzip 檔案。如果缺少某個你預期會出現的爬蟲,光憑這一點還不能證明它被封鎖:它可能只是沒有在你的日誌所涵蓋的期間內來過。
每個爬蟲實際收到了什麼?
造訪次數不如回應重要。一個每次請求都收到 403 的爬蟲,雖然來過,卻什麼也沒讀到。下列指令會顯示狀態碼、被請求最多的路徑,以及爬蟲是否擷取過 robots.txt:
# Status codes returned to PerplexityBot
zcat -f /var/log/nginx/access.log* | awk -F'"' '$6 ~ /PerplexityBot/ {split($3, s, " "); print s[1]}' | sort | uniq -c
# Most requested paths for OAI-SearchBot
zcat -f /var/log/nginx/access.log* | awk -F'"' '$6 ~ /OAI-SearchBot/ {split($2, r, " "); print r[2]}' | sort | uniq -c | sort -rn | head -20
# Did ClaudeBot fetch robots.txt, and what did it get?
zcat -f /var/log/nginx/access.log* | awk -F'"' '$6 ~ /ClaudeBot/ && $2 ~ /robots\.txt/ {split($3, s, " "); print s[1]}' | sort | uniq -c
以 200 為主是你希望看到的結果。大量的 403 或 429 指向防火牆規則或速率限制。robots.txt 回傳 5xx 則很嚴重:依據 RFC 9309,爬蟲在擷取 robots.txt 時收到伺服器錯誤,就必須假設整個網站都被禁止。
如果你的網站位於 CDN 之後,會有兩點不同。被 CDN 擋下的請求根本不會到達來源伺服器,因此完全不會出現在來源伺服器的日誌中;請改為查看 CDN 自己的安全事件。而且除非你還原訪客 IP,否則來源伺服器記錄的是 CDN 的位址。例如,Cloudflare 會在 CF-Connecting-IP 標頭中送出原始 IP,而預設記錄的是 Cloudflare 的 IP。
如何驗證某次造訪確實來自 OpenAI、Anthropic 或 Perplexity?
這些業者公布了其代理程式使用的 IP 範圍:OpenAI 在 openai.com/gptbot.json、openai.com/searchbot.json 和 openai.com/chatgpt-user.json;Anthropic 在 claude.com/crawling/bots.json;Perplexity 在 perplexity.ai/perplexitybot.json 和 perplexity.ai/perplexity-user.json。Anthropic 表示,來源 IP 出現在其清單中,代表該爬蟲來自 Anthropic。這三家都沒有記載反向 DNS 驗證,所以請使用這些清單。
這些檔案結構相同,都是由 ipv4Prefix 或 ipv6Prefix 項目組成的 prefixes 清單,所以一個小指令碼就能把某個 IP 與其中任何一個比對:
python3 - 20.171.206.5 https://openai.com/gptbot.json <<'EOF'
import ipaddress, json, sys, urllib.request
ip = ipaddress.ip_address(sys.argv[1])
req = urllib.request.Request(sys.argv[2], headers={"User-Agent": "log-check"})
prefixes = json.load(urllib.request.urlopen(req))["prefixes"]
nets = [ipaddress.ip_network(p.get("ipv4Prefix") or p.get("ipv6Prefix")) for p in prefixes]
print(ip, "listed" if any(ip in n for n in nets) else "NOT listed")
EOF
要列出自稱是某個爬蟲的 IP,請在日誌上執行 awk -F'"' '$6 ~ /GPTBot/ {split($1, a, " "); print a[1]}',再用管線傳給 sort | uniq -c | sort -rn。然後把每個 IP 與對應的清單比對。這些清單會變動,所以請重新擷取,不要使用舊的副本。
如何驗證 Googlebot、Applebot 與 CCBot?
Google、Apple 與 Common Crawl 都記載了反向加正向 DNS 的檢查方法。先查詢該 IP 的主機名稱,檢查其網域,再查詢這個主機名稱,確認它指回同一個 IP:
host 66.249.66.1
# 1.66.249.66.in-addr.arpa domain name pointer crawl-66-249-66-1.googlebot.com.
host crawl-66-249-66-1.googlebot.com
# crawl-66-249-66-1.googlebot.com has address 66.249.66.1
對 Google 而言,主機名稱必須以 googlebot.com、google.com 或 googleusercontent.com 結尾,視爬蟲而定;Google 也公布了它的 IP 範圍,Googlebot 的在 common-crawlers.json 中。對 Apple 而言,必須屬於 applebot.apple.com,IP 範圍在 applebot.json 中。對 Common Crawl 而言,必須位於 crawl.commoncrawl.org 之下,而且 Common Crawl 警告說,有其他爬蟲冒用 CCBot 這個名稱。
偽造的 AI 爬蟲長什麼樣子?
抓取程式經常借用知名爬蟲的 user agent 來繞過過濾。典型跡象:
- User agent 寫的是某個爬蟲的名稱,但 IP 不在該業者公布的清單中,或是其反向 DNS 不相符。
- 來源是業者沒有列出的住宅網路或雲端服務供應商。
- 該用戶端從不請求 robots.txt,或是請求了 robots.txt 對該爬蟲禁止的路徑。
- 請求頻率或模式與同名下已驗證的流量明顯不同,例如對搜尋或登入端點的突發請求。
反過來的問題同樣存在:使用一般瀏覽器 user agent 的爬蟲,根本無法從日誌行中辨識出來。2025 年,Cloudflare 表示觀察到 Perplexity 使用未聲明的、類似瀏覽器的 user agent,從其公布範圍之外的 IP 進行爬取;Perplexity 對此說法提出異議,並將一部分流量歸因於第三方服務。光憑日誌無法裁定這類情況,這就是為什麼依公布的 IP 範圍驗證在兩個方向上都很重要。
日誌無法告訴你什麼?
日誌顯示的是到達你伺服器的內容。它們不會顯示 CDN 在到達來源伺服器之前擋下了什麼,也不會顯示回傳 200 的頁面包含的是正文還是只有指令碼外殼,更不會顯示如果爬蟲今天來訪是否會被允許。它們也只涵蓋你保留的期間,而流量很小的網站可能很少見到 AI 爬蟲。
在 AISeeWhy 帳號中,你可以上傳 combined 格式的存取日誌(一般檔案或 .gz,最大 50 MB);日誌會在分析後捨棄,每個 AI 爬蟲的請求都會連同狀態碼一起統計,並與業者公布的 IP 範圍比對。
常見問題
為什麼我在日誌中看不到 Google-Extended?
Google 表示 Google-Extended 沒有獨立的 user agent 字串。爬取由 Google 現有的爬蟲完成,這個 token 只控制內容可以如何使用。Applebot-Extended 同樣如此,Apple 表示它不爬取內容。
我可以信任日誌中的 user agent 嗎?
不可以。任何人都可以送出任意 user agent。請把它當作一種聲明,並透過業者公布的 IP 範圍加以確認;對 Google、Apple 與 Common Crawl,則使用反向與正向 DNS 查詢。
我的日誌裡沒有任何 AI 爬蟲的造訪。我被封鎖了嗎?
不一定。爬蟲可能還沒來過,你的 CDN 可能在到達來源伺服器之前就擋下了它,或是你的日誌只記錄了 CDN 的 IP 位址。請查看 CDN 的安全事件,並用每個爬蟲的 user agent 測試頁面。
ChatGPT-User 的流量算爬蟲嗎?
OpenAI 表示,ChatGPT-User 用於某些使用者操作,不用於自動爬取網路。它的造訪通常發生在有人向 ChatGPT 詢問某個頁面之後,所以數量很少。
資料來源
- nginx:ngx_http_log_module(combined 日誌格式)
- Apache HTTP Server 2.4:日誌檔
- OpenAI:OpenAI 爬蟲總覽
- Anthropic:Anthropic 會從網路爬取資料嗎?網站經營者如何封鎖爬蟲?
- Perplexity:Perplexity 爬蟲
- Google:驗證 Google 爬蟲與擷取器
- Google:常見爬蟲(包含 Google-Extended)
- Apple:關於 Applebot
- Common Crawl:CCBot
- RFC 9309:Robots Exclusion Protocol
- Cloudflare:還原原始訪客 IP
- Cloudflare:Perplexity 使用隱蔽的未聲明爬蟲來規避網站的禁止爬取指令
- Perplexity:是代理程式還是機器人?理解開放網路上的 AI