目录
背景介绍
随着搜索引擎爬虫变得越来越智能,它们的抓取行为也越来越激进。过度频繁的爬虫访问可能会影响网站性能,甚至导致服务器负载过高。本文将详细介绍如何使用 Nginx 的配置来智能限制爬虫访问频率,同时保持对正常用户的友好访问体验。
实现目标
- 对主流搜索引擎爬虫(Google、Bing、Facebook、Yandex)进行访问频率限制
- 针对爬虫限制:5次/分钟
- 针对普通用户限制:100次/分钟
- 提供完整的测试验证方案
Nginx 配置详解
1. 基础限流规则配置
首先,我们需要创建一个专门的配置文件来存放限流规则(limit_rules.conf):
/etc/nginx/conf.d/limit_rules.conf
# 识别爬虫 User-Agent
map $http_user_agent $isbot_ua {
default 0;
~(GoogleBot|bingbot|YandexBot|mj12bot|facebookexternalhit) 1;
}
# 仅对爬虫进行限流
map $isbot_ua $limit_bot {
default "";
1 $binary_remote_addr;
}
# 定义限流区域
limit_req_zone $limit_bot zone=bots:10m rate=5r/m;
limit_req_zone $binary_remote_addr zone=one:10m rate=100r/m;
配置解析:
map
指令创建变量映射,用于识别爬虫~*
表示大小写不敏感的正则匹配limit_req_zone
定义限流区域和速率10m
表示共享内存区域大小rate
定义请求速率
2. 站点配置
在具体的站点配置中应用限流规则:
/etc/nginx/conf.d/demo-site.conf
server {
listen 80;
listen [::]:80;
server_name IPv4Address;
# 日志配置
access_log /var/log/nginx/access.log combined;
error_log /var/log/nginx/error.log;
location / {
# 当超过限制时返回 429 状态码
limit_req_status 429;
# 爬虫限制:允许5次/分钟
limit_req zone=bots burst=3 nodelay;
# 正常用户限制 允许10次/秒
limit_req zone=one burst=10;
proxy_pass http://127.0.0.1:5000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
验证服务搭建
为了验证配置效果,我们创建一个简单的 Flask 应用:
# server/app.py
from flask import Flask, request, jsonify
app = Flask(__name__)
@app.route('/')
def home():
# 获取客户端IP和User-Agent
client_ip = request.headers.get('X-Real-IP', request.remote_addr)
user_agent = request.headers.get('User-Agent', '')
return jsonify({
'status': 'success',
'client_ip': client_ip,
'user_agent': user_agent,
'message': 'Request received successfully'
})
if __name__ == '__main__':
app.run(host='127.0.0.1', port=5000)
客户端测试实现
我们编写一个 Python 测试脚本来模拟不同类型的请求:
# client/test_client.py
import requests
import time
from concurrent.futures import ThreadPoolExecutor
# 测试用的User-Agent列表
USER_AGENTS = {
'normal': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
'google': 'Googlebot/2.1 (+http://www.google.com/bot.html)',
'bing': 'Mozilla/5.0 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm)',
'facebook': 'facebookexternalhit/1.1',
'yandex': 'Mozilla/5.0 (compatible; YandexBot/3.0; +http://yandex.com/bots)'
}
def make_request(url, user_agent):
headers = {'User-Agent': user_agent}
try:
response = requests.get(url, headers=headers)
return response.status_code
except requests.exceptions.RequestException as e:
return str(e)
def test_rate_limit(url, user_agent_type, num_requests):
print(f"\nTesting with {user_agent_type} User-Agent")
user_agent = USER_AGENTS[user_agent_type]
success_count = 0
rate_limited_count = 0
with ThreadPoolExecutor(max_workers=10) as executor:
futures = []
for _ in range(num_requests):
futures.append(executor.submit(make_request, url, user_agent))
time.sleep(0.1) # 小延迟,避免请求过于密集
for future in futures:
status = future.result()
if status == 200:
success_count += 1
elif status == 429:
rate_limited_count += 1
else:
print(f"Unexpected status code: {status}")
print(f"Results for {user_agent_type}:")
print(f"Success: {success_count}")
print(f"Rate Limited: {rate_limited_count}")
def main():
url = 'http://localhost:5000/'
# 测试不同类型的请求
test_rate_limit(url, 'normal', 120) # 测试正常用户
test_rate_limit(url, 'google', 30) # 测试Google爬虫
test_rate_limit(url, 'bing', 30) # 测试Bing爬虫
test_rate_limit(url, 'facebook', 30) # 测试Facebook爬虫
test_rate_limit(url, 'yandex', 30) # 测试Yandex爬虫
test_rate_limit(url, 'baidu', 30) # 测试未识别的Baidu爬虫
if __name__ == '__main__':
main()
测试结果分析
过运行测试脚本,我们可以观察到:
- 普通用户请求:
- 成功率较高
-
仅在短时突发请求时触发限制
-
爬虫请求:
- 严格遵循每分钟限制
- 超出限制时返回 429 状态码
总结
通过本文的配置方案,我们实现了:
- 智能识别各大搜索引擎爬虫
- 差异化的请求频率限制
- 优雅的限流处理机制
这套配置不仅保护了服务器资源,也确保了正常用户的访问体验。建议根据实际情况调整限流参数,找到最适合您网站的配置。