通过user-agent来源判断阻止爬虫访问网站,并防止生成[ error ] NULL日志

发布于:2025-05-11 ⋅ 阅读:(12) ⋅ 点赞:(0)

一、TP5.0通过行为(Behavior)拦截爬虫并避免生成 [ error ] NULL 错误日志

1. 创建行为类(拦截爬虫)

在 application/common/behavior 目录下新建BlockBot.php ,用于识别并拦截爬虫请求:

<?php
namespace app\common\behavior;

use think\Response;

class BlockBot
{
    // 爬虫User-Agent特征列表
    protected $botPatterns = [
        '/bot/i', '/spider/i', '/curl/i', '/wget/i', 
        '/python/i', '/scrapy/i', '/crawl/i', '/httpclient/i',
        // 下面是自己添加的爬虫
        '/toutiao/i',
        '/zhanzhang.toutiao.com/i',
        '/dataforseo/i',
        '/dataforseo.com/i',
        '/dataforseo-bot/i',
        '/semrush/i',
        '/www.semrush.com/i',
        '/YisouSpider/i',
    ];

    // 白名单(搜索引擎合法爬虫)
    protected $allowPatterns = [
        '/googlebot/i', '/bingbot/i', '/baiduspider/i', '/Sogou web spider/i'
    ];

    public function run()
    {
        $request = request();
        $userAgent = $request->header('user-agent', '');
        $path = $request->path();

        // 白名单放行
        foreach ($this->allowPatterns as $pattern) {
            if (preg_match($pattern, $userAgent)) {
                trace("放行{$pattern}爬虫: UA={$userAgent}, Path={$path}", 'info');
                return;
            }
        }

        // 黑名单拦截
        foreach ($this->botPatterns as $pattern) {
            if (preg_match($pattern, $userAgent)) {

                // 静默记录日志(不触发错误)
                trace("Blocked Bot: UA={$userAgent}, Path={$path}", 'info');

                // 静默拦截(不记录错误日志)
                $this->silentBlock();

            }
        }
    }

    /**
     * 静默拦截逻辑
     */
    private function silentBlock()
    {
        // 返回404页面(或自定义响应)
        $response = Response::create()
            ->code(404)
            ->data('Access Denied')
            ->header(['Content-Type' => 'text/plain']);

        // 终止后续执行
        throw new \think\exception\HttpResponseException($response);
    }

    

}
2. 注册行为到请求事件

在 application/tags.php 中绑定行为到 app_init事件(应用初始化):

return [
    // 应用初始化
    'app_init'     => [
        'app\\common\\behavior\\BlockBot',  //爬虫拦截
    ],
];

3. 自定义异常处理(防止错误日志)
(1) 创建异常处理类

在 application/common/exception 下新建 ExceptionHandler.php,覆盖默认错误处理:

<?php
namespace app\common\exception;

use think\exception\Handle;
use think\exception\RouteNotFoundException;
use think\exception\ValidateException;
use think\Response;

class ExceptionHandler extends Handle
{
    public function render(\Exception $e)
    {
        // 拦截路由不存在错误(常见于爬虫探测)
        if ($e instanceof RouteNotFoundException) {
            return $this->silentResponse(404);
        }

        // 拦截参数验证错误(如分页参数过大)
        if ($e instanceof ValidateException) {
            return $this->silentResponse(400);
        }

        // 其他错误静默记录(可选)
        trace("Silent Error: " . $e->getMessage(), 'error');
        return parent::render($e);
    }

    /**
     * 静默响应(不记录日志)
     */
    private function silentResponse($code)
    {
        return Response::create()
            ->code($code)
            ->data('')
            ->header(['Content-Type' => 'text/plain']);
    }
}
(2) 配置异常处理

在 application/config.php 中指定自定义异常处理器:

// 异常处理配置
'exception_handle' => 'app\common\exception\ExceptionHandler',
4. Nginx层优化(可选)

在服务器配置中拦截部分爬虫并静默处理:

server {
    listen 80;
    server_name yourdomain.com;

    # 拦截爬虫User-Agent并静默处理
    if ($http_user_agent ~* (bot|spider|python|curl|wget)) {
        access_log off;  # 不记录访问日志
        return 444;     # 静默关闭连接
    }

    # 不记录404错误日志
    error_page 404 = /404;
    location = /404 {
        internal;
        access_log off;
    }

    # ThinkPHP伪静态规则
    location / {
        if (!-e $request_filename) {
            rewrite ^(.*)$ /index.php?s=$1 last;
            break;
        }
    }
}

