
开发者发现其网站90%的“人类”访客实为机器人
来源标题:90% of my "human" visitors were bots
一名开发者核查自建分析后发现,其 Orbital Market 网站仪表盘统计的“人类访客”中约90%其实是机器人。该仪表盘仅通过匹配常见的爬虫和自动化工具 User-Agent 来过滤,凡是声称 Chrome、Firefox 或 Safari 的流量都被计为真人。一次异常流量尖峰促使他进一步排查并得出这一结论。
以下正文由 AI 翻译自 Hacker News 最新(原文版权归原站所有),可能存在偏差,重要内容请以原文为准。
前阵子我在 Reddit 上问大家还在不在用 Orbital Market——那是我业余做的一个项目。后台数据显示每天有 1200 个独立访客,说实话我根本不知道这些是真人还是机器人。
所以当 Luna Park 的仪表盘显示一周有 2500 个人类访客时,我承认我挺开心的,也没去怀疑这个数字。我知道,这不算多,但好歹……也算有点成绩吧!
后来一个奇怪的尖峰让我仔细看了看,结果发现这些"人类"大部分都是机器人。
我们的分析是自托管的:nginx 写访问日志,Telegraf 把日志解析进 InfluxDB,Grafana 负责画图。网站上没有第三方脚本,所以访问日志就是我们唯一的依据。
因为我不想在网站上塞一个臃肿的第三方脚本,而且大多数广告拦截器本来就会把它拦掉。
为了统计人类,仪表盘保留 HTML 页面浏览,并剔除所有匹配下面这个正则的 user agent:
bot|crawl|spider|slurp|headless|facebookexternalhit|googleother|python|curl|go-http|wget|preview|scan|fetch|lighthouse
这样就去掉了 Googlebot、GPTBot、链接预览等等……剩下的全都自称是 Chrome、Firefox 或 Safari,于是仪表盘就把它们当成了人类。
看图表的时候,我注意到一个比其他尖峰高 5 倍的尖峰:大约 200 次页面浏览,全部来自同一个 IP。
/robots.txt /sitemap.xml /docs/sitemap.xml /branding /blog /docs/fr/backend-data/auth …
基本上,它读取了 sitemap,然后挨个访问了里面的地址:
当它跟随重定向时,还会把重定向的 URL 作为 Referer 发出去。浏览器不会这么做,但 Go 的 net/http 客户端会。
所以这大概率是一个用了 Chrome user agent 的 Go 脚本。
我可以封掉它,但我不知道是谁在跑。可能是某个 SEO 工具,也可能是 AI 爬虫,而我其实希望 Luna Park 能出现在搜索结果和 LLM 的回答里。我只是不想让它算进我的数据里。
而且这招确实有用:过去 90 天里,大约有 50 个访客是从 ChatGPT 里的链接过来的。
问题在于,浏览器必须下载页面的 JavaScript 和 CSS 才能显示页面,而一个只想要文本的爬虫没理由去下载这些。
没下载 CSS => 不是浏览器 => 不是人类。于是我加了一条规则:只有同一个 IP 当天也加载了 .js 或 .css 文件,这次页面浏览才算数。
那那些所有资源都在缓存里的回访用户怎么办?
说得对,他们会被漏掉:我们的资源缓存一年,所以回访的浏览器在我们重新部署之前不会再请求它们。我查了一下:大约占统计数的 2%。我们部署很频繁,每次部署都会改一些文件名,这有帮助。
在平常的一天里,大约有 300 个 IP 通过了 user agent 过滤,其中只有约 50 个加载了任何资源。其余大多数没有 referrer,直接访问 /,而且自称是相当老的浏览器,比如 iOS 13 上的 iPhone(2019 年的系统……)或者 Chrome 120。
加上这条规则后,每周的计数从 2500 掉到了 380……哎哟。
第二天晚上出现了一波"爆发",一小时内有 10 多个访客,全都通过了新检查。我把它们列出来时,模式非常明显:
43.134.109.74 /docs/fr/logic/scripts 43.156.2.23 /docs/fr/logic/variables 43.163.82.79 /docs/fr/interface/templates 43.173.164.79 /compare/draftbit 101.32.115.248 /docs/fr/styling/typography …
每个 IP 只加载一个页面,没有 referrer,而且大多是法语文档。它会执行页面的 JavaScript,所以是真正的无头 Chrome。
而这些 IP 全都来自腾讯的数据中心。它从每天约 100 次请求,一个月内涨到了约 700 次。有些日子,它占到了我们"人类"的一半。
每个页面换一个 IP 可以绕过按 IP 的速率限制,但没人会从云服务器上浏览网页。所以我排除了腾讯的 IP 段:
43.128.0.0 - 43.175.255.255 101.32.0.0 - 101.33.255.255 124.156.0.0/16 150.109.0.0/16
每周计数从 380 掉到了 290。
但腾讯只是我那天晚上恰好抓到的。其他云呢?于是我用一个免费的 ASN 数据库,把过去 90 天的每个 IP 映射到了它的网络所有者。
我们所有请求中有 43% 来自云和托管网络:
而且即使在通过了两道检查的"人类"里,也还有不少:
于是我排除了所有出现过"人类"的云的 IP 段:15 个网络的大约 190 个 IP 段。
每周计数从 290 掉到了 230,页面浏览掉得更多,从约 1300 降到约 400。
嗯,有些 VPN 也跑在数据中心 IP 上,所以现在可能有一些被误伤了。但说实话,大多数人不会通过 VPN 浏览网页,所以我乐意排除所有云。
问题在于,我的过滤规则是一份 IP 段列表,而"所有云"大约有 4 万个段(那就是一个 1 MB 的正则……)。这就是"接下来做什么"里那个每日任务要干的事。
幸运的是,我有办法验证。Luna Park 有自己的访客计数器,叫 Turnstile(记得吗,主题公园),它完全不用访问日志。
它统计到每周大约 220 个访客。所以 230 这个数字挺接近的,而 2500 则高出了 10 倍以上。
它仍然不完美:挂在住宅代理上的无头浏览器能通过,下一个用我没列出的云的爬虫也能通过。
趁着这个机会,我把过去 90 天里每一个尖峰都过了一遍。大多数都是常见的噪音,但有几个值得一说。
找 AI 密钥的。90 天里有 86 天,有东西在请求这样的文件:
/.aws/credentials /.claude/settings.json /.env.anthropic /.anthropic/config.json /.cursor/mcp.json
这大约是来自近 250 个 IP 的 2700 次请求,在找服务器上被误留下的 AI API 密钥。有一天,几个 Google Cloud 的 IP 各自发送了完全相同的约 280 次请求。显然是同一个工具。
法国国家图书馆。它的机器人(bnf.fr_bot)归档了我们的网站:一小时内约 500 次请求。所以 Luna Park 现在正式成为法国网络遗产的一部分了 :)
一次真正的人类尖峰!真人最大的一波爆发,是 13 个人用 Luna Park 的实时活动和挑战超过一个小时。我兴奋了一秒……然后意识到那是我们自己,在办一场工作坊。
(原文较长,此处译出前 6000 字,完整内容请点「打开原文」。)
正文由 探How 从来源站点 RSS 同步,内容未经改写;遇到排版缺失或需要图片、视频时请以原文为准。