site logo

Marico's space

Magento 2 爬虫与 Bot 流量管理——阻止恶意 Bots 拖垮你的性能

AI技术与应用 2026-07-22 21:00:09 6

最近帮几个朋友的Magento 2站点做性能优化,踩了不少爬虫相关的坑。站点流量看着还行,但服务器动不动就卡死,CDN账单莫名暴涨,一查日志才发现是被各种 Bots 爬到崩溃。一个不守规矩的爬虫,能在几个小时内把服务器负载翻倍,把你的带宽费用打出天际。

这篇文章把Bot流量识别、合法爬虫优化、恶意爬虫拦截讲清楚,全是可落地的方案,Nginx、Varnish、应用层都有覆盖。

为什么 Bots 对 Magento 2 性能影响这么大

Magento 是出了名的重型框架。每个未缓存的页面请求都要经历:

  • PHP-FPM 渲染模板
  • MySQL 查询 EAV 商品数据
  • Redis 查找 session 和缓存数据
  • Elasticsearch 调用分层导航

真实用户一次访问也就看个5-10个页面,而一个爬虫一小时能扫5万个URL。这个差距不用我多说了吧。

假设你有个5万SKU的商城,一个不懂事的爬虫把所有商品链接、筛选组合、分页链接全走一遍,产生的请求量能把你真实用户的访问量秒成渣。

Bot 流量典型的杀伤效果:

  • 缓存命中率从85%跌到40%——因为 Bots 请求的 URL 全是唯一的
  • MySQL 连接池被打满——并发查 catalog_product_entity
  • Elasticsearch 集群 CPU 飙高——聚合 facet 查询被打爆
  • CDN 流量费用暴涨——非缓存页面被 Bots 消耗

如果你的统计分析里出现一堆"直接访问"、跳出率100%、页面停留时间0秒,很可能就是 Bot 流量在伪装成真实用户。

从日志里识别 Bot 流量

动手之前先搞清楚状况。从访问日志入手是最直接的方式。

Nginx 访问日志分析

# 按 User-Agent 统计请求量 TOP 20
awk -F '"' '{print $6}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -20 # 按 IP 地址统计请求量 TOP 20
awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -20 # 统计 Bot 流量总量
awk '/Googlebot|bingbot|AhrefsBot|SemrushBot|MJ12bot/ {sum++} END {print sum}' /var/log/nginx/access.log

Magento 应用层检测

在 Magento 内部扩展 Http 上下文或者用 Observer 记录可疑模式:

