需通过服务端动态干预精细化控制爬虫:一、动态生成robots.txt;二、PHP层UA匹配拦截;三、IP+UA组合频控;四、响应头注入速率提示;五、伪静态路由拦截恶意路径。

如果您在PHP网站中希望精细化控制各类爬虫的访问权限与抓取节奏,则需突破静态robots.txt的局限,转向服务端动态干预。以下是实现该目标的具体策略:
一、动态生成robots.txt响应
通过PHP脚本替代静态文件,使robots.txt内容可根据时间、IP段、UA特征或服务器负载实时变化,从而对不同爬虫施加差异化指令。
1、在网站根目录创建robots.php文件,设置其HTTP响应头为text/plain。
2、在文件开头添加:header('Content-Type: text/plain');
立即学习“PHP免费学习笔记(深入)”;
3、使用$_SERVER['HTTP_USER_AGENT']识别百度、谷歌、必应等主流爬虫UA字符串。
4、对百度蜘蛛(Baiduspider)返回User-agent: Baiduspider\nCrawl-delay: 10;对Googlebot则返回User-agent: Googlebot\nCrawl-delay: 5。
5、将Web服务器配置为将对/robots.txt的请求重写至robots.php,例如Nginx中添加:rewrite ^/robots\.txt$ /robots.php last;
二、PHP层UA匹配+行为拦截
在关键入口文件(如index.php或公共初始化脚本)中嵌入实时UA判断逻辑,对高风险爬虫实施访问阻断或限速跳转,避免其进入业务处理流程。
1、定义需限制的爬虫标识数组,包含'SemrushBot'、'AhrefsBot'、'MJ12bot'等商业采集器。
2、调用stripos($_SERVER['HTTP_USER_AGENT'], $bot)进行子串匹配,避免正则开销。
3、若匹配成功且当前时间为工作日9:00–18:00,执行http_response_code(429)并输出Retry-After: 3600头部。
4、对未匹配但UA含bot或crawl的请求,记录至访问日志并允许通行,供后续分析。
5、确保该逻辑位于session_start()之前,防止因会话初始化引入额外延迟。
三、基于IP+UA组合的请求频控
结合客户端真实IP(需校验X-Forwarded-For可信性)与User-Agent,构建二维计数器,防止单一维度绕过限制,实现更精准的速率管控。
1、使用Redis存储键名格式为rate:ip_ua:{md5($ip.'|'.$ua)},有效期设为60秒。
2、每次请求前执行INCR key,若返回值大于5,则立即返回429 Too Many Requests。
3、在Nginx配置中启用real_ip模块,将CDN或代理的真实IP写入$remote_addr变量。
4、对百度蜘蛛单独启用宽松策略:当UA匹配Baiduspider时,阈值提升至20次/60秒。
5、所有计数操作须包裹try-catch,Redis连接失败时降级为仅记录日志,不中断正常访问。
四、响应头注入Crawl-Delay与RateLimit提示
在HTML页面或API响应中主动嵌入标准化速率提示字段,向支持HTTP标头解析的智能爬虫传达友好约束信号,无需依赖robots.txt解析。
1、在PHP输出前调用header('X-Robots-Tag: noindex, nofollow')对测试路径或后台接口生效。
2、对列表页响应添加:header('Retry-After: 30'); 表明建议重试间隔为30秒。
3、对高频访问的搜索接口,附加RateLimit-Limit: 100、RateLimit-Remaining: 92、RateLimit-Reset: 1747900800三组标准头。
4、使用getallheaders()捕获原始请求头,若发现X-Request-ID存在则复用其值生成日志追踪ID。
5、禁用所有输出缓冲(ob_end_flush()),确保响应头在内容前完整发出。
五、伪静态路由拦截恶意爬虫路径
利用PHP框架或原生路由机制,在URL解析阶段即识别并拦截已知爬虫偏好的高危路径模式,如/wp-content/、/admin/、/phpmyadmin/等,从源头减少无效请求消耗。
1、在入口文件顶部定义黑名单路径正则数组:['/wp-.*', '/\.git/', '/\.env$', '/backup.*\.sql$']。
2、使用preg_match匹配$_SERVER['REQUEST_URI'],命中任一规则立即终止。
3、对匹配请求记录HTTP_X_FORWARDED_FOR与HTTP_USER_AGENT至独立日志文件。
4、返回403 Forbidden状态码,并输出空响应体,避免泄露服务器信息。
5、将该逻辑封装为独立函数blockMaliciousPaths(),在所有控制器加载前调用。



















