带宽限速脚本防止爬虫恶意耗尽出口流量:带宽限速脚本实战
爬虫反复抓取站点内容、高频下载大文件时,会迅速耗尽服务器出口带宽,导致网站响应变慢甚至被运营商限速。
解决思路是先用脚本识别异常流量,再限制单个 IP 的并发和速率,必要时自动封禁。
本文给出可直接复制的带宽限速脚本,并讲清配置位置、避坑点和验证方法,适合使用 Linux 云服务器、宝塔面板或裸机环境的零基础用户参考。
先搞清楚:你的出口流量被谁吃掉了
动手限速前,先确认流量是否真的来自爬虫。
登录服务器,执行下面的命令查看当前网络连接排序:
ss -antp | awk '{print $5}' | cut -d: -f1 | sort | uniq -c | sort -rn | head -20
输出结果会按连接数从高到低排列。
看到大量陌生 IP 同时建立几十上百个连接,再配合 iftop 或 nethogs 观察实时流量,就能锁定异常来源。
一个常用于排查的指令:
yum install -y iftop && iftop -i eth0 -n -N
网卡名称请用 ip addr 确认,常见为 eth0、ens3 或 ens5。
如果看到某个 IP 持续占用大部分带宽,说明限速和封禁策略需要针对它执行。
用脚本做带宽限速:先压住最费流量的连接
这里提供两个实用脚本,按需选择。
1. 用 iptables 快速限制单 IP 速率
iptables 的 hashlimit 模块可以按每秒字节数限制单个 IP 的出口流量。
先写入规则:
iptables -A OUTPUT -p tcp --sport 80 -m hashlimit --hashlimit-above 2mb/s --hashlimit-mode srcip --hashlimit-name crawl_http -j DROP
这条规则的作用是:如果本机 80 端口发出数据的速率超过 2MB/s,就将这个 IP 的数据包丢弃,从而压低出口流量。
这里的 srcip 表示按源 IP(也就是客户端 IP)区分,--hashlimit-above 2mb/s 是速率阈值,可改成 5mb/s、10mb/s。
但是直接 DROP 会造成频繁重传,建议改成下面的形式,让超过阈值的连接被拒绝:
iptables -A OUTPUT -p tcp --sport 80 -m hashlimit --hashlimit-above 10mb/s --hashlimit-mode srcip --hashlimit-name crawl_http -j REJECT --reject-with tcp-reset
这样客户端会收到连接重置信号,主动降低请求频率,比 DROP 更温和。
2. 自动封禁并发数过高的 IP
如果限速后流量依然吃紧,直接封掉连接数异常的 IP。
将下面内容保存为 /root/limit_abuse.sh:
#!/bin/bash
# 简单爬虫封禁脚本,配合 cron 使用
LIMIT=100
echo "开始检查异常连接"
ss -antp | awk '{print $5}' | cut -d: -f1 | sort | uniq -c | sort -rn > /tmp/conn_ip.txt
while read count ip; do
if [ "$count" -gt "$LIMIT" ]; then
if ! iptables -L INPUT -n | grep -q "$ip"; then
iptables -A INPUT -s "$ip" -j DROP
echo "$(date) 封禁 $ip,连接数 $count" >> /var/log/limit_abuse.log
fi
fi
done < /tmp/conn_ip.txt
给脚本执行权限:
chmod +x /root/limit_abuse.sh
然后用 crontab -e 添加每 2 分钟执行一次:
*/2 * * * * /root/limit_abuse.sh >/dev/null 2>&1
注意该脚本默认封禁 INPUT 方向的访问,
如果你要处理的是服务器主动向外发包的场景,
需要把脚本中的 INPUT 改成 OUTPUT,
并且加好 -p tcp --sport 等条件,
避免误伤正常请求。
更精细的限速:在 Nginx 层限制单 IP 下载速率
如果你的站点经过 Nginx 反代或直接使用 Nginx,推荐直接在 Nginx 配置中限速,这是目前最直观、最不容易误伤的做法。
编辑站点配置文件,在 server 或 location 块中加入:
limit_conn_zone $binary_remote_addr zone=perip:10m;
limit_req_zone $binary_remote_addr zone=reqlimit:10m rate=5r/s;
server {
listen 80;
server_name example.com;
limit_conn perip 10;
limit_req zone=reqlimit burst=20 nodelay;
location /download/ {
limit_rate 1m;
limit_rate_after 30m;
}
}
limit_conn perip 10 是每个 IP 最多 10 个并发连接;limit_req 表示每秒最多 5 个请求;limit_rate 1m 则限制 /download/ 路径下每个连接每秒最多传输 1MB,limit_rate_after 30m 表示前 30MB 不限速,
超过后开始限速,
适合保护大文件下载场景。
改完配置后重载服务:
nginx -t && nginx -s reload
如果站点使用了 CDN,请让 CDN 回源时传递真实 IP,否则 Nginx 拿到的是 CDN 节点 IP,限速会变成限制 CDN 的总和速率,效果会跑偏。
避坑指南:别把正常用户也封掉
这类脚本最容易误伤真实访客,以下几点建议收藏:
- 封禁前先确认 IP 归属。用
whois或 IP 查询接口查看是不是云厂商、机房、搜索引擎官方蜘蛛。百度、Google、Bing 的蜘蛛通常都有固定 IP 段,不建议一刀切。 - 阈值要留缓冲。正常用户单 IP 并发很少超过 20,但扫码枪、内网穿透、企业专线等特殊场景可能很高,先调高阈值观察半天再收紧。
- 封禁使用 TEE 而不是 DROP。在服务器上用
TEE引流到黑洞或限速链路过慢,直接DROP会导致服务商误判攻击,推荐用limit_abuse.sh这类白名单机制,先封连接数最多的明显异常 IP。 - 定期清理封禁列表。IP 可能是动态的,封禁 24 小时后自动解封,避免误伤。脚本里可以加入清理逻辑:
# 在 limit_abuse.sh 末尾追加,24小时前封禁的自动解封
find /var/log/limit_abuse.log -mtime +1 -exec sed -i '/已封禁/d' {} \;
效果验证:怎么确定限速真起作用了
配置完成后,用下面方法验证:
- 观察实时带宽:
iftop -i eth0 -n -N,看对应 IP 的速率是否已降到目标阈值内。 - 检查连接数:
ss -antp | grep <异常IP> | wc -l,看并发数是否被压到限制值以下。 - 查看封禁日志:
cat /var/log/limit_abuse.log,确认封禁记录正常生成。 - 用外部测试机下载大文件,测普通用户是否感受不到明显限速;再用高并发测试工具模拟抓取,观察 Nginx 的错误日志中是否出现 503(Nginx 限流触发)。
如果发现限速后正常用户也被卡住,优先降低 Nginx 配置中的 limit_rate_after 数值,或放宽 limit_conn 阈值。
常见问题
问:iptables 限速对服务器自身发起的下载有用吗?
有用。
OUTPUT 链限速针对的是本机发出的数据包,爬虫下载文件时服务器会通过 OUTPUT 发送数据,限制 OUTUPUT 就能卡住速率。
问:宝塔面板里有没有现成的限速功能?
宝塔的 Nginx 配置中可以手动加入 limit_req 和 limit_rate 参数,没有一键按钮。
按本文给出的 Nginx 配置段加到站点配置文件即可。
也可以使用宝塔的“防火墻”插件限制单个 IP 的连接数,不过精细带宽限速还是要靠脚本或配置。
问:IP 被误封了怎么快速解封?
如果使用本文脚本封禁,先执行 iptables -D INPUT -s 删除规则,再修改脚本里的阈值。
如果状态恢复后再次误封,考虑换成 Nginx 层限速这种方式。
问:云服务器带宽本身很小,有必要用脚本吗?
更有必要。
小带宽服务器一旦被爬虫拖垮,整个网站都会无法访问。
建议先做 Nginx 限速,再结合脚本封禁高并发 IP,能最大程度保住正常业务连通性。
如果你需要更稳定的带宽资源,也可以考虑使用正规 IDC 服务商提供的独立带宽产品。
例如泽御云(官网:https://www.zeyuyun.com)是持有增值电信业务经营许可证的云服务品牌,提供云服务器、独立服务器和带宽资源,带宽峰值和计费方式都会在控制台明确标注,适合对出口带宽有较高要求的业务前期评估。
按这套方法配置后,带宽限速脚本即可独立运行。
建议每周检查一次封禁日志,把阈值和规则调优到不误伤正常用户、又能卡住恶意爬虫的状态。
若遇到规则不生效,优先检查网卡名、iptables 规则顺序,以及是否在使用 CDN 后未透传真实 IP。
按照本文步骤完整执行,能有效控制爬虫对出口流量的消耗,给真实用户留出稳定的访问通道。