ThinkPHP无内置“一键封爬虫”功能,需结合中间件UA识别、Nginx层拦截、行为校验与限流四层策略协同防护。

ThinkPHP 框架本身不内置“一键封爬虫”功能,禁止特定爬虫抓取需结合 请求识别 + 响应控制 + 外部协同 三层策略。核心原则是:UA 可伪造,不能当防线;但可作轻量标记与快速拦截起点。
一、用中间件做 UA 轻量识别与拦截(推荐首选)
把判断逻辑从控制器抽离到中间件,统一处理、易维护、不影响业务代码。
- 创建中间件
app/middleware/SpiderBlock.php:<?php declare(strict_types=1);
namespace app\middleware;
use think\Request; use think\Response;
class SpiderBlock { // 白名单(合法客户端 UA 关键词),存配置更佳(见下文) private $allowUaKeywords = ['Chrome', 'Firefox', 'Safari', 'Mobile Safari', 'WeChat'];
// 黑名单关键词(含明显爬虫、扫描器、脚本工具)
private $blockUaKeywords = [
'Baiduspider', 'Googlebot', 'Bingbot', 'YandexBot', '360spider',
'sogouspider', 'Bytespider', 'toutiao', 'msnbot', 'Amazonbot',
'python-requests', 'curl/', 'httpie', 'scrapy', 'playwright',
'headlesschrome', 'phantomjs'
];
public function handle(Request $request, \Closure $next): Response
{
$ua = $request->header('user-agent', '');
// 空 UA 或纯数字/乱码 → 极高风险,直接拦截
if (empty($ua) || preg_match('/^\d+$|^[\x00-\x1f\x7f-\xff]+$/', $ua)) {
return response('Forbidden', 403);
}
// 匹配黑名单(不区分大小写)
foreach ($this->blockUaKeywords as $keyword) {
if (stripos($ua, $keyword) !== false) {
// 可选:记录日志或限流,再拦截
\think\facade\Log::warning('Blocked bot UA', ['ua' => $ua, 'ip' => $request->ip()]);
return response('Forbidden', 403);
}
}
// 白名单仅用于放行加速,不用于信任授权(后续仍需行为校验)
$isTrusted = false;
foreach ($this->allowUaKeywords as $keyword) {
if (stripos($ua, $keyword) !== false) {
$isTrusted = true;
break;
}
}
// 非白名单但也不在黑名单?放行,交由后续风控(如验证码、JS 行为)处理
return $next($request);
}}
立即学习“PHP免费学习笔记(深入)”;
- 在 `app/middleware.php` 中注册(全局或按路由组):
```php
return [
'app\middleware\SpiderBlock' => ['except' => ['api.*']], // 例如 API 接口不拦截
];✅ 优势:不依赖数据库、响应快、支持正则扩展、便于打点统计
❌ 注意:不能防 UA 伪造,仅作为第一道“显性爬虫筛子”
二、配合配置文件管理 UA 规则(解耦+可热更)
把 UA 关键词移到配置中,避免改代码:
-
新建
app/extra/spider.php:<?php return [ 'allow_keywords' => ['Chrome', 'Firefox', 'Safari', 'WeChat', 'QQBrowser'], 'block_keywords' => [ 'Baiduspider', 'Googlebot', 'Bytespider', 'toutiao', 'python-requests', 'curl/', 'scrapy', 'headlesschrome' ], 'block_empty_ua' => true, 'log_blocked' => true, ]; -
中间件中读取:
$config = config('spider'); if ($config['block_empty_ua'] && empty($ua)) { ... } foreach ($config['block_keywords'] as $kw) { ... }
三、强化拦截:Nginx 层提前拒绝(高效兜底)
对高频恶意 UA,直接在 Nginx 拒绝,不进 PHP,节省资源:
- 在站点 Nginx 配置
server { }块内添加(宝塔用户可在【配置文件】中编辑):# 加载外部 UA 黑名单规则(推荐) include /www/server/nginx/conf/kill_bot.conf;
或直接写 inline 判断(简单场景)
if ($http_user_agent ~* "Baiduspider|Googlebot|Bytespider|python-requests|curl/") { return 403; }
- 创建 `/www/server/nginx/conf/kill_bot.conf`(支持多站点复用):
```nginx
# 垃圾蜘蛛
if ($http_user_agent ~* "Baiduspider|Googlebot|YandexBot|360spider|sogouspider|Bytespider|toutiao|msnbot") {
return 403;
}
# 扫描器与脚本工具
if ($http_user_agent ~* "sqlmap|nikto|dirbuster|python-requests|httpie|scrapy|curl/") {
return 403;
}⚠️ 修改后需
nginx -t && nginx -s reload生效(宝塔点【重启】Nginx 即可)
四、补充防护:不只是 UA,还要看行为
光拦 UA 不够,真实对抗需组合判断:
-
检查 Cookie 是否存在(真用户有会话,多数爬虫无):
if (!$request->cookie('thinkphp_token') && !$request->cookie('PHPSESSID')) { // 无会话且 UA 异常 → 加重风控权重 } 前端 JS 注入时间戳字段(防秒提交): 页面加载时用 JS 写
<input type="hidden" name="_ts" value="<?php echo time(); ?>">,服务端比对提交时间差是否 < 800ms。-
Referer 校验(非必须,但对简单爬虫有效):
$referer = $request->header('referer', ''); if (empty($referer) || !str_starts_with($referer, 'https://yourdomain.com')) { // 非站内来源,提高风险分 } -
IP 频次限流(用 ThinkPHP 自带的
throttle中间件):'throttle:10,1' // 每分钟最多 10 次
不靠单一手段,而是用 UA 做初筛、Nginx 做兜底、行为做深判、限流做压制,才能真正让特定爬虫“进得来、拿不走、跑不快”。



















