Bỏ qua để vào nội dung chính
Xác minh GPTBot thật hay giả trong access log bằng Python

Xác minh GPTBot thật hay giả trong access log bằng Python

Bởi Ava Mitchell
26 thg 10, 20264 phút đọc

User agent chỉ là một chuỗi text. Cách đối chiếu IP crawler với dải IP chính chủ bằng script Python stdlib, và ba loại dòng log cần sửa trước.

Bạn mở access log của site và thấy một hàng dài GPTBot, OAI-SearchBot, ChatGPT-User, PerplexityBot. Trước khi quyết định chặn hay mở, có một câu hỏi nhàm chán cần trả lời trước: chúng có thật không?

User agent chỉ là một chuỗi text. Bất kỳ scraper nào cũng gửi được OAI-SearchBot/1.3 rồi hy vọng firewall của bạn cho qua. Bài này đi qua cách verify bằng dải IP chính chủ, với một script Python chỉ dùng standard library.

Dải IP chính chủ nằm ở đâu

Các công ty đứng sau những crawler lớn đều publish dải IP họ thực sự dùng. Theo bài gốc, mỗi file là JSON thuần với một list prefixes gồm các entry ipv4Prefix / ipv6Prefix, và tác giả kiểm tra lại toàn bộ vào ngày 26/10/2026.

CrawlerNó làm gìFile IP
OAI-SearchBotĐưa site lên ChatGPT searchopenai.com/searchbot.json
GPTBotThu thập nội dung có thể dùng để trainingopenai.com/gptbot.json
ChatGPT-UserFetch trang khi user ChatGPT hỏiopenai.com/chatgpt-user.json
PerplexityBotIndex site cho kết quả search Perplexityperplexity.com/perplexitybot.json
GooglebotCrawl cho Google Searchdevelopers.google.com/.../googlebot.json

Google còn document thêm một cách DNS riêng cho Googlebot: reverse lookup trên IP, kiểm tra hostname kết thúc bằng googlebot.com hoặc google.com, rồi forward-resolve ngược lại đúng IP đó. Với batch check thì đọc file JSON vẫn gọn hơn.

Script đọc log, đối chiếu IP

Script trong bài gốc chỉ dùng standard library: đọc combined-format log (mặc định của nginx và Apache), lọc request có user agent mang tên crawler, rồi đối chiếu client IP với dải IP mà chủ sở hữu publish. Phần lõi trông như sau (ví dụ minh hoạ, rút gọn từ bài gốc):

nets = {bot: load_networks(url) for bot, url in RANGES.items()}
addr = ipaddress.ip_address(ip)
real = any(addr in n for n in nets[bot] if n.version == addr.version)
results[(bot, "verified" if real else "SPOOFED", status)] += 1

Tác giả chạy thử trên một log mẫu năm dòng tự viết và nhận output:

Googlebot       verified  HTTP 200 x1
OAI-SearchBot   SPOOFED   HTTP 403 x1
OAI-SearchBot   verified  HTTP 200 x1
PerplexityBot   verified  HTTP 200 x1

Ba loại dòng đáng đọc trong output

  • verified kèm HTTP 403 hoặc 429 — crawler thật đang bị bạn chặn, thường là vô tình: một CDN bot rule, một WAF preset, một rate limit. Nếu bạn muốn xuất hiện trong câu trả lời của ChatGPT hay Perplexity, đây là dòng sửa trước.
  • SPOOFED kèm HTTP 200 — ai đó mượn tên crawler để lách rule của bạn. Chặn theo IP là an toàn.
  • Không có dòng nào cho một crawler — hoặc nó chưa ghé, hoặc log rotation đã xoá mất. Kiểm tra robots.txt trước khi kết luận.

Crawl được không đồng nghĩa với được nhắc tên

Đây là giới hạn mà chính tác giả nêu: traffic crawler đã verify chỉ chứng minh engine đọc được trang của bạn, không nói gì về việc engine có nhắc tên bạn khi người dùng hỏi hay không.

Một bài khác cùng ngày đề xuất đo phần còn lại bằng bốn chỉ số tách rời thay vì một điểm tổng: Citation Rate (ví dụ brand xuất hiện trong 45/100 prompt liên quan là 45%), Share of Voice (120 trên 400 lượt nhắc là 30%), Citation Position và Sentiment. Cảnh báo đáng chú ý nhất của bài đó: đừng average qua các engine — ví dụ họ đưa ra là Citation Rate tổng 40% có thể đang che giấu 70% trên ChatGPT và 0% trên Gemini.

Làm gì tiếp

  • Chạy script trên log thật và đọc trước các dòng verified đi kèm 4xx.
  • Đưa dải IP vào firewall allowlist thay vì tin user agent.
  • Refresh file IP định kỳ — field creationTime trong mỗi file cho biết lần cập nhật gần nhất.
  • Thêm url vào counter key để biết crawler đọc trang nào; có thể bạn sẽ thấy OAI-SearchBot đọc blog nhưng chưa bao giờ chạm trang pricing.
  • Đặt cron chạy hàng ngày và alert khi một crawler đã verify nhận 4xx trên trang quan trọng.

Không spam, hủy đăng ký bất kỳ lúc nào.

Bài viết liên quan