// +---------------------------------------------------------------------- declare(strict_types=1); namespace ywxapp\library; /** * 搜索引擎蜘蛛识别 * * 仅按 User-Agent 特征串识别(不做 DNS 反查,保证零阻塞)。 * 新增蜘蛛只需在 SPIDERS 追加一行:标识 => [UA特征串列表, 显示名]。 * * @author ywxapp */ class SpiderDetect { /** * 蜘蛛特征表:key=入库标识,value=[UA 特征串(不区分大小写,命中任一即算), 中文显示名] */ public const SPIDERS = [ 'baidu' => [['Baiduspider'], '百度'], 'google' => [['Googlebot', 'Google-InspectionTool', 'AdsBot-Google'], '谷歌'], 'bing' => [['bingbot', 'msnbot', 'BingPreview'], '必应'], 'sogou' => [['Sogou web spider', 'Sogou inst spider', 'Sogou Pic Spider'], '搜狗'], 'so360' => [['360Spider', 'HaoSouSpider', 'qihoobot'], '360'], 'bytedance' => [['Bytespider', 'ToutiaoSpider'], '字节跳动'], 'shenma' => [['YisouSpider'], '神马'], 'huawei' => [['PetalBot'], '华为花瓣'], 'yandex' => [['YandexBot'], 'Yandex'], 'duckduckgo' => [['DuckDuckBot', 'DuckDuckGo-Favicons-Bot'], 'DuckDuckGo'], 'yahoo' => [['Yahoo! Slurp'], '雅虎'], 'apple' => [['Applebot'], '苹果'], 'gptbot' => [['GPTBot', 'ChatGPT-User', 'OAI-SearchBot'], 'OpenAI'], 'claudebot' => [['ClaudeBot', 'anthropic-ai'], 'Anthropic'], 'semrush' => [['SemrushBot'], 'Semrush'], 'ahrefs' => [['AhrefsBot'], 'Ahrefs'], 'mj12' => [['MJ12bot'], 'Majestic'], 'facebook' => [['facebookexternalhit', 'FacebookBot'], 'Facebook'], ]; /** * 识别 UA,命中返回蜘蛛标识(SPIDERS 的 key),未命中返回 null */ public static function detect(string $userAgent): ?string { if ($userAgent === '') { return null; } foreach (self::SPIDERS as $key => [$needles]) { foreach ($needles as $needle) { if (stripos($userAgent, $needle) !== false) { return $key; } } } return null; } /** * 蜘蛛标识 → 中文显示名(未知标识原样返回) */ public static function label(string $key): string { return self::SPIDERS[$key][1] ?? $key; } /** * 全部蜘蛛 标识=>显示名(后台下拉/报表用) */ public static function labels(): array { $out = []; foreach (self::SPIDERS as $key => [, $label]) { $out[$key] = $label; } return $out; } }