
Xác minh GPTBot thật hay giả trong access log bằng Python
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.
| Crawler | Nó làm gì | File IP |
|---|---|---|
| OAI-SearchBot | Đưa site lên ChatGPT search | openai.com/searchbot.json |
| GPTBot | Thu thập nội dung có thể dùng để training | openai.com/gptbot.json |
| ChatGPT-User | Fetch trang khi user ChatGPT hỏi | openai.com/chatgpt-user.json |
| PerplexityBot | Index site cho kết quả search Perplexity | perplexity.com/perplexitybot.json |
| Googlebot | Crawl cho Google Search | developers.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.txttrướ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
creationTimetrong mỗi file cho biết lần cập nhật gần nhất. - Thêm
urlvà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

Bảy app Mac cho nửa việc không phải code: Slack, PR, email
24 thg 10, 2026
laya-coreml: quyết định 5 ms trên Apple Neural Engine
16 thg 10, 2026