二、TP5.1或TP6.0通过中间件(middleware)拦截爬虫并避免生成 [ error ] NULL 错误日志

以TP5.1演示:

1. 创建拦截中间件(核心逻辑)

在 application/common/middleware 下新建 BlockBot.php,实现 双重防护:

<?php
namespace app\common\middleware;

use think\Response;

class BlockBot
{
    // 爬虫User-Agent特征列表
    protected $botPatterns = [
        '/bot/i', '/spider/i', '/curl/i', '/wget/i', 
        '/python/i', '/scrapy/i', '/crawl/i', '/httpclient/i'
    ];

    // 白名单(搜索引擎合法爬虫)
    protected $allowPatterns = [
        '/googlebot/i', '/bingbot/i', '/baiduspider/i'
    ];

    public function handle($request, \Closure $next)
    {
        $userAgent = $request->header('user-agent', '');
        $path = $request->pathinfo();

        // 放行白名单爬虫
        foreach ($this->allowPatterns as $pattern) {
            if (preg_match($pattern, $userAgent)) {
                return $next($request);
            }
        }

        // 拦截黑名单爬虫
        foreach ($this->botPatterns as $pattern) {
            if (preg_match($pattern, $userAgent)) {
                // 静默记录日志(不触发错误)
                trace("Blocked Bot: UA={$userAgent}, Path={$path}", 'info');
                
                // 直接返回404或403,避免后续逻辑执行
                return response('', 404)->header([
                    'Content-Type' => 'text/html; charset=utf-8'
                ]);
            }
        }

        return $next($request);
    }
}
2. 注册中间件(全局生效)

修改 application/config.php 配置,确保中间件在最优先执行:

// 中间件配置
'middleware' => [
    'app\common\middleware\BlockBot', // 添加此行到最前面
    // ...其他中间件
],
3. 防止生成 [ error ] NULL 日志
(1) 自定义错误处理(覆盖ThinkPHP5默认行为)

在 application/config.php 中配置:

// 错误处理配置
'exception_handle'       => 'app\common\exception\ExceptionHandler',

创建 application/common/exception/ExceptionHandler.php:

<?php
namespace app\common\exception;

use think\exception\Handle;
use think\exception\RouteNotFoundException;
use think\exception\ValidateException;
use think\Response;

class ExceptionHandler extends Handle
{
    public function render(\Exception $e)
    {
        // 拦截路由不存在错误(常见于爬虫探测)
        if ($e instanceof RouteNotFoundException) {
            return $this->silentResponse(404);
        }

        // 拦截参数验证错误(如分页过大)
        if ($e instanceof ValidateException) {
            return $this->silentResponse(400);
        }

        // 其他错误按需处理(此处静默记录)
        trace("Silent Error: " . $e->getMessage(), 'error');
        return parent::render($e);
    }

    /**
     * 静默响应(不记录日志)
     */
    private function silentResponse($code)
    {
        return Response::create()
            ->code($code)
            ->data('')
            ->header(['Content-Type' => 'text/plain']);
    }
}
(2) 配置日志过滤

修改 application/config.php 忽略部分错误类型:

// 日志配置
'log' => [
    'type' => 'File',
    'level' => ['error', 'sql'],
    'apart_level' => ['error', 'sql'],
    'ignore_error' => [
        // 忽略路由不存在错误(避免生成 [ error ] NULL 日志)
        'think\exception\RouteNotFoundException',
    ],
],
4. Nginx层优化(双重防护)
server {
    listen 80;
    server_name yourdomain.com;

    # 拦截爬虫User-Agent并静默处理
    if ($http_user_agent ~* (bot|spider|python|curl|wget)) {
        access_log off;  # 不记录访问日志
        return 444;      # 静默关闭连接
    }

    # FastAdmin伪静态规则
    location / {
        if (!-e $request_filename) {
            rewrite ^(.*)$ /index.php?s=$1 last;
            break;
        }
    }

    # 不记录404错误日志
    error_page 404 = /404.html;
    location = /404.html {
        internal;
        access_log off;
    }
}

网站公告

今日签到

点亮在社区的每一天
去签到