<?php
namespace Vendor\BotLogger\Observer; use Magento\Framework\Event\Observer;
use Magento\Framework\Event\ObserverInterface;
use Magento\Framework\HTTP\PhpEnvironment\Request;
use Psr\Log\LoggerInterface; class LogBotTraffic implements ObserverInterface
{ public function __construct( private Request $request, private LoggerInterface $logger ) {} public function execute(Observer $observer): void { $userAgent = $this->request->getHeader('User-Agent') ?? ''; $ip = $this->request->getClientIp(); // Detect known bots $bots = ['Googlebot', 'bingbot', 'AhrefsBot', 'SemrushBot', 'MJ12bot', 'DotBot']; foreach ($bots as $bot) { if (stripos($userAgent, $bot) !== false) { $this->logger->info('BOT_TRAFFIC', [ 'bot' => $bot, 'ip' => $ip, 'url' => $this->request->getRequestUri(), 'time' => microtime(true) ]); break; } } }
}

把这个日志单独存,配合 Grafana、阿里云日志服务或者腾讯云监控来追踪。

robots.txt —— 第一道防线

一个配置得当的 robots.txt 是引导合法爬虫远离高消耗页面的最简单手段。

文件放在 pub/robots.txt(如果你 webroot 是 pub/ 的话):

User-agent: *
Disallow: /admin/
Disallow: /checkout/
Disallow: /customer/
Disallow: /catalogsearch/
Disallow: /sales/guest/
Disallow: /wishlist/
Disallow: /compare/
Disallow: /review/product/post/
Disallow: /newsletter/
Disallow: /sendfriend/
Disallow: /catalog/product_compare/
Disallow: /*?*price=
Disallow: /*?*color=
Disallow: /*?*size=
Disallow: /*?*material=
Disallow: /*?*limit=
Disallow: /*?*order=
Disallow: /*?*dir=
Disallow: /*?*mode= # Allow CSS/JS/images for rendering
Allow: /pub/media/catalog/product/
Allow: /pub/static/ # Sitemap for efficient crawling
Sitemap: https://yourstore.com/sitemap.xml # Crawl delay for all bots
Crawl-delay: 2

关键规则解释:

  • 禁止分层导航参数——price、color、size、material 这些筛选条件能生成成千上万个 URL,但内容其实差不多。这些既是 SEO 噩梦,也是性能杀手。
  • 禁止比较和心愿单——这些都是用户私有的,根本不该被爬。
  • 设置爬取间隔——单个爬虫两次请求间隔2秒是合理的要求。
  • 提供 sitemap——引导爬虫去你的标准 URL,别让它自己摸索各种筛选组合。

Magento 特有的坑

如果你的 webroot 是 pub/(安全最佳实践),robots.txt 要放在 pub/robots.txt。别放错了位置。

robots.txt 只能防君子,不能防小人——恶意爬虫根本不会理它。

Nginx 限流——拦截 Bots 的第二道防线

在 Web 服务器层面做限流,能保护 PHP-FPM 和 MySQL 不会被冲垮。

基于 Zone 的限流

# In http context (nginx.conf)
limit_req_zone $binary_remote_addr zone=general:10m rate=10r/s;
limit_req_zone $bot_zone zone=bots:10m rate=1r/s; # Map user agents to bot classification
map $http_user_agent $bot_zone { default ""; ~*(Googlebot|bingbot) $binary_remote_addr; ~*(AhrefsBot|SemrushBot) $binary_remote_addr; ~*(MJ12bot|DotBot|BLEXBot) $binary_remote_addr; ~*(Screaming|Majestic) $binary_remote_addr; ~*crawler $binary_remote_addr; ~*spider $binary_remote_addr;
} # In server context (site config)
server { # General limit for all traffic limit_req zone=general burst=20 nodelay; # Stricter limit for identified bots location / { if ($bot_zone != "") { limit_req zone=bots burst=5 nodelay; } try_files $uri $uri/ /index.php$is_args$args; } # Always allow static assets (they're cached and cheap) location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg|woff|woff2)$ { limit_req off; expires 1y; add_header Cache-Control "public, immutable"; }
}

这个配置能达到的效果:

  • 普通流量:每个 IP 每秒10个请求,允许20个突发
  • Bots:每个 IP 每秒1个请求,允许5个突发——合法爬虫够用,激进爬虫会很难受
  • 静态资源:不限流——图片和 CSS 从缓存里拿,不值钱

Nginx + Lua 动态拦截

进阶玩法是用 OpenResty/Nginx 配合 Lua,根据行为动态封禁 Bots:

-- nginx.conf lua_shared_dict blocklist 10m;
init_worker_by_lua_block { local blocklist = ngx.shared.blocklist -- Preload known bad actors blocklist:set("185.220.101.0/24", true, 86400)
} access_by_lua_block { local blocklist = ngx.shared.blocklist local ip = ngx.var.remote_addr if blocklist:get(ip) then ngx.exit(ngx.HTTP_FORBIDDEN) end -- Block by excessive requests (detected via log analysis) local req_count = blocklist:incr(ip .. ":count", 1, 0, 60) if req_count > 100 then blocklist:set(ip, true, 3600) -- Block for 1 hour ngx.log(ngx.WARN, "Auto-blocked IP for excessive requests: ", ip) ngx.exit(ngx.HTTP_TOO_MANY_REQUESTS) end
}

Varnish 缓存策略——让 Bots 帮你分担流量

Varnish 可以区分人类和 Bots,给他们用不同的缓存策略。

Bot 感知的 VCL 配置

sub vcl_recv { # Normalize user agent for bot detection if (req.http.User-Agent ~ "(Googlebot|bingbot|Slurp|DuckDuckBot|Baiduspider|YandexBot)") { set req.http.X-Bot = "true"; } else { set req.http.X-Bot = "false"; } # Don't cache admin, checkout, customer area for anyone if (req.url ~ "^/(admin|checkout|customer)/") { return (pass); } # Cache product pages for bots with longer TTL (they don't need fresh prices instantly) if (req.http.X-Bot == "true" && req.url ~ "^/catalog/product/view/") { unset req.http.Cookie; return (hash); } # For humans, respect cookies if (req.http.Cookie) { # Strip all but essential cookies set req.http.Cookie = regsuball(req.http.Cookie, "(^|;)\s*__[a-z]+=[^;]*", ""); set req.http.Cookie = regsub(req.http.Cookie, "^;\s*", ""); if (req.http.Cookie == "") { unset req.http.Cookie; } }
} sub vcl_backend_response { # Cache product pages for bots longer if (bereq.http.X-Bot == "true" && bereq.url ~ "^/catalog/product/view/") { set beresp.ttl = 1h; set beresp.grace = 6h; } # Cache category pages for everyone if (bereq.url ~ "^/catalog/category/view/") { set beresp.ttl = 15m; set beresp.grace = 1h; }
} sub vcl_deliver { # Add debug header (remove in production) set resp.http.X-Cache-Status = req.http.X-Bot;
}

Bot 特供缓存的好处:

  • 商品页:Bots 的 TTL 设成1小时——它们对实时价格不敏感
  • 分类页:所有人的 TTL 都是15分钟——Bots 和人类拿到的缓存内容一样
  • Grace 机制:回源拿新数据时先给旧缓存,防止后端被打爆

封禁恶意 Bots

不是所有 Bots 都守规矩。有些根本不管 robots.txt,伪装 User-Agent,疯狂爬你的站。

Nginx 恶意 Bot 拦截

可以用 Nginx Bad Bot Blocker 或者自己写个精简版:

# Block known bad user agents
if ($http_user_agent ~* (ahrefsbot|semrushbot|mj12bot|dotbot|blexbot|ezooms|yandexbot|baiduspider|sogou|exabot|facebot|facebookexternalhit)) { # Allow search engines, block SEO tools and scrapers if ($http_user_agent !~* (googlebot|bingbot|slurp|duckduckbot)) { return 444; #