Bot 流量“假阳性”调优笔记 - 实践

日志里 80% 的 404 都来自同一个 User-Agent,但把它直接拉黑又怕误伤真用户。本文记录了我们如何用 150 行 Python 写出一个实时标记脚本,并把它无缝接入已有的高防 IP 回源链路。


背景

公司运营了一款小游戏,前端每 5 秒会轮询一次 /api/heartbeat 保活。
最近监控发现,该接口 404 率飙到 30%,但把出现 404 的 UA 拉黑后,日活直接掉 5%。显然里面混进了高仿爬虫,规则写太粗就会误杀。

思路:把“行为”抽象成特征,而不是死盯 UA

我们决定用一条极简的机器学习流水线:

  1. 采集:在高防 IP 回源段上开一个旁路端口,镜像 1% 流量到本地;
  2. 特征:把一次会话(IP + UA + 5 min 窗口)抽象成 4 个数值特征
    • ratio_404:404 占比
    • avg_interval:心跳间隔均值
    • entropy_path:访问路径熵
    • is_night:是否凌晨 0-6 点
  3. 模型:用 sklearn 现成的随机森林,正负样本各 1 万条,训练 30 s 搞定;
  4. 动作:模型输出概率 > 0.8 的会话,实时推送到高防 IP 的“自定义封禁 API”,30 秒生效。

关键代码

下面这段脚本跑在回源机房的一台 2C4G 小水管上,占用内存不到 30 MB。
核心依赖只有 pandas + scikit-learn,可以随镜像一起打包。

#!/usr/bin/env python3
import json, time, requests
from collections import defaultdict
from sklearn.ensemble import RandomForestClassifier
from sklearn.externals import joblib
MODEL = joblib.load('bot_model.pkl')
API = 'https://api.anycast-clean.com/v1/ban ' # 高防 IP 提供的封禁接口
TOKEN = 'YOUR_SECRET_TOKEN'
session = defaultdict(lambda: {
'paths': [], 'codes': [], 'ts': []
})
def ingest(line):
# 假设日志格式: 2025-08-19T12:00:00 ip ua path code
_, ip, ua, path, code = line.strip().split(' ', 4)
key = (ip, ua)
session[key]['paths'].append(path)
session[key]['codes'].append(int(code))
session[key]['ts'].append(time.time())
def features(rec):
codes = rec['codes']
paths = rec['paths']
ts = rec['ts']
ratio = codes.count(404) / len(codes)
avg_iv = (max(ts) - min(ts)) / max(len(ts) - 1, 1)
entropy = -sum(p * (p and (p := paths.count(x) / len(paths))) for x in set(paths))
night = 0 <= time.localtime().tm_hour <
6
return [ratio, avg_iv, entropy, night]
def decide():
for key, rec in list(session.items()):
if len(rec['codes']) <
10: # 数据不足
continue
vec = [features(rec)]
prob = MODEL.predict_proba(vec)[0][1]
if prob >
0.8:
ip, ua = key
requests.post(API, json={
'ip': ip, 'ua': ua, 'ttl': 600
}, headers={
'X-Token': TOKEN
})
del session[key]
if __name__ == '__main__':
while True:
line = input()
ingest(line)
if int(time.time()) % 30 == 0:
decide()

部署小贴士

  • 旁路流量:用 iptables -j TEE 把清洗中心回源口的 1% 流量复制给脚本,不影响主链路;
  • 模型更新:每天凌晨跑一次离线训练,生成新的 bot_model.pkl,然后热替换;
  • TTL 设计:封禁 10 min 足够让爬虫换 IP,但真用户即使被误杀,刷新页面即可恢复。

效果

上线 48 h:

  • 404 占比从 30% 降到 2.1%;
  • 日活不降反升 1.8%(推测是爬虫被挡掉后,服务器响应更快);
  • 高防 IP 的账单里,回源流量少 6 TB,意外省下 200 多块。

写在最后

这次实验最大的收获是:与其在规则里“猜”爬虫长什么样,不如把判断逻辑外置到一个能持续学习的边缘节点。群联的清洗中心给出了实时封禁 API,让大家可以把模型结果直接落地,而不用改一行业务代码——这比传统“先打日志、再人工加黑名单”的节奏快了整整一个量级。

posted @ 2025-08-20 08:57  wzzkaifa  阅读(12)  评论(0)    收藏  举报