[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fc-R-XUw97EE_E3Lb8mUIOSSTLkupXUtSfDZMlvJSykw":3,"$fvpinTRml3U3FnUeIIk8ubpbq369afJrc4RHYXn3PCrM":25},{"_id":4,"slug":5,"__v":6,"author":7,"body":8,"canonical":9,"category":10,"createdAt":11,"date":12,"description":13,"htmlContent":14,"image":15,"imageAlt":15,"readingTime":16,"tags":17,"title":23,"updatedAt":24},"69e1cce1aa6b273b0c7d7064","why-log-file-analysis-matters-for-ai-crawlers-and-search-visibility",0,"Equipe Seogard","Un site e-commerce de 22 000 pages produit. GPTBot en a visité 640 sur les 30 derniers jours. ClaudeBot, 180. GoogleBot, 16 400. La question n'est plus de savoir si les crawlers IA existent — c'est de comprendre pourquoi ils ignorent 97% de votre catalogue, et ce que ça implique pour votre visibilité dans les moteurs de réponse.\n\nLes logs serveur sont le seul endroit où cette réalité est visible. Pas Google Search Console. Pas Bing Webmaster Tools. Les fichiers access log bruts de votre serveur.\n\n## Les AI crawlers ne sont pas Googlebot : comprendre les différences de comportement\n\nGooglebot crawle depuis 25 ans. Son comportement est documenté, ses patterns prévisibles, son budget crawl optimisable via des leviers connus (sitemap, internal linking, page speed). Les crawlers IA — GPTBot (OpenAI), ClaudeBot (Anthropic), Bytespider (ByteDance), Meta-ExternalAgent, PerplexityBot — fonctionnent différemment sur trois dimensions fondamentales.\n\n### Fréquence et volume\n\nLà où Googlebot visite un site e-commerce de taille moyenne plusieurs milliers de fois par jour, GPTBot fait des passages épisodiques. Les données issues de logs analysés sur des sites de publishers montrent que les bots IA représentent entre 5% et 15% du volume total de crawl, avec des pics imprévisibles. Bytespider (le bot de TikTok/ByteDance) est souvent le plus agressif en volume, mais cible principalement les contenus textuels longs.\n\n### Sélection des pages\n\nGooglebot suit vos liens internes, parse vos sitemaps, respecte (globalement) votre architecture. Les crawlers IA ont des heuristiques différentes. Ils privilégient les pages à fort contenu textuel, les pages de type éditorial, les FAQ, les guides. Les fiches produit courtes avec specs techniques et peu de prose ? Largement ignorées. Les pages de catégorie avec du contenu thin ? Ignorées aussi.\n\n### Rendu JavaScript\n\nLa plupart des crawlers IA ne font pas de rendu JavaScript côté client. Si votre contenu dépend d'un hydratation React pour apparaître dans le DOM, GPTBot voit une page vide ou un shell HTML. C'est un problème que [les développeurs rencontrent lors de migrations de framework](/blog/changer-de-framework-next-js-vers-nuxt-ou-l-inverse-sans-perte-seo) — et qui est amplifié pour les bots IA par rapport à Googlebot, qui dispose d'un pipeline de rendering dédié (même si [le rendering budget a ses limites](/blog/rendering-budget-de-google-combien-de-javascript-est-trop)).\n\n## Extraire et parser les logs : setup technique\n\nAvant d'analyser quoi que ce soit, il faut capturer les bons signaux. Voici un pipeline concret.\n\n### Identifier les user-agents dans vos logs\n\nVotre fichier access log (Nginx, Apache, ou CDN) contient le user-agent de chaque requête. Les principaux bots IA utilisent ces identifiants :\n\n| Bot | User-Agent (substring) | Opérateur |\n|-----|----------------------|-----------|\n| GPTBot | `GPTBot` | OpenAI |\n| ChatGPT-User | `ChatGPT-User` | OpenAI |\n| ClaudeBot | `ClaudeBot` | Anthropic |\n| Bytespider | `Bytespider` | ByteDance |\n| PerplexityBot | `PerplexityBot` | Perplexity |\n| Meta-ExternalAgent | `Meta-ExternalAgent` | Meta |\n| Google-Extended | `Google-Extended` | Google (AI) |\n| Applebot-Extended | `Applebot-Extended` | Apple |\n\nUn premier filtre en ligne de commande pour extraire les hits de bots IA depuis un log Nginx combiné :\n\n```bash\n#!/bin/bash\n# extract-ai-bot-hits.sh\n# Usage: ./extract-ai-bot-hits.sh /var/log/nginx/access.log\n\nLOG_FILE=\"${1:-/var/log/nginx/access.log}\"\nAI_BOTS=\"GPTBot|ChatGPT-User|ClaudeBot|Bytespider|PerplexityBot|Meta-ExternalAgent|Google-Extended|Applebot-Extended\"\n\necho \"=== AI Bot Crawl Summary ($(basename $LOG_FILE)) ===\"\necho \"\"\n\n# Volume par bot\necho \"--- Hits par bot ---\"\ngrep -oP \"($AI_BOTS)\" \"$LOG_FILE\" | sort | uniq -c | sort -rn\n\necho \"\"\necho \"--- Top 20 URLs crawlées par GPTBot ---\"\ngrep \"GPTBot\" \"$LOG_FILE\" | awk '{print $7}' | sort | uniq -c | sort -rn | head -20\n\necho \"\"\necho \"--- Codes de réponse pour les bots IA ---\"\ngrep -E \"($AI_BOTS)\" \"$LOG_FILE\" | awk '{print $9}' | sort | uniq -c | sort -rn\n\necho \"\"\necho \"--- Pages crawlées par Googlebot mais PAS par les bots IA ---\"\ncomm -23 \\\n  \u003C(grep \"Googlebot\" \"$LOG_FILE\" | awk '{print $7}' | sort -u) \\\n  \u003C(grep -E \"($AI_BOTS)\" \"$LOG_FILE\" | awk '{print $7}' | sort -u) \\\n| head -50\n```\n\nCette dernière commande (`comm -23`) est la plus précieuse : elle révèle les pages que Googlebot juge dignes d'être crawlées mais que les bots IA ignorent complètement. C'est votre crawl gap IA.\n\n### Structurer les données pour une analyse répétable\n\nPour un suivi mensuel sur un site de taille significative, un script bash ne suffit plus. Voici un parser Python minimal qui structure les hits dans un format exploitable :\n\n```python\nimport re\nimport csv\nimport sys\nfrom collections import defaultdict\nfrom datetime import datetime\n\nAI_BOT_PATTERNS = {\n    'GPTBot': re.compile(r'GPTBot'),\n    'ChatGPT-User': re.compile(r'ChatGPT-User'),\n    'ClaudeBot': re.compile(r'ClaudeBot'),\n    'Bytespider': re.compile(r'Bytespider'),\n    'PerplexityBot': re.compile(r'PerplexityBot'),\n    'Meta-ExternalAgent': re.compile(r'Meta-ExternalAgent'),\n    'Google-Extended': re.compile(r'Google-Extended'),\n    'Googlebot': re.compile(r'Googlebot\\/'),\n}\n\n# Format log Nginx combined\nLOG_PATTERN = re.compile(\n    r'(?P\u003Cip>\\S+) \\S+ \\S+ \\[(?P\u003Ctime>[^\\]]+)\\] '\n    r'\"(?P\u003Cmethod>\\S+) (?P\u003Curl>\\S+) \\S+\" (?P\u003Cstatus>\\d{3}) '\n    r'(?P\u003Csize>\\d+) \"(?P\u003Creferer>[^\"]*)\" \"(?P\u003Cua>[^\"]*)\"'\n)\n\ndef parse_log(filepath):\n    hits = []\n    with open(filepath, 'r', encoding='utf-8', errors='ignore') as f:\n        for line in f:\n            m = LOG_PATTERN.match(line)\n            if not m:\n                continue\n            ua = m.group('ua')\n            for bot_name, pattern in AI_BOT_PATTERNS.items():\n                if pattern.search(ua):\n                    hits.append({\n                        'bot': bot_name,\n                        'url': m.group('url'),\n                        'status': int(m.group('status')),\n                        'timestamp': m.group('time'),\n                        'size': int(m.group('size')),\n                    })\n                    break  # un seul bot par ligne\n    return hits\n\ndef export_csv(hits, output_path):\n    with open(output_path, 'w', newline='') as f:\n        writer = csv.DictWriter(f, fieldnames=['bot', 'url', 'status', 'timestamp', 'size'])\n        writer.writeheader()\n        writer.writerows(hits)\n\nif __name__ == '__main__':\n    log_path = sys.argv[1]\n    out_path = sys.argv[2] if len(sys.argv) > 2 else 'ai_bot_hits.csv'\n    hits = parse_log(log_path)\n    export_csv(hits, out_path)\n    \n    # Résumé\n    by_bot = defaultdict(int)\n    for h in hits:\n        by_bot[h['bot']] += 1\n    print(f\"Total hits: {len(hits)}\")\n    for bot, count in sorted(by_bot.items(), key=lambda x: -x[1]):\n        print(f\"  {bot}: {count}\")\n```\n\nCe script vous donne un CSV que vous pouvez croiser avec votre sitemap ou votre export Screaming Frog pour identifier les URLs présentes dans votre architecture mais absentes des crawls IA.\n\n## Scénario concret : un média tech de 8 000 articles\n\nPrenons un cas réaliste. Un site de type média/blog tech — 8 200 articles publiés, 450 pages de catégories et tags, 12 landing pages statiques. Stack Next.js avec SSR, hébergé sur Vercel, CDN Cloudflare en front.\n\n### Les données brutes\n\nAprès un mois de collecte de logs (via Cloudflare Logpush vers un bucket S3, parsé avec le script ci-dessus) :\n\n| Bot | Hits/mois | URLs uniques | % du catalogue |\n|-----|-----------|-------------|----------------|\n| Googlebot | 184 000 | 7 800 | 90.2% |\n| Bytespider | 31 000 | 2 100 | 24.3% |\n| GPTBot | 8 400 | 1 350 | 15.6% |\n| ClaudeBot | 3 200 | 680 | 7.9% |\n| PerplexityBot | 5 800 | 920 | 10.6% |\n\n### Ce que les données révèlent\n\n**Problème 1 : les articles récents sont sous-crawlés par les bots IA.** Sur les 600 articles publiés dans les 90 derniers jours, GPTBot en a visité 89 (14.8%). Googlebot en a visité 571 (95.2%). Les bots IA découvrent les contenus récents avec un retard de 3 à 8 semaines par rapport à Googlebot.\n\n**Problème 2 : les pages de catégorie sont crawlées mais les articles paginés ne le sont pas.** GPTBot visite `/category/devops` mais ne suit pas `/category/devops?page=4`. Les articles accessibles uniquement via la pagination profonde sont invisibles pour les LLM.\n\n**Problème 3 : les codes 403 sur les assets.** 12% des requêtes de ClaudeBot retournaient un 403 — le WAF Cloudflare bloquait le bot. L'équipe n'avait pas whitelisté le user-agent dans les règles de firewall.\n\n### Les actions correctives\n\nPour le retard de découverte, l'équipe a ajouté un `\u003Clink rel=\"preload\">` dans le head de la homepage pointant vers un flux RSS/Atom des 50 derniers articles — les bots IA suivent les liens Atom de manière plus fiable que les sitemaps XML (observation empirique, non documentée officiellement).\n\nPour la pagination, un passage à une architecture de scroll infini avec des URLs canoniques propres et un sitemap paginé a résolu le problème en 3 semaines.\n\nPour les 403, une règle Cloudflare WAF :\n\n```nginx\n# Cloudflare WAF Custom Rule (expression syntax)\n# Action: Skip (Allow)\n# Nom: Allow AI Crawlers\n\n(http.user_agent contains \"GPTBot\") or\n(http.user_agent contains \"ChatGPT-User\") or\n(http.user_agent contains \"ClaudeBot\") or\n(http.user_agent contains \"PerplexityBot\") or\n(http.user_agent contains \"Applebot-Extended\") or\n(http.user_agent contains \"Google-Extended\")\n```\n\nRésultat après 6 semaines : les URLs uniques crawlées par GPTBot sont passées de 1 350 à 3 100 (+130%). Le site a commencé à apparaître dans les réponses de Perplexity et ChatGPT sur des requêtes de niche DevOps, là où il était absent avant.\n\n## Croiser les logs avec robots.txt et les directives d'accès\n\nLa log file analysis ne prend son sens que si vous maîtrisez ce que vous autorisez et ce que vous bloquez. Les crawlers IA respectent (pour la plupart) le robots.txt — mais les conventions sont encore en mouvement.\n\n### L'état des directives en 2026\n\nLe fichier robots.txt gère les crawlers IA via des user-agents spécifiques. Voici un exemple de configuration qui autorise le crawl pour les moteurs de recherche IA tout en bloquant le scraping brut :\n\n```\n# robots.txt — stratégie différenciée IA\n\n# Googlebot classique : accès complet\nUser-agent: Googlebot\nAllow: /\n\n# Google AI (Gemini, SGE) : accès au contenu éditorial\nUser-agent: Google-Extended\nAllow: /blog/\nAllow: /guides/\nDisallow: /account/\nDisallow: /api/\nDisallow: /admin/\n\n# OpenAI\nUser-agent: GPTBot\nAllow: /blog/\nAllow: /guides/\nAllow: /docs/\nDisallow: /account/\nDisallow: /api/\nDisallow: /staging/\n\n# Anthropic\nUser-agent: ClaudeBot\nAllow: /blog/\nAllow: /guides/\nDisallow: /account/\nDisallow: /api/\n\n# Bytespider — bloqué (scraping agressif, faible valeur retour)\nUser-agent: Bytespider\nDisallow: /\n\n# Sitemap\nSitemap: https://techblog.dev/sitemap-index.xml\n```\n\nLe piège classique : bloquer un bot IA dans robots.txt puis se demander pourquoi le contenu n'apparaît pas dans les réponses du LLM associé. L'analyse de logs vous montre si un bot *tente* d'accéder à des URLs bloquées — un signal que votre politique de blocage mérite peut-être d'être affinée.\n\nVérifiez dans vos logs les requêtes des bots IA qui retournent des 200 vs celles qui retournent des 403 ou 404. Un volume élevé de 404 pour GPTBot signifie que le bot a des références vers des URLs qui n'existent plus — potentiellement des backlinks ou des pages supprimées sans redirect.\n\n## Au-delà des logs : croiser avec les données de visibilité IA\n\nLa log file analysis seule ne suffit pas. L'insight stratégique vient du croisement entre :\n\n1. **Ce que les bots IA crawlent** (vos logs serveur)\n2. **Ce que les moteurs de réponse IA citent** (monitoring des citations dans ChatGPT, Perplexity, Gemini)\n3. **Ce que Google indexe et sert dans les AI Overviews** (Search Console + scraping des SERP)\n\n### Identifier les intent gaps entre crawl IA et visibilité organique\n\nSi GPTBot crawle vos pages `/guides/kubernetes-deployment` mais que ces contenus n'apparaissent jamais dans les réponses ChatGPT sur les requêtes Kubernetes, le problème n'est pas le crawl — c'est la qualité ou la structure du contenu. Si en revanche GPTBot ne crawle jamais ces pages, le problème est en amont : découvrabilité, architecture, ou blocage technique.\n\nC'est le même type de raisonnement que l'analyse d'intent gaps via Search Console, [appliqué au monde des moteurs de réponse IA](/blog/how-to-measure-intent-gaps-using-google-search-console-data). La méthode change, mais le principe reste : mesurer l'écart entre ce que vous proposez et ce que les systèmes consomment.\n\n### Le rôle du contenu structuré\n\nLes bots IA extraient plus facilement les informations quand le contenu est structuré avec du balisage sémantique clair. Les pages qui utilisent des `\u003Carticle>`, des `\u003Ch2>`/`\u003Ch3>` hiérarchiques, des listes `\u003Cdl>` pour les définitions, et du JSON-LD pour le schema markup sont crawlées plus en profondeur. C'est une corrélation observée dans les logs, pas une causalité prouvée — mais elle est consistante.\n\n[Optimiser pour les moteurs de réponse IA](/blog/optimiser-pour-les-moteurs-de-reponse-ia) passe par cette double couche : s'assurer que les bots accèdent au contenu (log analysis) et que le contenu est structuré pour être extractible (balisage sémantique).\n\n## Outils et stack technique pour la log file analysis IA\n\n### Screaming Frog Log Analyzer\n\nScreaming Frog dispose d'un module Log Analyzer qui importe les fichiers access log et permet de filtrer par user-agent. La limite : il faut manuellement ajouter les patterns de bots IA car les presets ne couvrent que les crawlers classiques (Googlebot, Bingbot). La fonctionnalité de croisement avec un crawl Screaming Frog est précieuse : vous visualisez les pages crawlées par le spider vs les pages visitées par chaque bot.\n\n### GoAccess pour le temps réel\n\nPour un monitoring rapide sur un serveur dédié :\n\n```bash\n# Monitoring temps réel des bots IA avec GoAccess\nzcat /var/log/nginx/access.log.*.gz | \\\n  grep -E \"(GPTBot|ClaudeBot|PerplexityBot|Bytespider|ChatGPT-User)\" | \\\n  goaccess --log-format=COMBINED -o /var/www/html/ai-bot-report.html --real-time-html\n```\n\nGoAccess génère un dashboard HTML interactif avec les URLs les plus crawlées, les codes de réponse, et les patterns temporels. L'option `--real-time-html` met à jour le rapport en continu via WebSocket.\n\n### Solutions cloud pour les sites derrière un CDN\n\nSi votre trafic passe par Cloudflare, Fastly ou AWS CloudFront, les logs ne sont pas sur votre serveur. Vous devez activer le log forwarding :\n\n- **Cloudflare** : Logpush vers S3, R2, ou un endpoint HTTP. Configurez un filtre pour ne capturer que les requêtes dont le user-agent matche les bots.\n- **Fastly** : Real-time log streaming vers BigQuery, S3, ou Datadog.\n- **CloudFront** : Standard logs ou Real-time logs vers Kinesis Data Firehose.\n\nLe coût n'est pas négligeable. Un site à 500K pages vues/mois génère environ 1-2 Go de logs compressés. Un site à 10M pages vues/mois, 20-40 Go. Filtrer en amont (uniquement les bots) réduit le volume d'un facteur 50 à 100.\n\n### Monitoring continu vs analyse ponctuelle\n\nL'analyse ponctuelle (une fois par trimestre, après une migration) donne un snapshot. Elle est utile mais insuffisante. Les crawlers IA changent de comportement sans préavis. OpenAI a modifié le crawl rate de GPTBot trois fois en 2025 selon les observations de la communauté SEO. Bytespider a été bloqué par défaut par plusieurs CDN, puis partiellement réautorisé.\n\nUn monitoring continu — qui détecte quand un bot IA arrête de crawler une section du site, ou quand un nouveau bot apparaît — est le seul moyen de réagir rapidement. C'est exactement le type de régression qu'un outil comme Seogard détecte automatiquement : une chute du volume de crawl IA sur une section spécifique déclenche une alerte avant que la perte de visibilité ne se matérialise dans les métriques de trafic.\n\n## Ce que les logs vous apprennent sur le futur de la search visibility\n\nL'analyse des logs serveur pour les crawlers IA n'est pas un exercice académique. C'est le mécanisme de feedback le plus direct entre votre infrastructure technique et votre visibilité dans [les systèmes qui remplacent progressivement les SERP classiques](/blog/google-sge-ai-overviews-quel-impact-sur-le-seo-technique).\n\nTrois tendances visibles dans les logs des sites que nous observons :\n\n**Le crawl IA se concentre.** Les bots IA ne cherchent pas à tout indexer. Ils ciblent le contenu à haute densité informationnelle. Les sites qui produisent 200 articles thin de 300 mots voient moins de crawl IA que ceux qui publient 30 guides exhaustifs de 3 000 mots. Les logs le prouvent noir sur blanc.\n\n**Les bots IA sont plus sensibles aux erreurs techniques.** Un 5xx transitoire que Googlebot retente 6 heures plus tard, GPTBot ne le retente parfois jamais. Chaque requête compte. Votre uptime et votre TTFB pour les bots IA doivent être irréprochables.\n\n**Le nombre de bots IA explose.** En 2024, on comptait 4-5 crawlers IA significatifs. En 2026, [on en recense plus d'une douzaine](/blog/openai-meta-bytedance-lead-ai-bot-traffic-in-publishing-via-sejournal-mattgsouthern), dont certains ne s'identifient pas clairement. L'analyse de logs est le seul moyen de détecter les crawlers non documentés qui accèdent à votre contenu.\n\nLa log file analysis est la couche fondamentale de toute stratégie de visibilité IA. Sans elle, vous optimisez à l'aveugle — vous publiez du contenu en espérant que les bots le trouvent, sans vérifier s'ils le trouvent effectivement. Les logs ne mentent pas. Commencez par les lire.","https://seogard.io/blog/why-log-file-analysis-matters-for-ai-crawlers-and-search-visibility","Actualités SEO","2026-04-17T06:02:09.095Z","2026-04-17","Analysez vos logs serveur pour tracer les crawlers IA, identifier les pages ignorées et optimiser votre visibilité dans les moteurs de réponse.","\u003Cp>Un site e-commerce de 22 000 pages produit. GPTBot en a visité 640 sur les 30 derniers jours. ClaudeBot, 180. GoogleBot, 16 400. La question n'est plus de savoir si les crawlers IA existent — c'est de comprendre pourquoi ils ignorent 97% de votre catalogue, et ce que ça implique pour votre visibilité dans les moteurs de réponse.\u003C/p>\n\u003Cp>Les logs serveur sont le seul endroit où cette réalité est visible. Pas Google Search Console. Pas Bing Webmaster Tools. Les fichiers access log bruts de votre serveur.\u003C/p>\n\u003Ch2>Les AI crawlers ne sont pas Googlebot : comprendre les différences de comportement\u003C/h2>\n\u003Cp>Googlebot crawle depuis 25 ans. Son comportement est documenté, ses patterns prévisibles, son budget crawl optimisable via des leviers connus (sitemap, internal linking, page speed). Les crawlers IA — GPTBot (OpenAI), ClaudeBot (Anthropic), Bytespider (ByteDance), Meta-ExternalAgent, PerplexityBot — fonctionnent différemment sur trois dimensions fondamentales.\u003C/p>\n\u003Ch3>Fréquence et volume\u003C/h3>\n\u003Cp>Là où Googlebot visite un site e-commerce de taille moyenne plusieurs milliers de fois par jour, GPTBot fait des passages épisodiques. Les données issues de logs analysés sur des sites de publishers montrent que les bots IA représentent entre 5% et 15% du volume total de crawl, avec des pics imprévisibles. Bytespider (le bot de TikTok/ByteDance) est souvent le plus agressif en volume, mais cible principalement les contenus textuels longs.\u003C/p>\n\u003Ch3>Sélection des pages\u003C/h3>\n\u003Cp>Googlebot suit vos liens internes, parse vos sitemaps, respecte (globalement) votre architecture. Les crawlers IA ont des heuristiques différentes. Ils privilégient les pages à fort contenu textuel, les pages de type éditorial, les FAQ, les guides. Les fiches produit courtes avec specs techniques et peu de prose ? Largement ignorées. Les pages de catégorie avec du contenu thin ? Ignorées aussi.\u003C/p>\n\u003Ch3>Rendu JavaScript\u003C/h3>\n\u003Cp>La plupart des crawlers IA ne font pas de rendu JavaScript côté client. Si votre contenu dépend d'un hydratation React pour apparaître dans le DOM, GPTBot voit une page vide ou un shell HTML. C'est un problème que \u003Ca href=\"/blog/changer-de-framework-next-js-vers-nuxt-ou-l-inverse-sans-perte-seo\">les développeurs rencontrent lors de migrations de framework\u003C/a> — et qui est amplifié pour les bots IA par rapport à Googlebot, qui dispose d'un pipeline de rendering dédié (même si \u003Ca href=\"/blog/rendering-budget-de-google-combien-de-javascript-est-trop\">le rendering budget a ses limites\u003C/a>).\u003C/p>\n\u003Ch2>Extraire et parser les logs : setup technique\u003C/h2>\n\u003Cp>Avant d'analyser quoi que ce soit, il faut capturer les bons signaux. Voici un pipeline concret.\u003C/p>\n\u003Ch3>Identifier les user-agents dans vos logs\u003C/h3>\n\u003Cp>Votre fichier access log (Nginx, Apache, ou CDN) contient le user-agent de chaque requête. Les principaux bots IA utilisent ces identifiants :\u003C/p>\n\u003Ctable>\n\u003Cthead>\n\u003Ctr>\n\u003Cth>Bot\u003C/th>\n\u003Cth>User-Agent (substring)\u003C/th>\n\u003Cth>Opérateur\u003C/th>\n\u003C/tr>\n\u003C/thead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>GPTBot\u003C/td>\n\u003Ctd>\u003Ccode>GPTBot\u003C/code>\u003C/td>\n\u003Ctd>OpenAI\u003C/td>\n\u003C/tr>\n\u003Ctr>\n\u003Ctd>ChatGPT-User\u003C/td>\n\u003Ctd>\u003Ccode>ChatGPT-User\u003C/code>\u003C/td>\n\u003Ctd>OpenAI\u003C/td>\n\u003C/tr>\n\u003Ctr>\n\u003Ctd>ClaudeBot\u003C/td>\n\u003Ctd>\u003Ccode>ClaudeBot\u003C/code>\u003C/td>\n\u003Ctd>Anthropic\u003C/td>\n\u003C/tr>\n\u003Ctr>\n\u003Ctd>Bytespider\u003C/td>\n\u003Ctd>\u003Ccode>Bytespider\u003C/code>\u003C/td>\n\u003Ctd>ByteDance\u003C/td>\n\u003C/tr>\n\u003Ctr>\n\u003Ctd>PerplexityBot\u003C/td>\n\u003Ctd>\u003Ccode>PerplexityBot\u003C/code>\u003C/td>\n\u003Ctd>Perplexity\u003C/td>\n\u003C/tr>\n\u003Ctr>\n\u003Ctd>Meta-ExternalAgent\u003C/td>\n\u003Ctd>\u003Ccode>Meta-ExternalAgent\u003C/code>\u003C/td>\n\u003Ctd>Meta\u003C/td>\n\u003C/tr>\n\u003Ctr>\n\u003Ctd>Google-Extended\u003C/td>\n\u003Ctd>\u003Ccode>Google-Extended\u003C/code>\u003C/td>\n\u003Ctd>Google (AI)\u003C/td>\n\u003C/tr>\n\u003Ctr>\n\u003Ctd>Applebot-Extended\u003C/td>\n\u003Ctd>\u003Ccode>Applebot-Extended\u003C/code>\u003C/td>\n\u003Ctd>Apple\u003C/td>\n\u003C/tr>\n\u003C/tbody>\n\u003C/table>\n\u003Cp>Un premier filtre en ligne de commande pour extraire les hits de bots IA depuis un log Nginx combiné :\u003C/p>\n\u003Cpre class=\"shiki github-dark\" style=\"background-color:#24292e;color:#e1e4e8\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">#!/bin/bash\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\"># extract-ai-bot-hits.sh\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\"># Usage: ./extract-ai-bot-hits.sh /var/log/nginx/access.log\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">LOG_FILE\u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#9ECBFF\">\"\u003C/span>\u003Cspan style=\"color:#79B8FF\">${1\u003C/span>\u003Cspan style=\"color:#F97583\">:-/\u003C/span>\u003Cspan style=\"color:#E1E4E8\">var\u003C/span>\u003Cspan style=\"color:#F97583\">/\u003C/span>\u003Cspan style=\"color:#E1E4E8\">log\u003C/span>\u003Cspan style=\"color:#F97583\">/\u003C/span>\u003Cspan style=\"color:#E1E4E8\">nginx\u003C/span>\u003Cspan style=\"color:#F97583\">/\u003C/span>\u003Cspan style=\"color:#E1E4E8\">access\u003C/span>\u003Cspan style=\"color:#9ECBFF\">.\u003C/span>\u003Cspan style=\"color:#E1E4E8\">log\u003C/span>\u003Cspan style=\"color:#79B8FF\">}\u003C/span>\u003Cspan style=\"color:#9ECBFF\">\"\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">AI_BOTS\u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#9ECBFF\">\"GPTBot|ChatGPT-User|ClaudeBot|Bytespider|PerplexityBot|Meta-ExternalAgent|Google-Extended|Applebot-Extended\"\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#79B8FF\">echo\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> \"=== AI Bot Crawl Summary ($(\u003C/span>\u003Cspan style=\"color:#B392F0\">basename\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> $LOG_FILE\u003C/span>\u003Cspan style=\"color:#9ECBFF\">)) ===\"\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#79B8FF\">echo\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> \"\"\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\"># Volume par bot\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#79B8FF\">echo\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> \"--- Hits par bot ---\"\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#B392F0\">grep\u003C/span>\u003Cspan style=\"color:#79B8FF\"> -oP\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> \"(\u003C/span>\u003Cspan style=\"color:#E1E4E8\">$AI_BOTS\u003C/span>\u003Cspan style=\"color:#9ECBFF\">)\"\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> \"\u003C/span>\u003Cspan style=\"color:#E1E4E8\">$LOG_FILE\u003C/span>\u003Cspan style=\"color:#9ECBFF\">\"\u003C/span>\u003Cspan style=\"color:#F97583\"> |\u003C/span>\u003Cspan style=\"color:#B392F0\"> sort\u003C/span>\u003Cspan style=\"color:#F97583\"> |\u003C/span>\u003Cspan style=\"color:#B392F0\"> uniq\u003C/span>\u003Cspan style=\"color:#79B8FF\"> -c\u003C/span>\u003Cspan style=\"color:#F97583\"> |\u003C/span>\u003Cspan style=\"color:#B392F0\"> sort\u003C/span>\u003Cspan style=\"color:#79B8FF\"> -rn\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#79B8FF\">echo\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> \"\"\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#79B8FF\">echo\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> \"--- Top 20 URLs crawlées par GPTBot ---\"\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#B392F0\">grep\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> \"GPTBot\"\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> \"\u003C/span>\u003Cspan style=\"color:#E1E4E8\">$LOG_FILE\u003C/span>\u003Cspan style=\"color:#9ECBFF\">\"\u003C/span>\u003Cspan style=\"color:#F97583\"> |\u003C/span>\u003Cspan style=\"color:#B392F0\"> awk\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> '{print $7}'\u003C/span>\u003Cspan style=\"color:#F97583\"> |\u003C/span>\u003Cspan style=\"color:#B392F0\"> sort\u003C/span>\u003Cspan style=\"color:#F97583\"> |\u003C/span>\u003Cspan style=\"color:#B392F0\"> uniq\u003C/span>\u003Cspan style=\"color:#79B8FF\"> -c\u003C/span>\u003Cspan style=\"color:#F97583\"> |\u003C/span>\u003Cspan style=\"color:#B392F0\"> sort\u003C/span>\u003Cspan style=\"color:#79B8FF\"> -rn\u003C/span>\u003Cspan style=\"color:#F97583\"> |\u003C/span>\u003Cspan style=\"color:#B392F0\"> head\u003C/span>\u003Cspan style=\"color:#79B8FF\"> -20\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#79B8FF\">echo\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> \"\"\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#79B8FF\">echo\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> \"--- Codes de réponse pour les bots IA ---\"\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#B392F0\">grep\u003C/span>\u003Cspan style=\"color:#79B8FF\"> -E\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> \"(\u003C/span>\u003Cspan style=\"color:#E1E4E8\">$AI_BOTS\u003C/span>\u003Cspan style=\"color:#9ECBFF\">)\"\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> \"\u003C/span>\u003Cspan style=\"color:#E1E4E8\">$LOG_FILE\u003C/span>\u003Cspan style=\"color:#9ECBFF\">\"\u003C/span>\u003Cspan style=\"color:#F97583\"> |\u003C/span>\u003Cspan style=\"color:#B392F0\"> awk\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> '{print $9}'\u003C/span>\u003Cspan style=\"color:#F97583\"> |\u003C/span>\u003Cspan style=\"color:#B392F0\"> sort\u003C/span>\u003Cspan style=\"color:#F97583\"> |\u003C/span>\u003Cspan style=\"color:#B392F0\"> uniq\u003C/span>\u003Cspan style=\"color:#79B8FF\"> -c\u003C/span>\u003Cspan style=\"color:#F97583\"> |\u003C/span>\u003Cspan style=\"color:#B392F0\"> sort\u003C/span>\u003Cspan style=\"color:#79B8FF\"> -rn\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#79B8FF\">echo\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> \"\"\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#79B8FF\">echo\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> \"--- Pages crawlées par Googlebot mais PAS par les bots IA ---\"\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#B392F0\">comm\u003C/span>\u003Cspan style=\"color:#79B8FF\"> -23\u003C/span>\u003Cspan style=\"color:#79B8FF\"> \\\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">  &#x3C;(\u003C/span>\u003Cspan style=\"color:#B392F0\">grep\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> \"Googlebot\" \"\u003C/span>\u003Cspan style=\"color:#E1E4E8\">$LOG_FILE\u003C/span>\u003Cspan style=\"color:#9ECBFF\">\" \u003C/span>\u003Cspan style=\"color:#F97583\">|\u003C/span>\u003Cspan style=\"color:#B392F0\"> awk\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> '{print $7}' \u003C/span>\u003Cspan style=\"color:#F97583\">|\u003C/span>\u003Cspan style=\"color:#B392F0\"> sort\u003C/span>\u003Cspan style=\"color:#79B8FF\"> -u\u003C/span>\u003Cspan style=\"color:#9ECBFF\">)\u003C/span>\u003Cspan style=\"color:#79B8FF\"> \\\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">  &#x3C;(\u003C/span>\u003Cspan style=\"color:#B392F0\">grep\u003C/span>\u003Cspan style=\"color:#79B8FF\"> -E\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> \"(\u003C/span>\u003Cspan style=\"color:#E1E4E8\">$AI_BOTS\u003C/span>\u003Cspan style=\"color:#9ECBFF\">)\" \"\u003C/span>\u003Cspan style=\"color:#E1E4E8\">$LOG_FILE\u003C/span>\u003Cspan style=\"color:#9ECBFF\">\" \u003C/span>\u003Cspan style=\"color:#F97583\">|\u003C/span>\u003Cspan style=\"color:#B392F0\"> awk\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> '{print $7}' \u003C/span>\u003Cspan style=\"color:#F97583\">|\u003C/span>\u003Cspan style=\"color:#B392F0\"> sort\u003C/span>\u003Cspan style=\"color:#79B8FF\"> -u\u003C/span>\u003Cspan style=\"color:#9ECBFF\">)\u003C/span>\u003Cspan style=\"color:#79B8FF\"> \\\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">|\u003C/span>\u003Cspan style=\"color:#B392F0\"> head\u003C/span>\u003Cspan style=\"color:#79B8FF\"> -50\u003C/span>\u003C/span>\u003C/code>\u003C/pre>\n\u003Cp>Cette dernière commande (\u003Ccode>comm -23\u003C/code>) est la plus précieuse : elle révèle les pages que Googlebot juge dignes d'être crawlées mais que les bots IA ignorent complètement. C'est votre crawl gap IA.\u003C/p>\n\u003Ch3>Structurer les données pour une analyse répétable\u003C/h3>\n\u003Cp>Pour un suivi mensuel sur un site de taille significative, un script bash ne suffit plus. Voici un parser Python minimal qui structure les hits dans un format exploitable :\u003C/p>\n\u003Cpre class=\"shiki github-dark\" style=\"background-color:#24292e;color:#e1e4e8\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">import\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> re\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">import\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> csv\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">import\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> sys\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">from\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> collections \u003C/span>\u003Cspan style=\"color:#F97583\">import\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> defaultdict\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">from\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> datetime \u003C/span>\u003Cspan style=\"color:#F97583\">import\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> datetime\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#79B8FF\">AI_BOT_PATTERNS\u003C/span>\u003Cspan style=\"color:#F97583\"> =\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> {\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">    'GPTBot'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">: re.compile(\u003C/span>\u003Cspan style=\"color:#F97583\">r\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'\u003C/span>\u003Cspan style=\"color:#DBEDFF\">GPTBot\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">),\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">    'ChatGPT-User'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">: re.compile(\u003C/span>\u003Cspan style=\"color:#F97583\">r\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'\u003C/span>\u003Cspan style=\"color:#DBEDFF\">ChatGPT-User\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">),\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">    'ClaudeBot'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">: re.compile(\u003C/span>\u003Cspan style=\"color:#F97583\">r\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'\u003C/span>\u003Cspan style=\"color:#DBEDFF\">ClaudeBot\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">),\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">    'Bytespider'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">: re.compile(\u003C/span>\u003Cspan style=\"color:#F97583\">r\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'\u003C/span>\u003Cspan style=\"color:#DBEDFF\">Bytespider\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">),\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">    'PerplexityBot'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">: re.compile(\u003C/span>\u003Cspan style=\"color:#F97583\">r\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'\u003C/span>\u003Cspan style=\"color:#DBEDFF\">PerplexityBot\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">),\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">    'Meta-ExternalAgent'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">: re.compile(\u003C/span>\u003Cspan style=\"color:#F97583\">r\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'\u003C/span>\u003Cspan style=\"color:#DBEDFF\">Meta-ExternalAgent\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">),\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">    'Google-Extended'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">: re.compile(\u003C/span>\u003Cspan style=\"color:#F97583\">r\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'\u003C/span>\u003Cspan style=\"color:#DBEDFF\">Google-Extended\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">),\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">    'Googlebot'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">: re.compile(\u003C/span>\u003Cspan style=\"color:#F97583\">r\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'\u003C/span>\u003Cspan style=\"color:#DBEDFF\">Googlebot\u003C/span>\u003Cspan style=\"color:#85E89D;font-weight:bold\">\\/\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">),\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">}\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\"># Format log Nginx combined\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#79B8FF\">LOG_PATTERN\u003C/span>\u003Cspan style=\"color:#F97583\"> =\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> re.compile(\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">    r\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'\u003C/span>\u003Cspan style=\"color:#79B8FF\">(\u003C/span>\u003Cspan style=\"color:#85E89D\">?P&#x3C;ip>\u003C/span>\u003Cspan style=\"color:#79B8FF\">\\S\u003C/span>\u003Cspan style=\"color:#F97583\">+\u003C/span>\u003Cspan style=\"color:#79B8FF\">)\u003C/span>\u003Cspan style=\"color:#79B8FF\"> \\S\u003C/span>\u003Cspan style=\"color:#F97583\">+\u003C/span>\u003Cspan style=\"color:#79B8FF\"> \\S\u003C/span>\u003Cspan style=\"color:#F97583\">+\u003C/span>\u003Cspan style=\"color:#85E89D;font-weight:bold\"> \\[\u003C/span>\u003Cspan style=\"color:#79B8FF\">(\u003C/span>\u003Cspan style=\"color:#85E89D\">?P&#x3C;time>\u003C/span>\u003Cspan style=\"color:#79B8FF\">[\u003C/span>\u003Cspan style=\"color:#F97583\">^\u003C/span>\u003Cspan style=\"color:#85E89D;font-weight:bold\">\\]\u003C/span>\u003Cspan style=\"color:#79B8FF\">]\u003C/span>\u003Cspan style=\"color:#F97583\">+\u003C/span>\u003Cspan style=\"color:#79B8FF\">)\u003C/span>\u003Cspan style=\"color:#85E89D;font-weight:bold\">\\]\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> '\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">    r\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'\u003C/span>\u003Cspan style=\"color:#DBEDFF\">\"\u003C/span>\u003Cspan style=\"color:#79B8FF\">(\u003C/span>\u003Cspan style=\"color:#85E89D\">?P&#x3C;method>\u003C/span>\u003Cspan style=\"color:#79B8FF\">\\S\u003C/span>\u003Cspan style=\"color:#F97583\">+\u003C/span>\u003Cspan style=\"color:#79B8FF\">)\u003C/span>\u003Cspan style=\"color:#79B8FF\"> (\u003C/span>\u003Cspan style=\"color:#85E89D\">?P&#x3C;url>\u003C/span>\u003Cspan style=\"color:#79B8FF\">\\S\u003C/span>\u003Cspan style=\"color:#F97583\">+\u003C/span>\u003Cspan style=\"color:#79B8FF\">)\u003C/span>\u003Cspan style=\"color:#79B8FF\"> \\S\u003C/span>\u003Cspan style=\"color:#F97583\">+\u003C/span>\u003Cspan style=\"color:#DBEDFF\">\" \u003C/span>\u003Cspan style=\"color:#79B8FF\">(\u003C/span>\u003Cspan style=\"color:#85E89D\">?P&#x3C;status>\u003C/span>\u003Cspan style=\"color:#79B8FF\">\\d\u003C/span>\u003Cspan style=\"color:#F97583\">{3}\u003C/span>\u003Cspan style=\"color:#79B8FF\">)\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> '\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">    r\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'\u003C/span>\u003Cspan style=\"color:#79B8FF\">(\u003C/span>\u003Cspan style=\"color:#85E89D\">?P&#x3C;size>\u003C/span>\u003Cspan style=\"color:#79B8FF\">\\d\u003C/span>\u003Cspan style=\"color:#F97583\">+\u003C/span>\u003Cspan style=\"color:#79B8FF\">)\u003C/span>\u003Cspan style=\"color:#DBEDFF\"> \"\u003C/span>\u003Cspan style=\"color:#79B8FF\">(\u003C/span>\u003Cspan style=\"color:#85E89D\">?P&#x3C;referer>\u003C/span>\u003Cspan style=\"color:#79B8FF\">[\u003C/span>\u003Cspan style=\"color:#F97583\">^\u003C/span>\u003Cspan style=\"color:#79B8FF\">\"]\u003C/span>\u003Cspan style=\"color:#F97583\">*\u003C/span>\u003Cspan style=\"color:#79B8FF\">)\u003C/span>\u003Cspan style=\"color:#DBEDFF\">\" \"\u003C/span>\u003Cspan style=\"color:#79B8FF\">(\u003C/span>\u003Cspan style=\"color:#85E89D\">?P&#x3C;ua>\u003C/span>\u003Cspan style=\"color:#79B8FF\">[\u003C/span>\u003Cspan style=\"color:#F97583\">^\u003C/span>\u003Cspan style=\"color:#79B8FF\">\"]\u003C/span>\u003Cspan style=\"color:#F97583\">*\u003C/span>\u003Cspan style=\"color:#79B8FF\">)\u003C/span>\u003Cspan style=\"color:#DBEDFF\">\"\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">)\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">def\u003C/span>\u003Cspan style=\"color:#B392F0\"> parse_log\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(filepath):\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    hits \u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> []\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">    with\u003C/span>\u003Cspan style=\"color:#79B8FF\"> open\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(filepath, \u003C/span>\u003Cspan style=\"color:#9ECBFF\">'r'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">, \u003C/span>\u003Cspan style=\"color:#FFAB70\">encoding\u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'utf-8'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">, \u003C/span>\u003Cspan style=\"color:#FFAB70\">errors\u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'ignore'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">) \u003C/span>\u003Cspan style=\"color:#F97583\">as\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> f:\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">        for\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> line \u003C/span>\u003Cspan style=\"color:#F97583\">in\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> f:\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">            m \u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#79B8FF\"> LOG_PATTERN\u003C/span>\u003Cspan style=\"color:#E1E4E8\">.match(line)\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">            if\u003C/span>\u003Cspan style=\"color:#F97583\"> not\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> m:\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">                continue\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">            ua \u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> m.group(\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'ua'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">)\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">            for\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> bot_name, pattern \u003C/span>\u003Cspan style=\"color:#F97583\">in\u003C/span>\u003Cspan style=\"color:#79B8FF\"> AI_BOT_PATTERNS\u003C/span>\u003Cspan style=\"color:#E1E4E8\">.items():\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">                if\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> pattern.search(ua):\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">                    hits.append({\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">                        'bot'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">: bot_name,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">                        'url'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">: m.group(\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'url'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">),\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">                        'status'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">: \u003C/span>\u003Cspan style=\"color:#79B8FF\">int\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(m.group(\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'status'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">)),\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">                        'timestamp'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">: m.group(\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'time'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">),\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">                        'size'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">: \u003C/span>\u003Cspan style=\"color:#79B8FF\">int\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(m.group(\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'size'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">)),\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">                    })\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">                    break\u003C/span>\u003Cspan style=\"color:#6A737D\">  # un seul bot par ligne\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">    return\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> hits\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">def\u003C/span>\u003Cspan style=\"color:#B392F0\"> export_csv\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(hits, output_path):\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">    with\u003C/span>\u003Cspan style=\"color:#79B8FF\"> open\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(output_path, \u003C/span>\u003Cspan style=\"color:#9ECBFF\">'w'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">, \u003C/span>\u003Cspan style=\"color:#FFAB70\">newline\u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#9ECBFF\">''\u003C/span>\u003Cspan style=\"color:#E1E4E8\">) \u003C/span>\u003Cspan style=\"color:#F97583\">as\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> f:\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">        writer \u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> csv.DictWriter(f, \u003C/span>\u003Cspan style=\"color:#FFAB70\">fieldnames\u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#E1E4E8\">[\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'bot'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">, \u003C/span>\u003Cspan style=\"color:#9ECBFF\">'url'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">, \u003C/span>\u003Cspan style=\"color:#9ECBFF\">'status'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">, \u003C/span>\u003Cspan style=\"color:#9ECBFF\">'timestamp'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">, \u003C/span>\u003Cspan style=\"color:#9ECBFF\">'size'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">])\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">        writer.writeheader()\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">        writer.writerows(hits)\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">if\u003C/span>\u003Cspan style=\"color:#79B8FF\"> __name__\u003C/span>\u003Cspan style=\"color:#F97583\"> ==\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> '__main__'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">:\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    log_path \u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> sys.argv[\u003C/span>\u003Cspan style=\"color:#79B8FF\">1\u003C/span>\u003Cspan style=\"color:#E1E4E8\">]\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    out_path \u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> sys.argv[\u003C/span>\u003Cspan style=\"color:#79B8FF\">2\u003C/span>\u003Cspan style=\"color:#E1E4E8\">] \u003C/span>\u003Cspan style=\"color:#F97583\">if\u003C/span>\u003Cspan style=\"color:#79B8FF\"> len\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(sys.argv) \u003C/span>\u003Cspan style=\"color:#F97583\">>\u003C/span>\u003Cspan style=\"color:#79B8FF\"> 2\u003C/span>\u003Cspan style=\"color:#F97583\"> else\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> 'ai_bot_hits.csv'\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    hits \u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> parse_log(log_path)\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    export_csv(hits, out_path)\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    \u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">    # Résumé\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    by_bot \u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> defaultdict(\u003C/span>\u003Cspan style=\"color:#79B8FF\">int\u003C/span>\u003Cspan style=\"color:#E1E4E8\">)\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">    for\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> h \u003C/span>\u003Cspan style=\"color:#F97583\">in\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> hits:\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">        by_bot[h[\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'bot'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">]] \u003C/span>\u003Cspan style=\"color:#F97583\">+=\u003C/span>\u003Cspan style=\"color:#79B8FF\"> 1\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#79B8FF\">    print\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(\u003C/span>\u003Cspan style=\"color:#F97583\">f\u003C/span>\u003Cspan style=\"color:#9ECBFF\">\"Total hits: \u003C/span>\u003Cspan style=\"color:#79B8FF\">{len\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(hits)\u003C/span>\u003Cspan style=\"color:#79B8FF\">}\u003C/span>\u003Cspan style=\"color:#9ECBFF\">\"\u003C/span>\u003Cspan style=\"color:#E1E4E8\">)\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">    for\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> bot, count \u003C/span>\u003Cspan style=\"color:#F97583\">in\u003C/span>\u003Cspan style=\"color:#79B8FF\"> sorted\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(by_bot.items(), \u003C/span>\u003Cspan style=\"color:#FFAB70\">key\u003C/span>\u003Cspan style=\"color:#F97583\">=lambda\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> x: \u003C/span>\u003Cspan style=\"color:#F97583\">-\u003C/span>\u003Cspan style=\"color:#E1E4E8\">x[\u003C/span>\u003Cspan style=\"color:#79B8FF\">1\u003C/span>\u003Cspan style=\"color:#E1E4E8\">]):\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#79B8FF\">        print\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(\u003C/span>\u003Cspan style=\"color:#F97583\">f\u003C/span>\u003Cspan style=\"color:#9ECBFF\">\"  \u003C/span>\u003Cspan style=\"color:#79B8FF\">{\u003C/span>\u003Cspan style=\"color:#E1E4E8\">bot\u003C/span>\u003Cspan style=\"color:#79B8FF\">}\u003C/span>\u003Cspan style=\"color:#9ECBFF\">: \u003C/span>\u003Cspan style=\"color:#79B8FF\">{\u003C/span>\u003Cspan style=\"color:#E1E4E8\">count\u003C/span>\u003Cspan style=\"color:#79B8FF\">}\u003C/span>\u003Cspan style=\"color:#9ECBFF\">\"\u003C/span>\u003Cspan style=\"color:#E1E4E8\">)\u003C/span>\u003C/span>\u003C/code>\u003C/pre>\n\u003Cp>Ce script vous donne un CSV que vous pouvez croiser avec votre sitemap ou votre export Screaming Frog pour identifier les URLs présentes dans votre architecture mais absentes des crawls IA.\u003C/p>\n\u003Ch2>Scénario concret : un média tech de 8 000 articles\u003C/h2>\n\u003Cp>Prenons un cas réaliste. Un site de type média/blog tech — 8 200 articles publiés, 450 pages de catégories et tags, 12 landing pages statiques. Stack Next.js avec SSR, hébergé sur Vercel, CDN Cloudflare en front.\u003C/p>\n\u003Ch3>Les données brutes\u003C/h3>\n\u003Cp>Après un mois de collecte de logs (via Cloudflare Logpush vers un bucket S3, parsé avec le script ci-dessus) :\u003C/p>\n\u003Ctable>\n\u003Cthead>\n\u003Ctr>\n\u003Cth>Bot\u003C/th>\n\u003Cth>Hits/mois\u003C/th>\n\u003Cth>URLs uniques\u003C/th>\n\u003Cth>% du catalogue\u003C/th>\n\u003C/tr>\n\u003C/thead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>Googlebot\u003C/td>\n\u003Ctd>184 000\u003C/td>\n\u003Ctd>7 800\u003C/td>\n\u003Ctd>90.2%\u003C/td>\n\u003C/tr>\n\u003Ctr>\n\u003Ctd>Bytespider\u003C/td>\n\u003Ctd>31 000\u003C/td>\n\u003Ctd>2 100\u003C/td>\n\u003Ctd>24.3%\u003C/td>\n\u003C/tr>\n\u003Ctr>\n\u003Ctd>GPTBot\u003C/td>\n\u003Ctd>8 400\u003C/td>\n\u003Ctd>1 350\u003C/td>\n\u003Ctd>15.6%\u003C/td>\n\u003C/tr>\n\u003Ctr>\n\u003Ctd>ClaudeBot\u003C/td>\n\u003Ctd>3 200\u003C/td>\n\u003Ctd>680\u003C/td>\n\u003Ctd>7.9%\u003C/td>\n\u003C/tr>\n\u003Ctr>\n\u003Ctd>PerplexityBot\u003C/td>\n\u003Ctd>5 800\u003C/td>\n\u003Ctd>920\u003C/td>\n\u003Ctd>10.6%\u003C/td>\n\u003C/tr>\n\u003C/tbody>\n\u003C/table>\n\u003Ch3>Ce que les données révèlent\u003C/h3>\n\u003Cp>\u003Cstrong>Problème 1 : les articles récents sont sous-crawlés par les bots IA.\u003C/strong> Sur les 600 articles publiés dans les 90 derniers jours, GPTBot en a visité 89 (14.8%). Googlebot en a visité 571 (95.2%). Les bots IA découvrent les contenus récents avec un retard de 3 à 8 semaines par rapport à Googlebot.\u003C/p>\n\u003Cp>\u003Cstrong>Problème 2 : les pages de catégorie sont crawlées mais les articles paginés ne le sont pas.\u003C/strong> GPTBot visite \u003Ccode>/category/devops\u003C/code> mais ne suit pas \u003Ccode>/category/devops?page=4\u003C/code>. Les articles accessibles uniquement via la pagination profonde sont invisibles pour les LLM.\u003C/p>\n\u003Cp>\u003Cstrong>Problème 3 : les codes 403 sur les assets.\u003C/strong> 12% des requêtes de ClaudeBot retournaient un 403 — le WAF Cloudflare bloquait le bot. L'équipe n'avait pas whitelisté le user-agent dans les règles de firewall.\u003C/p>\n\u003Ch3>Les actions correctives\u003C/h3>\n\u003Cp>Pour le retard de découverte, l'équipe a ajouté un \u003Ccode>&#x3C;link rel=\"preload\">\u003C/code> dans le head de la homepage pointant vers un flux RSS/Atom des 50 derniers articles — les bots IA suivent les liens Atom de manière plus fiable que les sitemaps XML (observation empirique, non documentée officiellement).\u003C/p>\n\u003Cp>Pour la pagination, un passage à une architecture de scroll infini avec des URLs canoniques propres et un sitemap paginé a résolu le problème en 3 semaines.\u003C/p>\n\u003Cp>Pour les 403, une règle Cloudflare WAF :\u003C/p>\n\u003Cpre class=\"shiki github-dark\" style=\"background-color:#24292e;color:#e1e4e8\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\"># Cloudflare WAF Custom Rule (expression syntax)\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\"># Action: Skip (Allow)\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\"># Nom: Allow AI Crawlers\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">(http.\u003C/span>\u003Cspan style=\"color:#F97583\">user_agent\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> contains \u003C/span>\u003Cspan style=\"color:#9ECBFF\">\"GPTBot\"\u003C/span>\u003Cspan style=\"color:#E1E4E8\">) or\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">(http.\u003C/span>\u003Cspan style=\"color:#F97583\">user_agent\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> contains \u003C/span>\u003Cspan style=\"color:#9ECBFF\">\"ChatGPT-User\"\u003C/span>\u003Cspan style=\"color:#E1E4E8\">) or\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">(http.\u003C/span>\u003Cspan style=\"color:#F97583\">user_agent\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> contains \u003C/span>\u003Cspan style=\"color:#9ECBFF\">\"ClaudeBot\"\u003C/span>\u003Cspan style=\"color:#E1E4E8\">) or\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">(http.\u003C/span>\u003Cspan style=\"color:#F97583\">user_agent\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> contains \u003C/span>\u003Cspan style=\"color:#9ECBFF\">\"PerplexityBot\"\u003C/span>\u003Cspan style=\"color:#E1E4E8\">) or\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">(http.\u003C/span>\u003Cspan style=\"color:#F97583\">user_agent\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> contains \u003C/span>\u003Cspan style=\"color:#9ECBFF\">\"Applebot-Extended\"\u003C/span>\u003Cspan style=\"color:#E1E4E8\">) or\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">(http.\u003C/span>\u003Cspan style=\"color:#F97583\">user_agent\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> contains \u003C/span>\u003Cspan style=\"color:#9ECBFF\">\"Google-Extended\"\u003C/span>\u003Cspan style=\"color:#E1E4E8\">)\u003C/span>\u003C/span>\u003C/code>\u003C/pre>\n\u003Cp>Résultat après 6 semaines : les URLs uniques crawlées par GPTBot sont passées de 1 350 à 3 100 (+130%). Le site a commencé à apparaître dans les réponses de Perplexity et ChatGPT sur des requêtes de niche DevOps, là où il était absent avant.\u003C/p>\n\u003Ch2>Croiser les logs avec robots.txt et les directives d'accès\u003C/h2>\n\u003Cp>La log file analysis ne prend son sens que si vous maîtrisez ce que vous autorisez et ce que vous bloquez. Les crawlers IA respectent (pour la plupart) le robots.txt — mais les conventions sont encore en mouvement.\u003C/p>\n\u003Ch3>L'état des directives en 2026\u003C/h3>\n\u003Cp>Le fichier robots.txt gère les crawlers IA via des user-agents spécifiques. Voici un exemple de configuration qui autorise le crawl pour les moteurs de recherche IA tout en bloquant le scraping brut :\u003C/p>\n\u003Cpre>\u003Ccode># robots.txt — stratégie différenciée IA\n\n# Googlebot classique : accès complet\nUser-agent: Googlebot\nAllow: /\n\n# Google AI (Gemini, SGE) : accès au contenu éditorial\nUser-agent: Google-Extended\nAllow: /blog/\nAllow: /guides/\nDisallow: /account/\nDisallow: /api/\nDisallow: /admin/\n\n# OpenAI\nUser-agent: GPTBot\nAllow: /blog/\nAllow: /guides/\nAllow: /docs/\nDisallow: /account/\nDisallow: /api/\nDisallow: /staging/\n\n# Anthropic\nUser-agent: ClaudeBot\nAllow: /blog/\nAllow: /guides/\nDisallow: /account/\nDisallow: /api/\n\n# Bytespider — bloqué (scraping agressif, faible valeur retour)\nUser-agent: Bytespider\nDisallow: /\n\n# Sitemap\nSitemap: https://techblog.dev/sitemap-index.xml\n\u003C/code>\u003C/pre>\n\u003Cp>Le piège classique : bloquer un bot IA dans robots.txt puis se demander pourquoi le contenu n'apparaît pas dans les réponses du LLM associé. L'analyse de logs vous montre si un bot \u003Cem>tente\u003C/em> d'accéder à des URLs bloquées — un signal que votre politique de blocage mérite peut-être d'être affinée.\u003C/p>\n\u003Cp>Vérifiez dans vos logs les requêtes des bots IA qui retournent des 200 vs celles qui retournent des 403 ou 404. Un volume élevé de 404 pour GPTBot signifie que le bot a des références vers des URLs qui n'existent plus — potentiellement des backlinks ou des pages supprimées sans redirect.\u003C/p>\n\u003Ch2>Au-delà des logs : croiser avec les données de visibilité IA\u003C/h2>\n\u003Cp>La log file analysis seule ne suffit pas. L'insight stratégique vient du croisement entre :\u003C/p>\n\u003Col>\n\u003Cli>\u003Cstrong>Ce que les bots IA crawlent\u003C/strong> (vos logs serveur)\u003C/li>\n\u003Cli>\u003Cstrong>Ce que les moteurs de réponse IA citent\u003C/strong> (monitoring des citations dans ChatGPT, Perplexity, Gemini)\u003C/li>\n\u003Cli>\u003Cstrong>Ce que Google indexe et sert dans les AI Overviews\u003C/strong> (Search Console + scraping des SERP)\u003C/li>\n\u003C/ol>\n\u003Ch3>Identifier les intent gaps entre crawl IA et visibilité organique\u003C/h3>\n\u003Cp>Si GPTBot crawle vos pages \u003Ccode>/guides/kubernetes-deployment\u003C/code> mais que ces contenus n'apparaissent jamais dans les réponses ChatGPT sur les requêtes Kubernetes, le problème n'est pas le crawl — c'est la qualité ou la structure du contenu. Si en revanche GPTBot ne crawle jamais ces pages, le problème est en amont : découvrabilité, architecture, ou blocage technique.\u003C/p>\n\u003Cp>C'est le même type de raisonnement que l'analyse d'intent gaps via Search Console, \u003Ca href=\"/blog/how-to-measure-intent-gaps-using-google-search-console-data\">appliqué au monde des moteurs de réponse IA\u003C/a>. La méthode change, mais le principe reste : mesurer l'écart entre ce que vous proposez et ce que les systèmes consomment.\u003C/p>\n\u003Ch3>Le rôle du contenu structuré\u003C/h3>\n\u003Cp>Les bots IA extraient plus facilement les informations quand le contenu est structuré avec du balisage sémantique clair. Les pages qui utilisent des \u003Ccode>&#x3C;article>\u003C/code>, des \u003Ccode>&#x3C;h2>\u003C/code>/\u003Ccode>&#x3C;h3>\u003C/code> hiérarchiques, des listes \u003Ccode>&#x3C;dl>\u003C/code> pour les définitions, et du JSON-LD pour le schema markup sont crawlées plus en profondeur. C'est une corrélation observée dans les logs, pas une causalité prouvée — mais elle est consistante.\u003C/p>\n\u003Cp>\u003Ca href=\"/blog/optimiser-pour-les-moteurs-de-reponse-ia\">Optimiser pour les moteurs de réponse IA\u003C/a> passe par cette double couche : s'assurer que les bots accèdent au contenu (log analysis) et que le contenu est structuré pour être extractible (balisage sémantique).\u003C/p>\n\u003Ch2>Outils et stack technique pour la log file analysis IA\u003C/h2>\n\u003Ch3>Screaming Frog Log Analyzer\u003C/h3>\n\u003Cp>Screaming Frog dispose d'un module Log Analyzer qui importe les fichiers access log et permet de filtrer par user-agent. La limite : il faut manuellement ajouter les patterns de bots IA car les presets ne couvrent que les crawlers classiques (Googlebot, Bingbot). La fonctionnalité de croisement avec un crawl Screaming Frog est précieuse : vous visualisez les pages crawlées par le spider vs les pages visitées par chaque bot.\u003C/p>\n\u003Ch3>GoAccess pour le temps réel\u003C/h3>\n\u003Cp>Pour un monitoring rapide sur un serveur dédié :\u003C/p>\n\u003Cpre class=\"shiki github-dark\" style=\"background-color:#24292e;color:#e1e4e8\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\"># Monitoring temps réel des bots IA avec GoAccess\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#B392F0\">zcat\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> /var/log/nginx/access.log.\u003C/span>\u003Cspan style=\"color:#79B8FF\">*\u003C/span>\u003Cspan style=\"color:#9ECBFF\">.gz\u003C/span>\u003Cspan style=\"color:#F97583\"> |\u003C/span>\u003Cspan style=\"color:#79B8FF\"> \\\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#B392F0\">  grep\u003C/span>\u003Cspan style=\"color:#79B8FF\"> -E\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> \"(GPTBot|ClaudeBot|PerplexityBot|Bytespider|ChatGPT-User)\"\u003C/span>\u003Cspan style=\"color:#F97583\"> |\u003C/span>\u003Cspan style=\"color:#79B8FF\"> \\\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#B392F0\">  goaccess\u003C/span>\u003Cspan style=\"color:#79B8FF\"> --log-format=COMBINED\u003C/span>\u003Cspan style=\"color:#79B8FF\"> -o\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> /var/www/html/ai-bot-report.html\u003C/span>\u003Cspan style=\"color:#79B8FF\"> --real-time-html\u003C/span>\u003C/span>\u003C/code>\u003C/pre>\n\u003Cp>GoAccess génère un dashboard HTML interactif avec les URLs les plus crawlées, les codes de réponse, et les patterns temporels. L'option \u003Ccode>--real-time-html\u003C/code> met à jour le rapport en continu via WebSocket.\u003C/p>\n\u003Ch3>Solutions cloud pour les sites derrière un CDN\u003C/h3>\n\u003Cp>Si votre trafic passe par Cloudflare, Fastly ou AWS CloudFront, les logs ne sont pas sur votre serveur. Vous devez activer le log forwarding :\u003C/p>\n\u003Cul>\n\u003Cli>\u003Cstrong>Cloudflare\u003C/strong> : Logpush vers S3, R2, ou un endpoint HTTP. Configurez un filtre pour ne capturer que les requêtes dont le user-agent matche les bots.\u003C/li>\n\u003Cli>\u003Cstrong>Fastly\u003C/strong> : Real-time log streaming vers BigQuery, S3, ou Datadog.\u003C/li>\n\u003Cli>\u003Cstrong>CloudFront\u003C/strong> : Standard logs ou Real-time logs vers Kinesis Data Firehose.\u003C/li>\n\u003C/ul>\n\u003Cp>Le coût n'est pas négligeable. Un site à 500K pages vues/mois génère environ 1-2 Go de logs compressés. Un site à 10M pages vues/mois, 20-40 Go. Filtrer en amont (uniquement les bots) réduit le volume d'un facteur 50 à 100.\u003C/p>\n\u003Ch3>Monitoring continu vs analyse ponctuelle\u003C/h3>\n\u003Cp>L'analyse ponctuelle (une fois par trimestre, après une migration) donne un snapshot. Elle est utile mais insuffisante. Les crawlers IA changent de comportement sans préavis. OpenAI a modifié le crawl rate de GPTBot trois fois en 2025 selon les observations de la communauté SEO. Bytespider a été bloqué par défaut par plusieurs CDN, puis partiellement réautorisé.\u003C/p>\n\u003Cp>Un monitoring continu — qui détecte quand un bot IA arrête de crawler une section du site, ou quand un nouveau bot apparaît — est le seul moyen de réagir rapidement. C'est exactement le type de régression qu'un outil comme Seogard détecte automatiquement : une chute du volume de crawl IA sur une section spécifique déclenche une alerte avant que la perte de visibilité ne se matérialise dans les métriques de trafic.\u003C/p>\n\u003Ch2>Ce que les logs vous apprennent sur le futur de la search visibility\u003C/h2>\n\u003Cp>L'analyse des logs serveur pour les crawlers IA n'est pas un exercice académique. C'est le mécanisme de feedback le plus direct entre votre infrastructure technique et votre visibilité dans \u003Ca href=\"/blog/google-sge-ai-overviews-quel-impact-sur-le-seo-technique\">les systèmes qui remplacent progressivement les SERP classiques\u003C/a>.\u003C/p>\n\u003Cp>Trois tendances visibles dans les logs des sites que nous observons :\u003C/p>\n\u003Cp>\u003Cstrong>Le crawl IA se concentre.\u003C/strong> Les bots IA ne cherchent pas à tout indexer. Ils ciblent le contenu à haute densité informationnelle. Les sites qui produisent 200 articles thin de 300 mots voient moins de crawl IA que ceux qui publient 30 guides exhaustifs de 3 000 mots. Les logs le prouvent noir sur blanc.\u003C/p>\n\u003Cp>\u003Cstrong>Les bots IA sont plus sensibles aux erreurs techniques.\u003C/strong> Un 5xx transitoire que Googlebot retente 6 heures plus tard, GPTBot ne le retente parfois jamais. Chaque requête compte. Votre uptime et votre TTFB pour les bots IA doivent être irréprochables.\u003C/p>\n\u003Cp>\u003Cstrong>Le nombre de bots IA explose.\u003C/strong> En 2024, on comptait 4-5 crawlers IA significatifs. En 2026, \u003Ca href=\"/blog/openai-meta-bytedance-lead-ai-bot-traffic-in-publishing-via-sejournal-mattgsouthern\">on en recense plus d'une douzaine\u003C/a>, dont certains ne s'identifient pas clairement. L'analyse de logs est le seul moyen de détecter les crawlers non documentés qui accèdent à votre contenu.\u003C/p>\n\u003Cp>La log file analysis est la couche fondamentale de toute stratégie de visibilité IA. Sans elle, vous optimisez à l'aveugle — vous publiez du contenu en espérant que les bots le trouvent, sans vérifier s'ils le trouvent effectivement. Les logs ne mentent pas. Commencez par les lire.\u003C/p>",null,12,[18,19,20,21,22],"log file analysis","AI crawlers","crawl budget","search visibility","bot monitoring","Log file analysis pour AI crawlers : détecter ce que les bots IA ignorent","Fri Apr 17 2026 06:02:09 GMT+0000 (Coordinated Universal Time)",[26,40,53],{"_id":27,"slug":28,"__v":6,"author":7,"canonical":29,"category":10,"createdAt":30,"date":12,"description":31,"image":15,"imageAlt":15,"readingTime":16,"tags":32,"title":38,"updatedAt":39},"69e2055faa6b273b0caa9ce6","machine-first-architecture-ai-agents-are-here-and-your-website-isn-t-ready-says-no-hacks-podcast-host-via-sejournal-theshelleywalsh","https://seogard.io/blog/machine-first-architecture-ai-agents-are-here-and-your-website-isn-t-ready-says-no-hacks-podcast-host-via-sejournal-theshelleywalsh","2026-04-17T10:03:11.013Z","Les AI agents ne crawlent pas comme Googlebot. Architecture, données structurées, API endpoints : guide technique pour rendre votre site lisible par les machines autonomes.",[33,34,35,36,37],"machine-first architecture","AI agents","SEO technique","données structurées","agentic search","Machine-First Architecture : préparer votre site aux AI agents","Fri Apr 17 2026 10:03:11 GMT+0000 (Coordinated Universal Time)",{"_id":41,"slug":42,"__v":6,"author":7,"canonical":43,"category":10,"createdAt":44,"date":12,"description":45,"image":15,"imageAlt":15,"readingTime":16,"tags":46,"title":51,"updatedAt":52},"69e24b95aa6b273b0ce2c255","no-javascript-fallbacks-in-2026-less-critical-still-necessary","https://seogard.io/blog/no-javascript-fallbacks-in-2026-less-critical-still-necessary","2026-04-17T15:02:45.267Z","Googlebot rend le JS, mais pas toujours complètement. Où les fallbacks no-JS protègent encore votre indexation, vos liens et votre trafic organique.",[47,48,49,50,35],"no-javascript","fallbacks","rendering","indexation","No-JavaScript fallbacks en 2026 : moins critiques, toujours nécessaires","Fri Apr 17 2026 15:02:45 GMT+0000 (Coordinated Universal Time)",{"_id":54,"slug":55,"__v":6,"author":7,"canonical":56,"category":10,"createdAt":57,"date":58,"description":59,"image":15,"imageAlt":15,"readingTime":16,"tags":60,"title":66,"updatedAt":67},"69e07b73aa6b273b0c6f9b74","google-search-console-glitch-gives-seos-a-scare-via-sejournal-martinibuster","https://seogard.io/blog/google-search-console-glitch-gives-seos-a-scare-via-sejournal-martinibuster","2026-04-16T06:02:27.256Z","2026-04-16","Analyse technique du bug Google Search Console qui a affolé les SEOs. Comment vérifier vos données, automatiser les alertes et éviter les faux positifs.",[61,62,63,64,65],"google search console","glitch","monitoring SEO","API GSC","données search","Bug GSC : quand un glitch déclenche la panique SEO","Thu Apr 16 2026 06:02:27 GMT+0000 (Coordinated Universal Time)"]