<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Blogging on kenji.blog</title><link>http://kenji.blog/fr/categories/blogging/</link><description>Recent content in Blogging on kenji.blog</description><generator>Hugo -- gohugo.io</generator><language>fr</language><copyright>kenjinote</copyright><lastBuildDate>Sun, 13 Sep 2026 02:00:00 +0900</lastBuildDate><atom:link href="http://kenji.blog/fr/categories/blogging/index.xml" rel="self" type="application/rss+xml"/><item><title>Introduction à Hugo en tant que générateur de site statique (guide de migration depuis WordPress)</title><link>http://kenji.blog/fr/p/hugo-static-site-generator-wordpress-migration/</link><pubDate>Sun, 13 Sep 2026 02:00:00 +0900</pubDate><guid>http://kenji.blog/fr/p/hugo-static-site-generator-wordpress-migration/</guid><description>&lt;img src="http://kenji.blog/p/hugo-static-site-generator-wordpress-migration/img/eyecatch.jpg" alt="Featured image of post Introduction à Hugo en tant que générateur de site statique (guide de migration depuis WordPress)" />&lt;p>Dans le développement web moderne et la gestion de blogs, la vitesse d&amp;rsquo;affichage, la sécurité et la maintenabilité d&amp;rsquo;un site sont des éléments cruciaux. Longtemps leader incontesté en tant que fondation pour les blogs et les sites d&amp;rsquo;entreprise, &amp;ldquo;WordPress&amp;rdquo; est utilisé par de nombreux utilisateurs grâce à son écosystème de plugins flexible et son interface d&amp;rsquo;administration intuitive. Cependant, parce qu&amp;rsquo;il implique une communication avec une base de données et la génération dynamique de pages côté serveur (traitement via PHP), il présente également des vulnérabilités face aux pics de trafic et des problèmes de latence (retards d&amp;rsquo;affichage).&lt;/p>
&lt;p>C&amp;rsquo;est pourquoi les &amp;ldquo;Générateurs de Sites Statiques (SSG: Static Site Generator)&amp;rdquo; connaissent une diffusion rapide ces dernières années. Dans cet article, nous allons nous pencher sur &amp;ldquo;&lt;strong>Hugo&lt;/strong>&amp;rdquo;, un SSG développé en langage Go et connu pour sa vitesse de compilation (build) impressionnante, parmi de nombreux autres SSG. Nous l&amp;rsquo;expliquerons en détail, de la comparaison de son architecture technique avec les CMS dynamiques (Content Management System) tels que WordPress, aux procédures de migration concrètes, en passant par une évaluation des performances à l&amp;rsquo;aide de modèles mathématiques, ainsi que la structure des répertoires et l&amp;rsquo;ordre de recherche des modèles (templates) spécifiques à Hugo.&lt;/p>
&lt;hr>
&lt;h2 id="1-différences-techniques-entre-un-cms-dynamique-wordpress-et-un-générateur-de-site-statique-hugo">1. Différences techniques entre un CMS dynamique (WordPress) et un générateur de site statique (Hugo)
&lt;/h2>&lt;p>Dans la façon dont ils distribuent un site web, WordPress et Hugo adoptent des approches fondamentalement différentes.&lt;/p>
&lt;h3 id="11-architecture-de-wordpress-génération-dynamique">1.1 Architecture de WordPress (Génération dynamique)
&lt;/h3>&lt;p>WordPress est un représentant typique des CMS dynamiques qui construisent la page côté serveur à chaque requête. Lorsqu&amp;rsquo;un utilisateur (navigateur) accède à une page, le serveur web (Apache, Nginx, etc.) exécute des scripts PHP et envoie une requête à une base de données relationnelle telle que MySQL (ou MariaDB). Il combine le contenu récupéré de la base de données (données d&amp;rsquo;articles, catégories, tags, paramètres du site, etc.) avec des fichiers de modèles (templates) pour générer le code HTML final et le renvoyer au client.&lt;/p>
&lt;p>Bien que ce système ait l&amp;rsquo;avantage de pouvoir générer en temps réel un contenu différent pour chaque visiteur (ex : panier d&amp;rsquo;un site e-commerce, page dédiée aux utilisateurs connectés), il consomme énormément de ressources serveur, à moins qu&amp;rsquo;un mécanisme de cache (reverse proxy, plugins, etc.) ne soit correctement configuré.&lt;/p>
&lt;h3 id="12-architecture-de-hugo-génération-préalable-à-la-compilation">1.2 Architecture de Hugo (Génération préalable à la compilation)
&lt;/h3>&lt;p>D&amp;rsquo;autre part, comme son nom de &amp;ldquo;générateur de site statique&amp;rdquo; l&amp;rsquo;indique, Hugo effectue la génération du contenu au moment de la &amp;ldquo;compilation (build)&amp;rdquo; et non au moment de la &amp;ldquo;requête&amp;rdquo;. Le contenu n&amp;rsquo;est pas conservé dans une base de données, mais sous forme de &amp;ldquo;fichiers Markdown&amp;rdquo; locaux dont les versions sont gérées via Git, etc.
Lorsque le développeur exécute la commande (&lt;code>hugo&lt;/code>), Hugo lit les fichiers Markdown, injecte les données dans les modèles HTML spécifiés (fichiers de layout) et génère un ensemble de fichiers HTML/CSS/JS purs et complets.&lt;/p>
&lt;p>L&amp;rsquo;ensemble des fichiers générés (assets statiques) peut être distribué simplement en le plaçant sur un &amp;ldquo;environnement d&amp;rsquo;hébergement statique&amp;rdquo; tel qu&amp;rsquo;Amazon S3, Cloudflare Pages, Netlify, Vercel, ou un simple serveur Nginx. Puisqu&amp;rsquo;il ne nécessite ni base de données ni langage côté serveur (comme PHP), les risques de sécurité (injections SQL, vulnérabilités PHP, etc.) sont drastiquement réduits, et la vitesse de distribution est maximisée en étant mise en cache sur les nœuds périphériques (edge nodes) d&amp;rsquo;un CDN (Content Delivery Network).&lt;/p>
&lt;p>Les schémas Mermaid ci-dessous illustrent les différences entre chaque architecture.&lt;/p>
&lt;pre class="mermaid">
flowchart TD
subgraph WordPress[&amp;#34;CMS Dynamique (WordPress)&amp;#34;]
direction TB
Req1[&amp;#34;Requête de l&amp;#39;utilisateur&amp;#34;] --&amp;gt; WebServer1[&amp;#34;Serveur Web (Nginx/Apache)&amp;#34;]
WebServer1 --&amp;gt; PHP[&amp;#34;Interpréteur PHP&amp;#34;]
PHP &amp;lt;--&amp;gt; DB[&amp;#34;Base de données (MySQL)&amp;#34;]
PHP --&amp;gt; HTML1[&amp;#34;Génération HTML&amp;#34;]
HTML1 --&amp;gt; Res1[&amp;#34;Renvoi de la réponse&amp;#34;]
end
subgraph Hugo[&amp;#34;Générateur de site statique (Hugo)&amp;#34;]
direction TB
Dev[&amp;#34;Développeur / CI・CD&amp;#34;] --&amp;gt; HugoBuild[&amp;#34;Processus de compilation Hugo&amp;#34;]
Markdown[&amp;#34;Fichiers Markdown&amp;#34;] --&amp;gt; HugoBuild
Templates[&amp;#34;Modèles (HTML)&amp;#34;] --&amp;gt; HugoBuild
HugoBuild --&amp;gt; StaticFiles[&amp;#34;Fichiers statiques (HTML/CSS/JS)&amp;#34;]
StaticFiles --&amp;gt; CDN[&amp;#34;CDN / Hébergement statique&amp;#34;]
Req2[&amp;#34;Requête de l&amp;#39;utilisateur&amp;#34;] --&amp;gt; CDN
CDN --&amp;gt; Res2[&amp;#34;Renvoi de réponse instantanée&amp;#34;]
end
&lt;/pre>
&lt;hr>
&lt;h2 id="2-évaluation-des-performances-par-des-modèles-mathématiques">2. Évaluation des performances par des modèles mathématiques
&lt;/h2>&lt;p>L&amp;rsquo;un des plus grands avantages de la migration de WordPress vers Hugo est l&amp;rsquo;amélioration des performances (vitesse d&amp;rsquo;affichage). Pour comprendre cela quantitativement, exprimons-le avec un modèle mathématique simple.&lt;/p>
&lt;p>Le temps jusqu&amp;rsquo;à ce que le chargement de la page soit terminé (Load Time : $T_{load}$) est principalement divisé en temps de réponse du serveur (TTFB : Time To First Byte) et en temps de rendu/récupération des ressources par le navigateur ($T_{render}$).&lt;/p>
$$ T_{load} = T_{ttfb} + T_{render} $$&lt;p>Dans le cas d&amp;rsquo;un CMS dynamique (WordPress), le $T_{ttfb}$ est la somme des éléments suivants : latence du réseau ($T_{network}$), temps d&amp;rsquo;exécution des scripts côté serveur ($T_{php}$) et temps de traitement des requêtes de la base de données ($T_{db}$).&lt;/p>
$$ T_{ttfb\_wp} = T_{network} + T_{php} + T_{db} $$&lt;p>Dans un état où les accès sont concentrés (forte charge), $T_{php}$ et $T_{db}$ augmentent de manière non linéaire, et le système dans son ensemble peut devenir un goulot d&amp;rsquo;étranglement. Exprimé sous forme de formule, par rapport au nombre de requêtes ($N$), on observe la détérioration du temps de réponse suivante ($k$ est le coefficient de surcharge de traitement).&lt;/p>
$$ T_{php}(N) \approx O(N^k), \quad T_{db}(N) \approx O(N^k) \quad \text{where } k > 1 $$&lt;p>D&amp;rsquo;autre part, dans une architecture combinant un générateur de site statique (Hugo) et un CDN, il n&amp;rsquo;y a pas de traitement dynamique côté serveur (PHP ou requêtes DB). Comme le contenu est mis en cache sur des serveurs périphériques (edge servers) répartis dans le monde entier, le $T_{ttfb}$ dépend purement et uniquement de la latence du réseau du client jusqu&amp;rsquo;au serveur périphérique le plus proche ($T_{edge}$).&lt;/p>
$$ T_{ttfb\_hugo} = T_{edge} $$&lt;p>Par conséquent, $T_{edge} \ll (T_{network} + T_{php} + T_{db})$ se vérifie, et le TTFB est drastiquement réduit à quelques millisecondes à quelques dizaines de millisecondes. De plus, même si le nombre de requêtes $N$ augmente, le temps de réponse reste presque constant ($O(1)$) grâce à la fonction de répartition de charge (load balancing) des serveurs périphériques.&lt;/p>
$$ \lim_{N \to \infty} T_{ttfb\_hugo}(N) \approx \text{Constant} $$&lt;p>Ceci est la justification mathématique expliquant pourquoi Hugo (site statique) est extrêmement robuste face aux pics de trafic (par exemple, lors d&amp;rsquo;un buzz).&lt;/p>
&lt;hr>
&lt;h2 id="3-structure-de-base-et-principes-de-fonctionnement-de-hugo">3. Structure de base et principes de fonctionnement de Hugo
&lt;/h2>&lt;p>Pour maîtriser Hugo, il est essentiel de comprendre sa structure de répertoires unique et les concepts de &amp;ldquo;Front Matter&amp;rdquo; et de &amp;ldquo;Template Lookup Order&amp;rdquo; (Ordre de recherche des modèles).&lt;/p>
&lt;h3 id="31-explication-détaillée-de-la-structure-des-répertoires">3.1 Explication détaillée de la structure des répertoires
&lt;/h3>&lt;p>Lorsque vous créez un nouveau projet Hugo (&lt;code>hugo new site mysite&lt;/code>), la structure de répertoires suivante est générée.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="cl">mysite/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── archetypes/ # Modèles (templates) lors de la création de nouveau contenu (modèles pour Front Matter)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── assets/ # Fichiers traités par Hugo Pipes (SCSS/Sass, JavaScript, etc.)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── content/ # Contenu réel du site (fichiers Markdown). Remplace la DB.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── data/ # Données externes et paramètres utilisés sur l&amp;#39;ensemble du site (JSON, TOML, YAML, CSV, etc.)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── layouts/ # Modèles HTML déterminant l&amp;#39;apparence du site (utilise Go html/template)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── public/ # Emplacement où les fichiers statiques générés sont placés après l&amp;#39;exécution de la commande de compilation
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── static/ # Fichiers statiques publiés tels quels (images, favicon, fichiers texte pour robots, etc.)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── themes/ # Répertoire pour les thèmes tiers ou créés par soi-même
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">└── hugo.toml # Fichier de configuration de l&amp;#39;ensemble du site (auparavant config.toml était courant)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Dans WordPress, le contenu est stocké dans la table &lt;code>wp_posts&lt;/code> de MySQL, mais dans Hugo, il est entièrement géré en tant que fichiers texte (principalement Markdown) dans le répertoire &lt;code>content/&lt;/code>. Cela facilite la gestion des versions de contenu (Git).&lt;/p>
&lt;h3 id="32-gestion-de-contenu--markdown-et-front-matter">3.2 Gestion de contenu : Markdown et Front Matter
&lt;/h3>&lt;p>Chaque fichier d&amp;rsquo;article de Hugo possède un bloc de métadonnées appelé &amp;ldquo;Front Matter&amp;rdquo; tout en haut, suivi du corps du texte (Markdown) en dessous. Le Front Matter peut être écrit en TOML, YAML ou JSON, mais le YAML est largement utilisé.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nn">---&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">title&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;Comprendre la taxonomie de Hugo&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">date&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="ld">2026-09-13T10:00:00&lt;/span>&lt;span class="m">+09&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="m">00&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">draft&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kc">false&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">categories&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="s2">&amp;#34;Explication technique&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">tags&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="s2">&amp;#34;Hugo&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="s2">&amp;#34;Go&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">aliases&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="s2">&amp;#34;/old-category/hugo-taxonomy/&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nn">---&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="l">Le texte commence ici. Il est écrit en **Markdown**.&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="l">Nous allons expliquer les fonctionnalités puissantes de Hugo...&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Ce qu&amp;rsquo;il faut noter ici, c&amp;rsquo;est la clé &lt;code>aliases&lt;/code>. Lors d&amp;rsquo;une migration depuis WordPress, si le permalien (URL) change, cela a un impact négatif important sur le SEO. En utilisant la fonction d&amp;rsquo;alias de Hugo, il suffit de spécifier l&amp;rsquo;ancienne URL, et Hugo générera automatiquement un HTML de redirection (transfert via meta refresh). C&amp;rsquo;est très pratique car cela élimine le besoin de configurer des redirections côté serveur (comme .htaccess).&lt;/p>
&lt;h3 id="33-ordre-de-recherche-des-modèles-template-lookup-order">3.3 Ordre de recherche des modèles (Template Lookup Order)
&lt;/h3>&lt;p>L&amp;rsquo;une des fonctionnalités puissantes de Hugo est son mécanisme de recherche de modèles flexible (Template Lookup Order). Lors du rendu d&amp;rsquo;une page spécifique, Hugo recherche les répertoires et les noms de fichiers dans un ordre spécifique pour trouver le meilleur modèle.&lt;/p>
&lt;p>Par exemple, pour afficher un article unique (Single Page) appelé &lt;code>content/post/hello-world.md&lt;/code>, Hugo cherchera généralement un fichier de layout dans l&amp;rsquo;ordre suivant :&lt;/p>
&lt;ol>
&lt;li>&lt;code>layouts/post/single.html&lt;/code>&lt;/li>
&lt;li>&lt;code>layouts/post/list.html&lt;/code> (Ce n&amp;rsquo;est pas une erreur, mais généralement utilisé pour les listes)&lt;/li>
&lt;li>&lt;code>layouts/_default/single.html&lt;/code>&lt;/li>
&lt;li>&lt;code>themes/&amp;lt;THEME_NAME&amp;gt;/layouts/post/single.html&lt;/code>&lt;/li>
&lt;li>&lt;code>themes/&amp;lt;THEME_NAME&amp;gt;/layouts/_default/single.html&lt;/code>&lt;/li>
&lt;/ol>
&lt;p>Les développeurs peuvent &lt;strong>écraser (overrider)&lt;/strong> les modèles du thème en créant simplement un fichier du même nom dans le répertoire &lt;code>layouts/&lt;/code> de leur propre projet, sans modifier directement le code source du thème. Cela permet d&amp;rsquo;appliquer ses propres personnalisations sans bloquer les mises à jour du thème de base.&lt;/p>
&lt;h3 id="34-taxonomie-taxonomy">3.4 Taxonomie (Taxonomy)
&lt;/h3>&lt;p>Dans Hugo, le système de classification équivalent aux &amp;ldquo;catégories&amp;rdquo; et &amp;ldquo;tags&amp;rdquo; de WordPress est appelé &amp;ldquo;Taxonomie (Taxonomy)&amp;rdquo;.
Hugo prend en charge par défaut les taxonomies &lt;code>categories&lt;/code> et &lt;code>tags&lt;/code>, mais en éditant &lt;code>hugo.toml&lt;/code>, vous pouvez ajouter librement des taxonomies personnalisées (ex : &lt;code>series&lt;/code>, &lt;code>authors&lt;/code>, etc.).&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-toml" data-lang="toml">&lt;span class="line">&lt;span class="cl">&lt;span class="c"># Exemple de hugo.toml&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">taxonomies&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">category&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;categories&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">tag&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;tags&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">series&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;series&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">author&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;authors&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Cela permet d&amp;rsquo;organiser et de lister le contenu selon divers axes.&lt;/p>
&lt;hr>
&lt;h2 id="4-processus-de-migration-de-wordpress-vers-hugo">4. Processus de migration de WordPress vers Hugo
&lt;/h2>&lt;p>La clé du succès d&amp;rsquo;une migration de WordPress vers Hugo est la manière de convertir proprement le contenu dynamique de la base de données en fichiers statiques (Markdown + Front Matter) tout en maintenant la structure des URL existantes.&lt;/p>
&lt;p>Voici le flux de travail d&amp;rsquo;un pipeline de migration typique.&lt;/p>
&lt;pre class="mermaid">
flowchart LR
WPDB[&amp;#34;Base de données WP&amp;#34;] --&amp;gt;|Plugin| Exporter[&amp;#34;Outil d&amp;#39;exportation&amp;#34;]
Exporter --&amp;gt;| Extrait Texte, \nMéta, Images | ZipFile[&amp;#34;Fichier Zip / Dossier&amp;#34;]
ZipFile --&amp;gt;|Décompression| MarkdownFiles[&amp;#34;Fichiers Markdown \n(content/)&amp;#34;]
ZipFile --&amp;gt;|Décompression| ImageFiles[&amp;#34;Images \n(static/wp-content/)&amp;#34;]
MarkdownFiles --&amp;gt; Formatting[&amp;#34;Vérification et Formatage \n(Correction des Shortcodes)&amp;#34;]
Formatting --&amp;gt; Git[&amp;#34;Commit vers Git&amp;#34;]
&lt;/pre>
&lt;h3 id="41-extraction-des-données-et-conversion-en-markdown">4.1 Extraction des données et conversion en Markdown
&lt;/h3>&lt;p>Pour exporter les données WordPress pour Hugo, l&amp;rsquo;utilisation d&amp;rsquo;un plugin dédié est la méthode la plus simple et la plus fiable. Voici quelques approches représentatives.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Utilisation du plugin Jekyll Exporter&lt;/strong>
Comme Hugo a une structure de données très similaire à celle de Jekyll, un autre SSG, l&amp;rsquo;utilisation du plugin &amp;ldquo;Jekyll Exporter&amp;rdquo; pour WordPress est une méthode courante. En installant et en exécutant ce plugin, toutes vos publications et pages statiques seront converties en fichiers Markdown avec Front Matter et pourront être téléchargées sous forme de fichier ZIP avec vos fichiers d&amp;rsquo;images.&lt;/li>
&lt;li>&lt;strong>Scripts personnalisés utilisant l&amp;rsquo;API WordPress&lt;/strong>
Il s&amp;rsquo;agit de la méthode consistant à créer un script (par exemple en Python ou Node.js) qui interroge l&amp;rsquo;API REST de WordPress (&lt;code>/wp-json/wp/v2/posts&lt;/code>), analyse les données JSON et génère des fichiers Markdown par vous-même. Ceci est efficace pour les sites qui utilisent intensivement des champs personnalisés complexes (comme ACF) qui ne peuvent pas être entièrement gérés par des plugins.&lt;/li>
&lt;li>&lt;strong>Utilisation de l&amp;rsquo;outil wp2hugo&lt;/strong>
Il existe également une approche qui consiste à utiliser un outil CLI écrit en langage Go, par exemple, pour convertir directement le fichier XML d&amp;rsquo;exportation de WordPress (WXR) au format Hugo.&lt;/li>
&lt;/ol>
&lt;h3 id="42-maintien-de-la-structure-des-permaliens-url">4.2 Maintien de la structure des permaliens (URL)
&lt;/h3>&lt;p>Pour conserver les acquis SEO, il est extrêmement important de conserver l&amp;rsquo;URL de l&amp;rsquo;époque WordPress telle quelle. Si vous aviez configuré des permaliens tels que &lt;code>https://example.com/2026/09/13/my-post/&lt;/code> dans WordPress, vous devez spécifier la structure du permalien dans le &lt;code>hugo.toml&lt;/code> de Hugo.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-toml" data-lang="toml">&lt;span class="line">&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">permalinks&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">post&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;/:year/:month/:day/:slug/&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Alternativement, il est également possible de force une URL fixe pour chaque article en spécifiant directement le paramètre &lt;code>url&lt;/code> dans le Front Matter.
De plus, pour les pages dont les URL changent, utilisez &lt;code>aliases&lt;/code> comme mentionné précédemment pour configurer des redirections.&lt;/p>
&lt;h3 id="43-conversion-des-shortcodes">4.3 Conversion des shortcodes
&lt;/h3>&lt;p>Les shortcodes spécifiques à WordPress (ex : &lt;code>[gallery]&lt;/code>, &lt;code>[caption]&lt;/code>, et codes propres à divers plugins) restent souvent sous forme de chaînes de caractères brutes lors de l&amp;rsquo;exportation et nécessitent donc une attention particulière.
Celles-ci peuvent être soit supprimées en masse à l&amp;rsquo;aide de scripts de remplacement (sed ou Python), soit migrées pour être correctement rendues du côté de Hugo en utilisant la puissante &lt;strong>fonctionnalité de shortcodes personnalisés&lt;/strong> de Hugo (en créant un layout personnalisé dans &lt;code>layouts/shortcodes/&lt;/code>).&lt;/p>
&lt;hr>
&lt;h2 id="5-outil-cli-de-hugo-compilation-et-déploiement">5. Outil CLI de Hugo, Compilation et Déploiement
&lt;/h2>&lt;p>Une fois la migration terminée, il est temps de compiler (build) le site avec Hugo et de le publier dans le monde entier. Hugo, fourni sous forme de binaire du langage Go, offre une vitesse incroyable, compilant un site de plusieurs milliers ou dizaines de milliers de pages en seulement quelques secondes.&lt;/p>
&lt;h3 id="51-démarrage-du-serveur-de-développement-local">5.1 Démarrage du serveur de développement local
&lt;/h3>&lt;p>Lors de la rédaction d&amp;rsquo;articles ou de l&amp;rsquo;ajustement du design, démarrez le serveur local.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Commande pour démarrer le serveur de développement (utilisez -D pour inclure les articles brouillons)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">hugo server -D
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>En exécutant cette commande, vous pouvez prévisualiser le site sur &lt;code>http://localhost:1313/&lt;/code>. Hugo possède une puissante fonctionnalité intégrée de &amp;ldquo;LiveReload&amp;rdquo;. Dès l&amp;rsquo;instant où vous modifiez et enregistrez un fichier Markdown, un modèle ou un fichier CSS, l&amp;rsquo;écran de votre navigateur est automatiquement et très rapidement mis à jour. Ainsi, l&amp;rsquo;expérience de rédaction et de développement est bien plus confortable que sur l&amp;rsquo;écran d&amp;rsquo;administration de WordPress.&lt;/p>
&lt;h3 id="52-compilation-pour-la-production-et-optimisation-des-performances">5.2 Compilation pour la production et optimisation des performances
&lt;/h3>&lt;p>Pour générer des fichiers statiques à déployer en environnement de production, tapez simplement &lt;code>hugo&lt;/code>.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Exécution de la compilation pour la production. L&amp;#39;option --minify minimise HTML/CSS/JS&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">hugo --minify
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Grâce à cette commande, les fichiers de l&amp;rsquo;ensemble du site sont exportés vers le répertoire &lt;code>public/&lt;/code>. En ajoutant l&amp;rsquo;option &lt;code>--minify&lt;/code>, les sauts de ligne et espaces inutiles sont supprimés, réduisant encore davantage la taille des fichiers. Cela contribue directement à la réduction de la latence du réseau ($T_{network}$) dans le modèle mathématique mentionné précédemment.&lt;/p>
&lt;h3 id="53-automatisation-du-déploiement-cicd">5.3 Automatisation du déploiement (CI/CD)
&lt;/h3>&lt;p>Générer des fichiers statiques sur votre PC local à chaque fois et les télécharger via FTP, etc., est inefficace. Dans l&amp;rsquo;exploitation moderne des SSG, la meilleure pratique consiste à créer un environnement CI/CD qui compile et déploie automatiquement en utilisant un push vers un dépôt Git (GitHub, etc.) comme déclencheur.&lt;/p>
&lt;p>Par exemple, la forme de base d&amp;rsquo;une configuration (fichier YAML) pour déployer sur Cloudflare Pages ou GitHub Pages en utilisant GitHub Actions est la suivante :&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;span class="lnt">40
&lt;/span>&lt;span class="lnt">41
&lt;/span>&lt;span class="lnt">42
&lt;/span>&lt;span class="lnt">43
&lt;/span>&lt;span class="lnt">44
&lt;/span>&lt;span class="lnt">45
&lt;/span>&lt;span class="lnt">46
&lt;/span>&lt;span class="lnt">47
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="c"># Exemple de .github/workflows/hugo.yml&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Déployer le site Hugo vers GitHub Pages&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">on&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">push&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">branches&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;main&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">workflow_dispatch&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">permissions&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">contents&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">read&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">pages&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">write&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">id-token&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">write&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">jobs&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">build&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">runs-on&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">ubuntu-latest&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">steps&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Checkout&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">uses&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">actions/checkout@v3&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">with&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">submodules&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">recursive&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># Si vous gérez les thèmes avec des sous-modules&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">fetch-depth&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">0&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Setup Hugo&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">uses&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">peaceiris/actions-hugo@v2&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">with&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">hugo-version&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;latest&amp;#39;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">extended&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kc">true&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Build&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">run&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">hugo --minify&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Upload artifact&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">uses&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">actions/upload-pages-artifact@v2&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">with&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">path&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">./public&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">deploy&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">environment&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">github-pages&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">url&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">${{ steps.deployment.outputs.page_url }}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">runs-on&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">ubuntu-latest&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">needs&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">build&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">steps&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Deploy to GitHub Pages&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">id&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">deployment&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">uses&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">actions/deploy-pages@v2&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>En configurant ainsi, la simple action de &amp;ldquo;rédiger un article en Markdown et de le pousser (Push) vers GitHub&amp;rdquo; complète un pipeline automatisé où le site mis à jour est publié en environnement de production en quelques minutes.&lt;/p>
&lt;hr>
&lt;h2 id="6-le-seo-après-la-migration-et-les-avantages-opérationnels">6. Le SEO après la migration et les avantages opérationnels
&lt;/h2>&lt;p>Les administrateurs de site qui ont achevé la migration de WordPress vers Hugo ressentent souvent les 3 avantages notables suivants.&lt;/p>
&lt;h3 id="61-amélioration-spectaculaire-de-la-vitesse-du-site-et-des-core-web-vitals">6.1 Amélioration spectaculaire de la vitesse du site et des Core Web Vitals
&lt;/h3>&lt;p>Les requêtes de base de données et le rendu côté serveur étant éliminés, le temps de chargement de la page est réduit à l&amp;rsquo;ordre des millisecondes. Cela conduit directement à une amélioration significative des scores &amp;ldquo;Core Web Vitals&amp;rdquo; (LCP, FID/INP, CLS) qui sont des facteurs de classement pour Google. On peut s&amp;rsquo;attendre à une baisse du taux de rebond (bounce rate) des utilisateurs et à une amélioration du classement SEO.&lt;/p>
&lt;h3 id="62-libération-face-aux-menaces-de-sécurité">6.2 Libération face aux menaces de sécurité
&lt;/h3>&lt;p>Étant largement utilisé à travers le monde, WordPress est une cible constante d&amp;rsquo;attaques. Des risques persistent, tels que la falsification exploitant les vulnérabilités de plugins, ou la violation de l&amp;rsquo;écran de connexion par des attaques par force brute (brute-force).
Cependant, dans un site statique généré par Hugo, il n&amp;rsquo;y a pas de base de données, pas d&amp;rsquo;environnement PHP, et même pas d&amp;rsquo;interface d&amp;rsquo;administration (formulaire de connexion). Il n&amp;rsquo;y a aucune place pour qu&amp;rsquo;un pirate informatique s&amp;rsquo;introduise dans le serveur et réécrive la base de données, les risques de sécurité s&amp;rsquo;approchant au plus près de zéro.&lt;/p>
&lt;h3 id="63-une-exploitation-sans-maintenance">6.3 Une exploitation sans maintenance
&lt;/h3>&lt;p>L&amp;rsquo;utilisation de WordPress requiert des tâches de maintenance constantes : mise à jour du cœur du système, mise à jour des plugins, suivi des versions de PHP, etc. Vous devez constamment redouter le risque que votre site soit cassé en raison de problèmes de compatibilité.
Dans le cas de Hugo, il suffit de mettre à jour l&amp;rsquo;outil lui-même si nécessaire. Le code du site étant constitué d&amp;rsquo;ensembles de fichiers texte indépendants, cela offre un sentiment de tranquillité absolue : &amp;ldquo;même s&amp;rsquo;il est laissé tel quel, il ne se cassera pas&amp;rdquo;.&lt;/p>
&lt;hr>
&lt;h2 id="7-conclusion">7. Conclusion
&lt;/h2>&lt;p>Dans cet article, nous avons détaillé la migration d&amp;rsquo;un CMS dynamique tel que WordPress vers &amp;ldquo;Hugo&amp;rdquo;, un puissant générateur de site statique basé sur le langage Go, en couvrant les différences d&amp;rsquo;architecture technique, la preuve de performance via des modèles mathématiques, ainsi que les étapes concrètes de la migration.&lt;/p>
&lt;p>Bien que la migration vers un générateur de site statique nécessite un coût d&amp;rsquo;apprentissage initial (utilisation de Git, syntaxe Markdown, exécution de commandes CLI depuis un terminal, compréhension des spécifications du moteur de templates, etc.), elle offre en retour une &amp;ldquo;vitesse d&amp;rsquo;affichage écrasante&amp;rdquo;, une &amp;ldquo;sécurité robuste&amp;rdquo; et un état &amp;ldquo;sans maintenance&amp;rdquo; qui compensent largement cet effort.&lt;/p>
&lt;p>Si votre site web ne nécessite pas de changements fréquents de design ou de traitements dynamiques complexes (tels que des fonctionnalités réservées aux membres ou des fonctions e-commerce avancées) et que son objectif principal est la diffusion d&amp;rsquo;informations (blog, média, site d&amp;rsquo;entreprise), la migration vers Hugo constituera l&amp;rsquo;un des investissements techniques les plus efficaces. N&amp;rsquo;hésitez pas à faire de cet article votre point de départ vers la gestion de site web de nouvelle génération utilisant Hugo.&lt;/p></description></item><item><title>Blog technique écrit en Markdown : Paramètres d'éditeur pour doubler votre vitesse de rédaction</title><link>http://kenji.blog/fr/p/markdown-editor-setup-for-tech-blogs/</link><pubDate>Sat, 12 Sep 2026 12:00:00 +0900</pubDate><guid>http://kenji.blog/fr/p/markdown-editor-setup-for-tech-blogs/</guid><description>&lt;img src="http://kenji.blog/p/markdown-editor-setup-for-tech-blogs/img/eyecatch.jpg" alt="Featured image of post Blog technique écrit en Markdown : Paramètres d'éditeur pour doubler votre vitesse de rédaction" />&lt;p>Pour écrire continuellement sur un blog technique, il est essentiel d&amp;rsquo;optimiser l&amp;rsquo;environnement de rédaction. Dans cet article, nous allons explorer en profondeur les paramètres d&amp;rsquo;éditeur avancés qui permettront d&amp;rsquo;améliorer de façon spectaculaire votre vitesse de rédaction de blogs techniques à l&amp;rsquo;aide de Markdown. Nous couvrirons tout de manière exhaustive : la personnalisation extrême de Visual Studio Code (VS Code) et Neovim, l&amp;rsquo;utilisation de snippets, l&amp;rsquo;introduction de textlint (un outil de vérification grammaticale), l&amp;rsquo;automatisation dans le pipeline CI/CD, et enfin les techniques de rédaction de pointe utilisant des LLM comme GitHub Copilot.&lt;/p>
&lt;h2 id="1-modèle-mathématique-de-lamélioration-de-la-vitesse-de-rédaction">1. Modèle mathématique de l&amp;rsquo;amélioration de la vitesse de rédaction
&lt;/h2>&lt;p>Commençons par modéliser l&amp;rsquo;impact de l&amp;rsquo;optimisation des paramètres de l&amp;rsquo;éditeur sur le temps de rédaction avec une formule mathématique simple. Soit $T_{total}$ le temps de saisie total pour écrire un article de blog.&lt;/p>
$$
T_{total} = T_{think} + T_{type} + T_{format} + T_{review}
$$&lt;p>Ici, $T_{think}$ est le temps de réflexion, $T_{type}$ est le temps de frappe, $T_{format}$ est le temps de formatage (pour Markdown, etc.), et $T_{review}$ est le temps de relecture et de correction.&lt;/p>
&lt;p>Le temps économisé $T_{saved}$ grâce à la personnalisation de l&amp;rsquo;éditeur (comme l&amp;rsquo;introduction de snippets ou la configuration de Linter) peut être exprimé comme suit, en utilisant le nombre d&amp;rsquo;occurrences $N$ d&amp;rsquo;un modèle spécifique (par exemple, un shortcode Hugo ou un tableau Markdown), le temps requis pour une saisie manuelle $t_{manual}$, et le temps pris par l&amp;rsquo;automatisation via des snippets $t_{snippet}$.&lt;/p>
$$
T_{saved} = \sum_{i=1}^{k} N_i \times (t_{manual, i} - t_{snippet, i}) + T_{review\_saved}
$$&lt;p>De plus, l&amp;rsquo;introduction d&amp;rsquo;outils de formatage automatique et de Linting réduit considérablement le temps de vérification visuelle humaine $T_{review}$. La maximisation de ce $T_{saved}$ est le but même de cet article.&lt;/p>
&lt;h2 id="2-la-meilleure-configuration-pour-visual-studio-code-vs-code">2. La meilleure configuration pour Visual Studio Code (VS Code)
&lt;/h2>&lt;p>VS Code est actuellement l&amp;rsquo;un des éditeurs les plus populaires et dispose d&amp;rsquo;un puissant écosystème d&amp;rsquo;extensions pour l&amp;rsquo;écriture en Markdown.&lt;/p>
&lt;h3 id="extensions-recommandées">Extensions recommandées
&lt;/h3>&lt;p>Pour accélérer la rédaction, nous recommandons fortement d&amp;rsquo;installer les extensions suivantes.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Markdown All in One&lt;/strong> : Il dispose de toutes les fonctionnalités de base nécessaires à la rédaction en Markdown, telles que le gras/italique avec des raccourcis clavier, la continuation automatique des listes, et la génération automatique d&amp;rsquo;une table des matières (TOC).&lt;/li>
&lt;li>&lt;strong>markdownlint&lt;/strong> : Il vous avertit en temps réel des erreurs de syntaxe Markdown et des violations de style.&lt;/li>
&lt;li>&lt;strong>vscode-textlint&lt;/strong> : Il applique un ensemble de règles destinées aux documents techniques pour éviter les incohérences de notation et les erreurs grammaticales.&lt;/li>
&lt;/ol>
&lt;h3 id="configuration-de-snippets-personnalisés-pour-hugo-markdownjson">Configuration de snippets personnalisés pour Hugo (&lt;code>markdown.json&lt;/code>)
&lt;/h3>&lt;p>Si vous utilisez un générateur de site statique comme Hugo ou Docusaurus pour votre blog technique, vous devrez fréquemment saisir le Frontmatter ou des shortcodes spécifiques. En utilisant la fonctionnalité de snippet de VS Code, vous pouvez les développer instantanément.&lt;/p>
&lt;p>Sélectionnez &lt;code>Preferences: Configure User Snippets&lt;/code> dans la palette de commandes et ajoutez la configuration suivante à &lt;code>markdown.json&lt;/code>.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-json" data-lang="json">&lt;span class="line">&lt;span class="cl">&lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;Hugo Frontmatter&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;prefix&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;frontmatter&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;body&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;---&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;title: \&amp;#34;${1:Titre}\&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;slug: \&amp;#34;${2:slug-name}\&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;date: \&amp;#34;$CURRENT_YEAR-$CURRENT_MONTH-$CURRENT_DATE T$CURRENT_HOUR:$CURRENT_MINUTE:$CURRENT_SECOND+09:00\&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;image: \&amp;#34;img/eyecatch.jpg\&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;math: true&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;mermaid: true&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;categories: [\&amp;#34;${3:Catégorie}\&amp;#34;]&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;tags: [\&amp;#34;${4:Tag1}\&amp;#34;, \&amp;#34;${5:Tag2}\&amp;#34;]&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;---&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;${0}&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;description&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;Développe le YAML Frontmatter pour Hugo&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;Hugo Figure Shortcode&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;prefix&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;hfig&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;body&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;{{&amp;lt; figure src=\&amp;#34;${1:image.jpg}\&amp;#34; title=\&amp;#34;${2:Titre de l&amp;#39;image}\&amp;#34; &amp;gt;}}&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;description&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;Shortcode Figure de Hugo&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;Markdown Table&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;prefix&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;mtable&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;body&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;| ${1:En-tête 1} | ${2:En-tête 2} | ${3:En-tête 3} |&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;| :--- | :---: | ---: |&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;| ${4:Ligne 1} | ${5:Données} | ${6:Données} |&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;| ${7:Ligne 2} | ${8:Données} | ${9:Données} |&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;$0&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;description&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;Génère un tableau Markdown à 3 colonnes&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Avec cette configuration, il suffit de taper &lt;code>frontmatter&lt;/code> et d&amp;rsquo;appuyer sur la touche Tab pour déployer instantanément le YAML Frontmatter incluant l&amp;rsquo;heure actuelle, augmentant ainsi considérablement la vitesse initiale de rédaction.&lt;/p>
&lt;h3 id="assistance-à-la-rédaction-grâce-à-github-copilot">Assistance à la rédaction grâce à GitHub Copilot
&lt;/h3>&lt;p>Lorsque GitHub Copilot est activé dans VS Code, la complétion par l&amp;rsquo;IA basée sur le contexte fonctionne également en Markdown. Particulièrement pour les blogs techniques, l&amp;rsquo;IA anticipe et suggère &amp;ldquo;la prochaine structure à expliquer&amp;rdquo; ou &amp;ldquo;les blocs de code associés&amp;rdquo;, ce qui permet de réduire considérablement le temps de frappe $T_{type}$.&lt;/p>
&lt;h2 id="3-personnalisation-extrême-dans-neovim">3. Personnalisation extrême dans Neovim
&lt;/h2>&lt;p>L&amp;rsquo;interface graphique de VS Code est excellente, mais pour les amateurs de terminal et les Vimmers, Neovim est le choix ultime pour tout accomplir sans jamais retirer les mains du clavier.&lt;/p>
&lt;h3 id="architecture-lsp-de-neovim">Architecture LSP de Neovim
&lt;/h3>&lt;p>L&amp;rsquo;architecture du LSP (Language Server Protocol) et du Linter de Neovim dans un environnement Markdown est la suivante.&lt;/p>
&lt;pre class="mermaid">
classDiagram
class Neovim {
+&amp;#34;Tampon de texte&amp;#34;
+&amp;#34;Raccourcis clavier&amp;#34;
}
class nvim_lspconfig {
+&amp;#34;marksman (LSP Markdown)&amp;#34;
}
class null_ls_or_none_ls {
+&amp;#34;markdownlint&amp;#34;
+&amp;#34;textlint&amp;#34;
}
class LuaSnip {
+&amp;#34;Snippets dynamiques&amp;#34;
}
class CMP {
+&amp;#34;Moteur d&amp;#39;auto-complétion&amp;#34;
}
Neovim --&amp;gt; nvim_lspconfig : &amp;#34;Fournit des fonctionnalités sémantiques&amp;#34;
Neovim --&amp;gt; null_ls_or_none_ls : &amp;#34;Diagnostics et formatage&amp;#34;
Neovim --&amp;gt; CMP : &amp;#34;Requête de complétion&amp;#34;
CMP --&amp;gt; nvim_lspconfig : &amp;#34;Source LSP&amp;#34;
CMP --&amp;gt; LuaSnip : &amp;#34;Source de snippet&amp;#34;
&lt;/pre>
&lt;h3 id="développement-de-snippets-avancés-avec-luasnip">Développement de snippets avancés avec LuaSnip
&lt;/h3>&lt;p>Plus puissant encore que les snippets JSON de VS Code, il y a le plugin Neovim &lt;code>LuaSnip&lt;/code>. En utilisant la logique de Lua, vous pouvez calculer et déployer dynamiquement le contenu des snippets.&lt;/p>
&lt;p>Voici un exemple de configuration LuaSnip qui récupère dynamiquement la date et l&amp;rsquo;heure actuelles (JST) et développe le Frontmatter de Hugo.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-lua" data-lang="lua">&lt;span class="line">&lt;span class="cl">&lt;span class="kd">local&lt;/span> &lt;span class="n">ls&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;luasnip&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">local&lt;/span> &lt;span class="n">s&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">ls.snippet&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">local&lt;/span> &lt;span class="n">t&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">ls.text_node&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">local&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">ls.insert_node&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">local&lt;/span> &lt;span class="n">f&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">ls.function_node&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">-- Fonction pour obtenir l&amp;#39;heure actuelle JST&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">local&lt;/span> &lt;span class="kr">function&lt;/span> &lt;span class="nf">get_current_date_jst&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kr">return&lt;/span> &lt;span class="n">os.date&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;!%Y-%m-%dT%H:%M:%S&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">..&lt;/span> &lt;span class="s2">&amp;#34;+09:00&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kr">end&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">ls.add_snippets&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;markdown&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">s&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;frontmatter&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">t&lt;/span>&lt;span class="p">({&lt;/span>&lt;span class="s2">&amp;#34;---&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;title: &lt;/span>&lt;span class="se">\&amp;#34;&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">}),&lt;/span> &lt;span class="n">i&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;Titre&amp;#34;&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="n">t&lt;/span>&lt;span class="p">({&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="se">\&amp;#34;&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;slug: &lt;/span>&lt;span class="se">\&amp;#34;&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">}),&lt;/span> &lt;span class="n">i&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;nom-du-slug&amp;#34;&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="n">t&lt;/span>&lt;span class="p">({&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="se">\&amp;#34;&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;date: &lt;/span>&lt;span class="se">\&amp;#34;&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">}),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">f&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kr">function&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="kr">return&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="n">get_current_date_jst&lt;/span>&lt;span class="p">()}&lt;/span> &lt;span class="kr">end&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="p">{}),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">t&lt;/span>&lt;span class="p">({&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="se">\&amp;#34;&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;image: &lt;/span>&lt;span class="se">\&amp;#34;&lt;/span>&lt;span class="s2">img/eyecatch.jpg&lt;/span>&lt;span class="se">\&amp;#34;&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;math: true&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;mermaid: true&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;categories: [&lt;/span>&lt;span class="se">\&amp;#34;&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">}),&lt;/span> &lt;span class="n">i&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">3&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;Catégorie&amp;#34;&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="n">t&lt;/span>&lt;span class="p">({&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="se">\&amp;#34;&lt;/span>&lt;span class="s2">]&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;tags: [&lt;/span>&lt;span class="se">\&amp;#34;&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">}),&lt;/span> &lt;span class="n">i&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">4&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;Tag&amp;#34;&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="n">t&lt;/span>&lt;span class="p">({&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="se">\&amp;#34;&lt;/span>&lt;span class="s2">]&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;---&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">}),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">i&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">s&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;mtable&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">t&lt;/span>&lt;span class="p">({&lt;/span>&lt;span class="s2">&amp;#34;| &amp;#34;&lt;/span>&lt;span class="p">}),&lt;/span> &lt;span class="n">i&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;En-tête 1&amp;#34;&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="n">t&lt;/span>&lt;span class="p">({&lt;/span>&lt;span class="s2">&amp;#34; | &amp;#34;&lt;/span>&lt;span class="p">}),&lt;/span> &lt;span class="n">i&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;En-tête 2&amp;#34;&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="n">t&lt;/span>&lt;span class="p">({&lt;/span>&lt;span class="s2">&amp;#34; |&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;|---|---|&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;| &amp;#34;&lt;/span>&lt;span class="p">}),&lt;/span> &lt;span class="n">i&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">3&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;Cellule 1&amp;#34;&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="n">t&lt;/span>&lt;span class="p">({&lt;/span>&lt;span class="s2">&amp;#34; | &amp;#34;&lt;/span>&lt;span class="p">}),&lt;/span> &lt;span class="n">i&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">4&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;Cellule 2&amp;#34;&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="n">t&lt;/span>&lt;span class="p">({&lt;/span>&lt;span class="s2">&amp;#34; |&amp;#34;&lt;/span>&lt;span class="p">}),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">})&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">})&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Ainsi, en exploitant la puissance d&amp;rsquo;un langage de programmation (Lua), vous pouvez créer des snippets complexes qui ne se contentent pas de chaînes de caractères fixes, mais intègrent des valeurs de retour de fonctions ou ajustent dynamiquement le nombre de colonnes d&amp;rsquo;un tableau en fonction du nombre de caractères saisis.&lt;/p>
&lt;h2 id="4-analyse-statique-textlint-et-expressions-régulières-pour-allier-qualité-et-rapidité-de-rédaction">4. Analyse statique (textlint et expressions régulières) pour allier qualité et rapidité de rédaction
&lt;/h2>&lt;p>Pour garantir la qualité de votre blog, vous devez éviter les fautes de frappe et les incohérences de notation. Faire cela manuellement augmenterait de façon exponentielle $T_{review}$, c&amp;rsquo;est pourquoi nous introduisons l&amp;rsquo;analyse statique avec &lt;code>textlint&lt;/code>.&lt;/p>
&lt;h3 id="introduction-de-textlint-et-de-lensemble-de-règles">Introduction de textlint et de l&amp;rsquo;ensemble de règles
&lt;/h3>&lt;p>Installez textlint dans l&amp;rsquo;environnement Node.js.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">npm install -D textlint textlint-rule-preset-ja-technical-writing textlint-rule-prh textlint-filter-rule-comments
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Créez un fichier &lt;code>.textlintrc.json&lt;/code> à la racine de votre projet et configurez-le comme suit.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-json" data-lang="json">&lt;span class="line">&lt;span class="cl">&lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;filters&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;comments&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="kc">true&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;rules&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;preset-ja-technical-writing&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;ja-no-mixed-period&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;periodMark&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;。&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;sentence-length&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;max&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">100&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;prh&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;rulePaths&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;./prh.yml&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Créez un fichier &lt;code>prh.yml&lt;/code> pour définir les incohérences de notation des termes techniques. Par exemple, uniformisez &amp;ldquo;serveur&amp;rdquo; et &amp;ldquo;Serveur&amp;rdquo;, ou &amp;ldquo;Javascript&amp;rdquo; et &amp;ldquo;JavaScript&amp;rdquo;.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;span class="lnt">8
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">version&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">1&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">rules&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">expected&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;JavaScript&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">pattern&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;Javascript&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">expected&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;serveur&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">pattern&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;Serveur&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">expected&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;interface&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">pattern&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;Interface&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Grâce à cela, chaque fois que vous tapez du texte dans l&amp;rsquo;éditeur, vous êtes averti en temps réel des incohérences de notation, ce qui réduit le temps de correction à presque zéro.&lt;/p>
&lt;h3 id="remplacement-par-lots-et-modèles-structurés-à-laide-dexpressions-régulières">Remplacement par lots et modèles structurés à l&amp;rsquo;aide d&amp;rsquo;expressions régulières
&lt;/h3>&lt;p>Lors de la migration d&amp;rsquo;articles existants vers Markdown ou de l&amp;rsquo;importation de texte depuis l&amp;rsquo;extérieur, le remplacement par lots avec des expressions régulières est très pratique.&lt;/p>
&lt;p>Par exemple, l&amp;rsquo;expression régulière pour convertir la balise HTML &lt;code>&amp;lt;b&amp;gt;gras&amp;lt;/b&amp;gt;&lt;/code> en Markdown &lt;code>**gras**&lt;/code> :&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Modèle de recherche&lt;/strong> : &lt;code>&amp;lt;b&amp;gt;(.*?)&amp;lt;/b&amp;gt;&lt;/code>&lt;/li>
&lt;li>&lt;strong>Modèle de remplacement&lt;/strong> : &lt;code>**$1**&lt;/code>&lt;/li>
&lt;/ul>
&lt;p>Pour regrouper les sauts de ligne consécutifs inutiles en un seul :&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Modèle de recherche&lt;/strong> : &lt;code>\n{3,}&lt;/code>&lt;/li>
&lt;li>&lt;strong>Modèle de remplacement&lt;/strong> : &lt;code>\n\n&lt;/code>&lt;/li>
&lt;/ul>
&lt;p>En exécutant ces commandes via la fonction de recherche et de remplacement de VS Code (en mode expression régulière) ou la commande &lt;code>%s&lt;/code> de Neovim (&lt;code>:%s/&amp;lt;b&amp;gt;\(.*?\)&amp;lt;\/b&amp;gt;/**\1**/g&lt;/code>), vous pouvez unifier le formatage en un instant.&lt;/p>
&lt;h3 id="vérification-automatique-par-pipeline-cicd">Vérification automatique par pipeline CI/CD
&lt;/h3>&lt;p>De plus, en utilisant GitHub Actions, nous pouvons construire un pipeline CI qui exécute automatiquement textlint lors du push d&amp;rsquo;un article de blog. Cela permet d&amp;rsquo;empêcher à l&amp;rsquo;avance le déploiement d&amp;rsquo;articles violant les règles.&lt;/p>
&lt;pre class="mermaid">
flowchart TD
A[&amp;#34;Auteur&amp;#34;] --&amp;gt;|Pousser les modifications| B[&amp;#34;Dépôt GitHub&amp;#34;]
B --&amp;gt; C{&amp;#34;Déclenchement des actions GitHub&amp;#34;}
C --&amp;gt; D[&amp;#34;Cloner le dépôt&amp;#34;]
D --&amp;gt; E[&amp;#34;Configurer Node.js&amp;#34;]
E --&amp;gt; F[&amp;#34;npm install&amp;#34;]
F --&amp;gt; G[&amp;#34;Exécuter textlint&amp;#34;]
G --&amp;gt;|Succès| H[&amp;#34;Construire le site Hugo&amp;#34;]
G --&amp;gt;|Échec| I[&amp;#34;Signaler l&amp;#39;erreur sur la PR/Commit&amp;#34;]
H --&amp;gt; J[&amp;#34;Déployer sur l&amp;#39;hébergement (Vercel/Netlify)&amp;#34;]
&lt;/pre>
&lt;h2 id="5-lart-décrire-en-markdown-à-lère-des-llm">5. L&amp;rsquo;art d&amp;rsquo;écrire en Markdown à l&amp;rsquo;ère des LLM
&lt;/h2>&lt;p>Dans la rédaction de blogs techniques modernes, l&amp;rsquo;utilisation de LLM (Large Language Models) est incontournable. En exploitant les outils d&amp;rsquo;IA intégrés à l&amp;rsquo;éditeur, la vitesse de rédaction peut être encore doublée.&lt;/p>
&lt;h3 id="ingénierie-des-prompts-prompt-engineering-dans-léditeur">Ingénierie des prompts (Prompt Engineering) dans l&amp;rsquo;éditeur
&lt;/h3>&lt;p>En utilisant GitHub Copilot Chat dans VS Code, ou &lt;code>ChatGPT.nvim&lt;/code> et &lt;code>Copilot.vim&lt;/code> dans Neovim, vous pouvez lancer des prompts comme celui-ci sans quitter votre éditeur :&lt;/p>
&lt;blockquote>
&lt;p>&amp;ldquo;Crée un plan structuré en Markdown pour les débutants concernant les technologies suivantes : Docker, Kubernetes, CI/CD&amp;rdquo;&lt;/p>
&lt;/blockquote>
&lt;p>Immédiatement, une structure Markdown avec des titres et des puces sera générée. Il ne nous reste plus qu&amp;rsquo;à étoffer cette structure.&lt;/p>
&lt;p>De plus, pour la rédaction de diagrammes Mermaid complexes ou de formules mathématiques (LaTeX), donner des instructions à l&amp;rsquo;IA permet de générer une syntaxe précise. Par exemple, la base de la mise en page des formules et diagrammes de cet article a également été accélérée grâce au pair-writing avec un LLM.&lt;/p>
&lt;h2 id="6-conclusion">6. Conclusion
&lt;/h2>&lt;p>Nous avons expliqué les paramètres d&amp;rsquo;éditeur qui permettent de doubler la vitesse d&amp;rsquo;écriture lors de la rédaction d&amp;rsquo;un blog technique en Markdown.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Prise de conscience du modèle mathématique&lt;/strong> : Éliminer les tâches répétitives pour maximiser $T_{saved}$.&lt;/li>
&lt;li>&lt;strong>Utilisation de VS Code&lt;/strong> : Gagner du temps de saisie avec les extensions et les snippets de &lt;code>markdown.json&lt;/code>.&lt;/li>
&lt;li>&lt;strong>Personnalisation extrême de Neovim&lt;/strong> : Snippets dynamiques avec &lt;code>LuaSnip&lt;/code> et utilisation exclusive du clavier.&lt;/li>
&lt;li>&lt;strong>textlint et analyse statique&lt;/strong> : Intégration d&amp;rsquo;un Linter local et du CI/CD pour réduire le temps de correction à presque zéro.&lt;/li>
&lt;li>&lt;strong>Intégration des LLM&lt;/strong> : Laisser l&amp;rsquo;IA générer la structure Markdown et le code des diagrammes directement dans l&amp;rsquo;éditeur.&lt;/li>
&lt;/ol>
&lt;p>En intégrant ces paramètres à votre propre environnement, la &amp;ldquo;corvée&amp;rdquo; de l&amp;rsquo;écriture disparaîtra, et le volume ainsi que la qualité de votre production technique s&amp;rsquo;amélioreront de manière spectaculaire. Pourquoi ne pas commencer par enregistrer un simple petit snippet dès aujourd&amp;rsquo;hui ?&lt;/p></description></item><item><title>Ce que les ingénieurs doivent faire pour augmenter le trafic mensuel de leur blog technique</title><link>http://kenji.blog/fr/p/tech-blog-growth-strategies-for-engineers/</link><pubDate>Sat, 12 Sep 2026 12:00:00 +0900</pubDate><guid>http://kenji.blog/fr/p/tech-blog-growth-strategies-for-engineers/</guid><description>&lt;img src="http://kenji.blog/p/tech-blog-growth-strategies-for-engineers/img/eyecatch.jpg" alt="Featured image of post Ce que les ingénieurs doivent faire pour augmenter le trafic mensuel de leur blog technique" />&lt;h2 id="introduction--le-growth-hacking-des-blogs-techniques-une-compétence-propre-aux-ingénieurs">Introduction : Le Growth Hacking des blogs techniques, une compétence propre aux ingénieurs
&lt;/h2>&lt;p>Beaucoup d&amp;rsquo;ingénieurs logiciels lancent un blog technique, mais rares sont ceux qui parviennent à attirer un certain niveau de trafic et à le maintenir ou l&amp;rsquo;augmenter sur le long terme. Rédiger des articles techniques de haute qualité est une condition préalable, mais l&amp;rsquo;époque où « écrire de bons articles suffisait pour être lu naturellement » est bel et bien révolue. Les algorithmes actuels des moteurs de recherche sont devenus complexes, et le flux d&amp;rsquo;informations sur les réseaux sociaux est plus rapide que jamais.&lt;/p>
&lt;p>Cependant, les ingénieurs possèdent des atouts que d&amp;rsquo;autres professions n&amp;rsquo;ont pas. Ils sont capables de « comprendre l&amp;rsquo;architecture des systèmes, de combiner des outils pour automatiser des processus, et d&amp;rsquo;analyser des données via la programmation ». Dans cet article, au lieu de nous limiter à de simples techniques de rédaction, nous considérerons le blog technique comme un véritable « produit » et expliquerons de manière très détaillée et pratique les stratégies permettant d&amp;rsquo;augmenter drastiquement le trafic mensuel grâce au pouvoir de l&amp;rsquo;ingénierie.&lt;/p>
&lt;hr>
&lt;h2 id="1-architecture-seo-pour-les-blogs-techniques-à-lattention-des-ingénieurs">1. Architecture SEO pour les blogs techniques à l&amp;rsquo;attention des ingénieurs
&lt;/h2>&lt;p>Le système de base du blog (comme les générateurs de sites statiques) et la structure HTML sont les éléments les plus cruciaux pour que les moteurs de recherche puissent interpréter correctement le contenu.&lt;/p>
&lt;h3 id="11-optimisation-des-signaux-web-essentiels-core-web-vitals">1.1 Optimisation des Signaux Web Essentiels (Core Web Vitals)
&lt;/h3>&lt;p>Google utilise l&amp;rsquo;expérience sur la page comme facteur de classement, et les &lt;strong>Signaux Web Essentiels (LCP, FID/INP, CLS)&lt;/strong> ne peuvent être ignorés, même pour un blog technique.
Les blogs techniques utilisent souvent de nombreux blocs de code source, des formules mathématiques (MathJax / KaTeX) et des illustrations. Ces éléments ont tendance à retarder le rendu de la page.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>LCP (Largest Contentful Paint)&lt;/strong> : Vitesse de chargement du contenu principal dans la ligne de flottaison. Utilisez le WebP ou l&amp;rsquo;AVIF pour les images à la une, et préchargez-les en ajoutant l&amp;rsquo;attribut &lt;code>fetchpriority=&amp;quot;high&amp;quot;&lt;/code>. De plus, les gros fichiers CSS ou JS pour la coloration syntaxique doivent être chargés de manière asynchrone ou conçus pour n&amp;rsquo;être chargés que sur les pages nécessaires.&lt;/li>
&lt;li>&lt;strong>CLS (Cumulative Layout Shift)&lt;/strong> : Décalage inattendu de la mise en page pendant le chargement de l&amp;rsquo;article. En réservant à l&amp;rsquo;avance l&amp;rsquo;espace d&amp;rsquo;affichage pour les formules et les images à l&amp;rsquo;aide de la propriété CSS &lt;code>aspect-ratio&lt;/code>, etc., vous évitez les sauts visuels lors de l&amp;rsquo;insertion ultérieure de nœuds DOM.&lt;/li>
&lt;li>&lt;strong>INP (Interaction to Next Paint)&lt;/strong> : Réactivité aux interactions de l&amp;rsquo;utilisateur. Il est impératif de ne pas exécuter de JavaScript lourd (par exemple, une recherche plein texte dynamique côté client ou l&amp;rsquo;exécution d&amp;rsquo;un énorme parseur Markdown) sur le thread principal. Il faut le déléguer à un Web Worker ou générer du HTML statique lors du build (SSG).&lt;/li>
&lt;/ul>
&lt;h3 id="12-implémentation-des-données-structurées-json-ld">1.2 Implémentation des données structurées (JSON-LD)
&lt;/h3>&lt;p>Afin d&amp;rsquo;indiquer explicitement aux moteurs de recherche que la page est un « article » et qui en est « l&amp;rsquo;auteur », implémentez des données structurées au format JSON-LD. L&amp;rsquo;utilisation de schémas tels que &lt;code>TechArticle&lt;/code> ou &lt;code>SoftwareSourceCode&lt;/code> augmente la probabilité d&amp;rsquo;apparaître dans les résultats enrichis de Google, ce qui améliore le CTR (taux de clics).&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-html" data-lang="html">&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">script&lt;/span> &lt;span class="na">type&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;application/ld+json&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;@context&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;https://schema.org&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;@type&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;TechArticle&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;headline&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;Ce que les ingénieurs doivent faire pour augmenter le trafic mensuel de leur blog technique&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;image&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;https://example.com/img/eyecatch.jpg&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;datePublished&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;2026-09-14T10:00:00+09:00&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;author&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;@type&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;Person&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;Kenji&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;url&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;https://example.com/about/&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;publisher&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;@type&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;Organization&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;Kenji&amp;#39;s Tech Blog&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;logo&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;@type&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;ImageObject&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;url&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;https://example.com/img/logo.png&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">script&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="13-html-sémantique-et-optimisation-de-la-structure-du-document">1.3 HTML sémantique et optimisation de la structure du document
&lt;/h3>&lt;p>L&amp;rsquo;imbrication correcte des balises d&amp;rsquo;en-tête (&lt;code>h1&lt;/code> à &lt;code>h6&lt;/code>) est fondamentale, mais un blog technique exige également l&amp;rsquo;utilisation précise des balises sémantiques HTML5 telles que &lt;code>article&lt;/code>, &lt;code>section&lt;/code>, &lt;code>aside&lt;/code> et &lt;code>nav&lt;/code>. De plus, l&amp;rsquo;utilisation appropriée des balises &lt;code>&amp;lt;code&amp;gt;&lt;/code> et &lt;code>&amp;lt;pre&amp;gt;&lt;/code> pour le code source, &lt;code>&amp;lt;kbd&amp;gt;&lt;/code> pour les entrées clavier, et &lt;code>&amp;lt;var&amp;gt;&lt;/code> pour les variables permet de fournir un HTML lisible par les machines. Il s&amp;rsquo;agit également d&amp;rsquo;une méthode très efficace pour l&amp;rsquo;indexation de contenu par l&amp;rsquo;IA (collecte de données d&amp;rsquo;apprentissage pour les LLM et systèmes RAG).&lt;/p>
&lt;hr>
&lt;h2 id="2-psychologie-de-lintention-de-recherche-et-stratégie-de-mots-clés">2. Psychologie de l&amp;rsquo;intention de recherche et stratégie de mots-clés
&lt;/h2>&lt;p>Pour maximiser le trafic en provenance des moteurs de recherche (trafic organique), il est nécessaire de déchiffrer avec précision l&amp;rsquo;intention de recherche de l&amp;rsquo;utilisateur, c&amp;rsquo;est-à-dire « pourquoi il a cherché ce mot-clé ». Les intentions de recherche dans le domaine technique peuvent être classées en deux grandes catégories.&lt;/p>
&lt;h3 id="21-type--résolution-derreur--et-type--apprentissage-systématique--revue-">2.1 Type « Résolution d&amp;rsquo;erreur » et Type « Apprentissage systématique / Revue »
&lt;/h3>&lt;ol>
&lt;li>
&lt;p>&lt;strong>Type Résolution d&amp;rsquo;erreur (Troubleshooting Intent)&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>Exemples de mots-clés : &lt;code>Docker &amp;quot;no space left on device&amp;quot; solution&lt;/code>, &lt;code>Python IndexError list index out of range cause&lt;/code>&lt;/li>
&lt;li>Psychologie : Bloqué par une erreur lors du développement, l&amp;rsquo;utilisateur cherche un remède immédiat sous forme de commande ou d&amp;rsquo;extrait de code.&lt;/li>
&lt;li>Stratégie : Présentez la « conclusion (code ou commande pour résoudre le problème) » dès le début de l&amp;rsquo;article (dans la ligne de flottaison). Placez le contexte et les explications détaillées des mécanismes plus bas, afin de satisfaire immédiatement le désir de l&amp;rsquo;utilisateur de « réparer tout de suite ». Cela permet de réduire le taux de rebond (bounce rate).&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Type Apprentissage systématique / Revue (Learning &amp;amp; Review Intent)&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>Exemples de mots-clés : &lt;code>React vs Vue 2026 comparaison&lt;/code>, &lt;code>Rust traitement asynchrone introduction&lt;/code>, &lt;code>GCP architecture réseau conception&lt;/code>&lt;/li>
&lt;li>Psychologie : Souhaite sélectionner une nouvelle stack technique ou approfondir sa compréhension depuis les bases, et est prêt à prendre le temps de lire.&lt;/li>
&lt;li>Stratégie : Enrichissez la table des matières (TOC) et utilisez de nombreux schémas et diagrammes d&amp;rsquo;architecture (comme Mermaid). Comparez objectivement les avantages et les inconvénients, et incluez des cas d&amp;rsquo;utilisation pour montrer comment cela s&amp;rsquo;applique dans la pratique, ce qui augmentera le temps passé sur la page.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;h3 id="22-modèle-de-décroissance-exponentielle-du-trafic-et-stratégie-de-longue-traîne">2.2 Modèle de décroissance exponentielle du trafic et stratégie de longue traîne
&lt;/h3>&lt;p>Le trafic d&amp;rsquo;un article technique a tendance à former un pic (augmentation soudaine) immédiatement après sa publication grâce au buzz sur les réseaux sociaux, puis à diminuer de manière exponentielle. Ce trafic $V(t)$ peut être approximé par le modèle mathématique suivant :&lt;/p>
$$ V(t) = V_0 e^{-\lambda t} + C $$&lt;p>Où :&lt;/p>
&lt;ul>
&lt;li>$V(t)$ : Volume de trafic à l&amp;rsquo;instant $t$&lt;/li>
&lt;li>$V_0$ : Volume du pic de trafic initial dû au buzz sur les réseaux sociaux juste après la publication&lt;/li>
&lt;li>$\lambda$ : Constante d&amp;rsquo;atténuation due à l&amp;rsquo;obsolescence du contenu ou à l&amp;rsquo;oubli sur les réseaux sociaux (dépend de la vitesse d&amp;rsquo;évolution des tendances technologiques)&lt;/li>
&lt;li>$C$ : Trafic organique stable provenant des moteurs de recherche (trafic de base)&lt;/li>
&lt;/ul>
&lt;p>La clé pour augmenter le trafic sur le long terme ne réside pas dans la recherche d&amp;rsquo;un buzz temporaire ($V_0$), mais dans &lt;strong>la façon d&amp;rsquo;augmenter le terme constant $C$ (l&amp;rsquo;afflux continu provenant des moteurs de recherche)&lt;/strong>. En couvrant un grand nombre de « mots-clés de longue traîne » – comme des erreurs spécifiques et de niche ou des méthodes d&amp;rsquo;intégration entre des outils précis – qui ont un faible volume de recherche mais aucune concurrence, vous ferez croître la somme de $C$ pour en faire un volume colossal.&lt;/p>
&lt;hr>
&lt;h2 id="3-analyse-de-contenu-axée-sur-les-données-à-laide-de-lapi-google-search-console">3. Analyse de contenu axée sur les données à l&amp;rsquo;aide de l&amp;rsquo;API Google Search Console
&lt;/h2>&lt;p>Afin de construire une base de trafic stable $C$, il est nécessaire d&amp;rsquo;utiliser les données de la Google Search Console (GSC) et d&amp;rsquo;analyser objectivement « comment vous êtes évalué par Google ». Cependant, cliquer manuellement sur l&amp;rsquo;interface web de GSC a ses limites. En tant qu&amp;rsquo;ingénieur, automatisez l&amp;rsquo;analyse à l&amp;rsquo;aide de l&amp;rsquo;API GSC et de Python.&lt;/p>
&lt;h3 id="31-approche-dautomatisation-avec-lapi-gsc-et-python">3.1 Approche d&amp;rsquo;automatisation avec l&amp;rsquo;API GSC et Python
&lt;/h3>&lt;p>Nous allons créer un script qui détecte automatiquement la manière dont le classement de recherche d&amp;rsquo;un article spécifique baisse avec le temps (Decaying Content), ou les « articles gaspillés » qui ont un nombre élevé d&amp;rsquo;impressions mais un taux de clics (CTR) anormalement bas.
Pour cela, nous utiliserons &lt;code>google-api-python-client&lt;/code> et &lt;code>pandas&lt;/code>.&lt;/p>
&lt;h3 id="32-implémentation-en-python--extraction-automatique-des-contenus-à-faible-ctr">3.2 Implémentation en Python : Extraction automatique des contenus à faible CTR
&lt;/h3>&lt;p>Voici un exemple de script qui récupère les données de performance de recherche des 30 derniers jours via l&amp;rsquo;API, et extrait les « mots-clés et URL d&amp;rsquo;articles ayant une grande marge d&amp;rsquo;amélioration pour le titre ou la description », c&amp;rsquo;est-à-dire ceux dont le nombre d&amp;rsquo;impressions est supérieur ou égal à 1000 et le CTR inférieur ou égal à 2 %.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;span class="lnt">40
&lt;/span>&lt;span class="lnt">41
&lt;/span>&lt;span class="lnt">42
&lt;/span>&lt;span class="lnt">43
&lt;/span>&lt;span class="lnt">44
&lt;/span>&lt;span class="lnt">45
&lt;/span>&lt;span class="lnt">46
&lt;/span>&lt;span class="lnt">47
&lt;/span>&lt;span class="lnt">48
&lt;/span>&lt;span class="lnt">49
&lt;/span>&lt;span class="lnt">50
&lt;/span>&lt;span class="lnt">51
&lt;/span>&lt;span class="lnt">52
&lt;/span>&lt;span class="lnt">53
&lt;/span>&lt;span class="lnt">54
&lt;/span>&lt;span class="lnt">55
&lt;/span>&lt;span class="lnt">56
&lt;/span>&lt;span class="lnt">57
&lt;/span>&lt;span class="lnt">58
&lt;/span>&lt;span class="lnt">59
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">pandas&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="nn">pd&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">google.oauth2&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">service_account&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">googleapiclient.discovery&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">build&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">datetime&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 1. Authentification et construction du service API&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">KEY_FILE_LOCATION&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s1">&amp;#39;path/to/your-service-account-key.json&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">SCOPES&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;https://www.googleapis.com/auth/webmasters.readonly&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">SITE_URL&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s1">&amp;#39;https://your-tech-blog.com/&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">credentials&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">service_account&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">Credentials&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">from_service_account_file&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">KEY_FILE_LOCATION&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">scopes&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">SCOPES&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">webmasters_service&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">build&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;searchconsole&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;v1&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">credentials&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">credentials&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 2. Calcul de la période de requête (30 derniers jours)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">today&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">datetime&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">date&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">today&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">end_date&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">today&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">datetime&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">timedelta&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">days&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">))&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">strftime&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;%Y-%m-&lt;/span>&lt;span class="si">%d&lt;/span>&lt;span class="s1">&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">start_date&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">today&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">datetime&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">timedelta&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">days&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">32&lt;/span>&lt;span class="p">))&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">strftime&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;%Y-%m-&lt;/span>&lt;span class="si">%d&lt;/span>&lt;span class="s1">&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 3. Exécution de la requête API&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">request&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;startDate&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">start_date&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;endDate&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">end_date&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;dimensions&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;query&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;page&amp;#39;&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;rowLimit&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">5000&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">response&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">webmasters_service&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">searchanalytics&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">query&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">siteUrl&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">SITE_URL&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">body&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">request&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">execute&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 4. Traitement des données et filtrage avec Pandas DataFrame&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="s1">&amp;#39;rows&amp;#39;&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">response&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">rows&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">response&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;rows&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">data&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">row&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">rows&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">data&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">append&lt;/span>&lt;span class="p">({&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;Query&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">row&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;keys&amp;#39;&lt;/span>&lt;span class="p">][&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;URL&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">row&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;keys&amp;#39;&lt;/span>&lt;span class="p">][&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;Clicks&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">row&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;clicks&amp;#39;&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;Impressions&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">row&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;impressions&amp;#39;&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;CTR&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">row&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;ctr&amp;#39;&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;Position&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">row&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;position&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">})&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">df&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">pd&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">DataFrame&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Conditions de filtrage : Impressions &amp;gt;= 1000 &amp;amp; CTR &amp;lt; 2%&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">target_df&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">df&lt;/span>&lt;span class="p">[(&lt;/span>&lt;span class="n">df&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;Impressions&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">&amp;gt;=&lt;/span> &lt;span class="mi">1000&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">&amp;amp;&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">df&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;CTR&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="mf">0.02&lt;/span>&lt;span class="p">)]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Tri croissant par position (priorité aux classements élevés non cliqués)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">target_df&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">target_df&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">sort_values&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">by&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;Position&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">ascending&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;【Liste des recommandations pour améliorer les titres/méta-descriptions】&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">target_df&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">head&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">10&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Export CSV si nécessaire&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># target_df.to_csv(&amp;#39;improve_candidates.csv&amp;#39;, index=False)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">else&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Aucune donnée trouvée.&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>En exécutant ce script via des tâches planifiées avec cron ou GitHub Actions, vous pouvez toujours décider de manière axée sur les données « quels titres d&amp;rsquo;articles doivent être réécrits ». Au lieu de se fier à l&amp;rsquo;intuition, une amélioration continue basée sur les données (une sorte de Continuous Content Improvement plutôt que CI/CD) est primordiale.&lt;/p>
&lt;hr>
&lt;h2 id="4-gestion-du-cycle-de-vie-des-articles-et-stratégie-de-réécriture">4. Gestion du cycle de vie des articles et stratégie de réécriture
&lt;/h2>&lt;p>Un article technique ne s&amp;rsquo;arrête pas à sa publication. Avec l&amp;rsquo;évolution des technologies (mise à jour de frameworks, dépréciation d&amp;rsquo;API, etc.), le contenu devient obsolète en un clin d&amp;rsquo;œil. Continuer à fournir des informations obsolètes nuit non seulement à la crédibilité du blog, mais entraîne également une évaluation négative en termes de SEO.&lt;/p>
&lt;h3 id="41-gestion-du-cycle-de-vie-du-contenu-diagramme-de-gantt">4.1 Gestion du cycle de vie du contenu (Diagramme de Gantt)
&lt;/h3>&lt;p>Nous illustrons le cycle de vie idéal pour la gestion du contenu avec un diagramme de Gantt Mermaid.&lt;/p>
&lt;pre class="mermaid">
gantt
title Gestion du cycle de vie du contenu axée sur les données
dateFormat YYYY-MM-DD
axisFormat %m/%d
section &amp;#34;Phase 1 : Planification et Rédaction&amp;#34;
&amp;#34;Analyse des mots-clés et des tendances de recherche&amp;#34; :a1, 2026-09-01, 3d
&amp;#34;Brouillon et validation du code&amp;#34; :a2, after a1, 5d
&amp;#34;Relecture et correction&amp;#34; :a3, after a2, 2d
section &amp;#34;Phase 2 : Publication et Promotion&amp;#34;
&amp;#34;Déploiement via pipeline CI/CD&amp;#34; :p1, 2026-09-11, 1d
&amp;#34;Distribution automatique sur réseaux sociaux (X, LinkedIn, RSS)&amp;#34; :p2, 2026-09-11, 1d
&amp;#34;Propagation vers des services comme Hatena Bookmark&amp;#34; :p3, after p2, 3d
section &amp;#34;Phase 3 : Observation et Analyse&amp;#34;
&amp;#34;Période d&amp;#39;accumulation de données GSC&amp;#34; :m1, 2026-09-14, 28d
&amp;#34;Évaluation des performances via API Python&amp;#34; :m2, after m1, 2d
section &amp;#34;Phase 4 : Amélioration (Réécriture)&amp;#34;
&amp;#34;Correction des titres des articles à faible CTR&amp;#34; :r1, after m2, 3d
&amp;#34;Mise à jour du code vers la dernière version&amp;#34; :r2, after r1, 4d
&lt;/pre>
&lt;p>Ainsi, traiter la création d&amp;rsquo;articles comme un projet de développement logiciel à part entière, et intégrer la phase d&amp;rsquo;exploitation et de maintenance (réécriture) post-publication dans votre planification est le secret pour maintenir et augmenter le trafic.&lt;/p>
&lt;h3 id="42-modèle-mathématique-du-roi-retour-sur-investissement-de-la-création-de-contenu">4.2 Modèle mathématique du ROI (retour sur investissement) de la création de contenu
&lt;/h3>&lt;p>Puisque les ingénieurs consacrent un temps précieux à rédiger des articles, ils doivent être conscients du retour sur investissement (ROI).
Le ROI d&amp;rsquo;un blog peut être formulé de la manière suivante :&lt;/p>
$$ ROI = \frac{\sum_{t=1}^{T} \left( Rev_{ad}(t) + Val_{brand}(t) + Val_{skill}(t) \right) - Cost_{time}}{\text{Cost}_{time}} \times 100 \ (\%) $$&lt;ul>
&lt;li>$T$ : Durée de vie utile de l&amp;rsquo;article (période avant qu&amp;rsquo;il ne devienne obsolète)&lt;/li>
&lt;li>$Rev_{ad}(t)$ : Revenus directs issus de la publicité, de l&amp;rsquo;affiliation ou du sponsoring&lt;/li>
&lt;li>$Val_{brand}(t)$ : Valeur monétaire équivalente de l&amp;rsquo;impact positif sur la carrière en mettant en avant vos compétences techniques (augmentation des offres salariales lors d&amp;rsquo;un changement d&amp;rsquo;emploi, demandes d&amp;rsquo;intervention, etc.)&lt;/li>
&lt;li>$Val_{skill}(t)$ : Valeur de l&amp;rsquo;amélioration de vos propres compétences grâce à l&amp;rsquo;apprentissage et à la recherche effectués pour rédiger l&amp;rsquo;article&lt;/li>
&lt;li>$Cost_{time}$ : Temps consacré à la rédaction de l&amp;rsquo;article, à la création des schémas et à la validation du code (converti à votre taux horaire)&lt;/li>
&lt;/ul>
&lt;p>Le point fort d&amp;rsquo;un blog technique est que même si $Rev_{ad}$ est faible, $Val_{brand}$ et $Val_{skill}$ ont tendance à être extrêmement élevés. En particulier, une explication technique de haute qualité devient directement un portfolio, ce qui s&amp;rsquo;avère redoutablement efficace lors de la recherche d&amp;rsquo;emploi ou de l&amp;rsquo;acquisition de missions en freelance.&lt;/p>
&lt;hr>
&lt;h2 id="5-distribution-via-github-actions-et-lintégration-doutils-dautomatisation-externes">5. Distribution via GitHub Actions et l&amp;rsquo;intégration d&amp;rsquo;outils d&amp;rsquo;automatisation externes
&lt;/h2>&lt;p>Après avoir créé du contenu, le défi est de savoir comment le diffuser efficacement à votre public cible (distribution). Publier manuellement des liens sur chaque réseau social à chaque fois est inefficace et indigne d&amp;rsquo;un ingénieur.&lt;/p>
&lt;h3 id="51-architecture-dautomatisation-du-partage-sur-les-réseaux-sociaux">5.1 Architecture d&amp;rsquo;automatisation du partage sur les réseaux sociaux
&lt;/h3>&lt;p>Nous allons mettre en place une architecture qui automatise l&amp;rsquo;intégralité du processus, de la compilation au déploiement, en passant par la notification sur de multiples plateformes, dès l&amp;rsquo;instant où un fichier Markdown est fusionné dans la branche principale (main) du dépôt GitHub.&lt;/p>
&lt;pre class="mermaid">
flowchart TD
A[&amp;#34;Développeur (Git Push)&amp;#34;] --&amp;gt; B[&amp;#34;Dépôt GitHub&amp;#34;]
B --&amp;gt;|Webhook| C[&amp;#34;GitHub Actions (CI/CD)&amp;#34;]
C --&amp;gt;|Build| D[&amp;#34;Générateur de site statique (Hugo/Gatsby)&amp;#34;]
D --&amp;gt;|Déployer| E[&amp;#34;Hébergement (Vercel / Cloudflare Pages)&amp;#34;]
D --&amp;gt;|Générer| F[&amp;#34;Flux RSS (index.xml)&amp;#34;]
F --&amp;gt;|Interrogé par| G[&amp;#34;Zapier / IFTTT / Make&amp;#34;]
G --&amp;gt;|Appel API| H[&amp;#34;Publication auto sur X (Twitter)&amp;#34;]
G --&amp;gt;|Appel API| I[&amp;#34;Publication d&amp;#39;article LinkedIn&amp;#34;]
G --&amp;gt;|Appel API| J[&amp;#34;Webhook de communauté Discord / Slack&amp;#34;]
C --&amp;gt;|Script Actions| K[&amp;#34;API de publication croisée Qiita / Zenn&amp;#34;]
&lt;/pre>
&lt;h3 id="52-points-clés-pour-la-mise-en-place-dun-pipeline-automatisé">5.2 Points clés pour la mise en place d&amp;rsquo;un pipeline automatisé
&lt;/h3>&lt;ol>
&lt;li>
&lt;p>&lt;strong>Compilation et déploiement via GitHub Actions&lt;/strong>
Si vous utilisez un générateur de site statique, automatisez la génération HTML et le déploiement vers votre hébergeur (Vercel, Netlify, Cloudflare Pages, etc.) à l&amp;rsquo;aide de GitHub Actions. À cette occasion, pour répondre aux exigences des Signaux Web Essentiels mentionnées précédemment, il est également efficace d&amp;rsquo;intégrer un processus d&amp;rsquo;optimisation des images (comme la conversion automatique en WebP) dans le pipeline de compilation.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Intégration des réseaux sociaux déclenchée par RSS via Zapier/IFTTT&lt;/strong>
Le générateur de site produit un flux RSS (XML) à jour lors de la compilation. En important cela dans une iPaaS telle que Zapier ou Make (anciennement Integromat), vous pouvez construire un workflow tel que : « Dès qu&amp;rsquo;un nouvel élément est ajouté au RSS, publier le titre et l&amp;rsquo;URL sur X (Twitter) et LinkedIn ». Cela permet de notifier automatiquement vos abonnés à l&amp;rsquo;instant même où l&amp;rsquo;article est publié.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Publication croisée sur Qiita/Zenn (Utilisation de balises canoniques)&lt;/strong>
Tant que l&amp;rsquo;autorité de domaine de votre blog personnel ou d&amp;rsquo;entreprise est faible, il peut être judicieux de tirer parti de la force d&amp;rsquo;attraction de plateformes techniques comme Qiita ou Zenn. Cependant, un simple copier-coller présente le risque de subir des pénalités SEO pour contenu dupliqué.
Ce problème peut être résolu en définissant la &lt;strong>balise Canonical&lt;/strong> dans les métadonnées des articles sur Qiita ou Zenn, en pointant vers l&amp;rsquo;URL de l&amp;rsquo;article original sur votre propre blog. En appelant les API des différentes plateformes depuis GitHub Actions et en écrivant un script pour générer automatiquement l&amp;rsquo;article à partir de votre fichier Markdown, vous pouvez automatiser entièrement la diffusion multicanale.&lt;/p>
&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="conclusion--faire-tourner-le-cycle-de-lamélioration-continue">Conclusion : Faire tourner le cycle de l&amp;rsquo;amélioration continue
&lt;/h2>&lt;p>Pour augmenter drastiquement le trafic mensuel d&amp;rsquo;un blog technique, au-delà de l&amp;rsquo;acte d&amp;rsquo;« écrire », les approches d&amp;rsquo;ingénierie telles que celles présentées ici sont indispensables.&lt;/p>
&lt;ol>
&lt;li>Construction d&amp;rsquo;une architecture de site et d&amp;rsquo;un HTML robustes axés sur le SEO&lt;/li>
&lt;li>Conception d&amp;rsquo;articles prenant en compte l&amp;rsquo;intention de recherche de l&amp;rsquo;utilisateur (résolution d&amp;rsquo;erreur vs apprentissage systématique)&lt;/li>
&lt;li>Analyse de données à l&amp;rsquo;aide de l&amp;rsquo;API Google Search Console et de Python&lt;/li>
&lt;li>Gestion du cycle de vie du contenu et réécriture en tenant compte du ROI&lt;/li>
&lt;li>Automatisation complète de la distribution via le CI/CD et l&amp;rsquo;intégration de Zapier&lt;/li>
&lt;/ol>
&lt;p>Si vous parvenez à assembler ces éléments en un système, votre blog technique deviendra l&amp;rsquo;actif (asset) le plus puissant pour propulser votre propre carrière. Ingénieurs souffrant d&amp;rsquo;une stagnation de trafic, n&amp;rsquo;hésitez pas à commencer le « Growth Hacking de votre blog » dès aujourd&amp;rsquo;hui. Vos compétences en programmation et votre capacité de conception d&amp;rsquo;architecture, cultivées lors de vos activités de développement, seront assurément vos meilleures armes dans la gestion de votre blog.&lt;/p></description></item><item><title>Comment héberger un blog Hugo gratuitement et à une vitesse fulgurante sur Cloudflare Pages ou GitHub Pages</title><link>http://kenji.blog/fr/p/hugo-hosting-cloudflare-vs-github-pages/</link><pubDate>Sat, 12 Sep 2026 12:00:00 +0900</pubDate><guid>http://kenji.blog/fr/p/hugo-hosting-cloudflare-vs-github-pages/</guid><description>&lt;img src="http://kenji.blog/p/hugo-hosting-cloudflare-vs-github-pages/img/eyecatch.jpg" alt="Featured image of post Comment héberger un blog Hugo gratuitement et à une vitesse fulgurante sur Cloudflare Pages ou GitHub Pages" />&lt;p>Lors de la gestion d&amp;rsquo;un site web ou d&amp;rsquo;un blog, la vitesse d&amp;rsquo;affichage (performances), les coûts d&amp;rsquo;exploitation et la sécurité sont des éléments cruciaux. Autrefois, la combinaison d&amp;rsquo;un CMS dynamique (comme WordPress) et d&amp;rsquo;un serveur d&amp;rsquo;hébergement partagé était la norme, mais aujourd&amp;rsquo;hui, l&amp;rsquo;architecture appelée &amp;ldquo;Jamstack&amp;rdquo; attire beaucoup l&amp;rsquo;attention. Parmi ses solutions, l&amp;rsquo;association de &amp;ldquo;Hugo&amp;rdquo;, un générateur de sites statiques (SSG) ultra-rapide écrit en langage Go, avec des services d&amp;rsquo;hébergement modernes comme Cloudflare Pages ou GitHub Pages, permet de construire un environnement de blog &lt;strong>totalement gratuit et extrêmement rapide&lt;/strong>.&lt;/p>
&lt;p>Dans cet article, nous plongerons profondément dans les détails techniques : les étapes concrètes pour publier un site statique utilisant Hugo sur Cloudflare Pages ou GitHub Pages, les différences d&amp;rsquo;architecture entre ces plateformes, la mise en place d&amp;rsquo;une CI/CD (Intégration Continue / Déploiement Continu) avec GitHub Actions, l&amp;rsquo;optimisation des DNS, les stratégies de cache, et enfin l&amp;rsquo;intégration d&amp;rsquo;une analyse d&amp;rsquo;audience respectueuse de la vie privée.&lt;/p>
&lt;hr>
&lt;h2 id="1-les-bases-des-générateurs-de-sites-statiques-ssg-et-de-jamstack">1. Les bases des générateurs de sites statiques (SSG) et de Jamstack
&lt;/h2>&lt;h3 id="11-pourquoi-un-site-statique-">1.1 Pourquoi un site statique ?
&lt;/h3>&lt;p>Les CMS dynamiques traditionnels (par exemple WordPress) exécutent des requêtes vers une base de données (comme MySQL) à chaque demande d&amp;rsquo;un utilisateur, et génèrent dynamiquement du HTML côté serveur (avec PHP, par exemple) pour le renvoyer. Bien que cette approche offre une grande flexibilité, elle a une faible résistance aux pics de trafic (les &amp;ldquo;buzz&amp;rdquo; ou les attaques DDoS) et a tendance à complexifier l&amp;rsquo;infrastructure, nécessitant souvent le placement d&amp;rsquo;un serveur de cache (Redis ou Varnish) en amont.&lt;/p>
&lt;p>D&amp;rsquo;un autre côté, avec un générateur de sites statiques (SSG) adoptant l&amp;rsquo;architecture Jamstack (JavaScript, APIs, and Markup), tous les fichiers HTML, CSS et JavaScript sont générés à l&amp;rsquo;avance (lors de la phase de build). Lorsqu&amp;rsquo;un utilisateur effectue une requête, le serveur web (ou le CDN) se contente de renvoyer les fichiers statiques déjà générés. Cela permet d&amp;rsquo;obtenir une vitesse fulgurante et une sécurité très robuste.&lt;/p>
&lt;h3 id="12-lavantage-de-hugo">1.2 L&amp;rsquo;avantage de Hugo
&lt;/h3>&lt;p>Il existe de nombreuses options pour les SSG telles que Next.js, Gatsby, Jekyll ou Astro, mais la plus grande caractéristique de Hugo est sa &lt;strong>vitesse de compilation (build)&lt;/strong>. Bénéficiant du traitement asynchrone et concurrentiel du langage Go, il peut compiler un site de plusieurs milliers ou dizaines de milliers de pages en quelques secondes seulement. Cela réduit considérablement le temps d&amp;rsquo;attente dans les pipelines CI/CD, ce qui se traduit directement par une amélioration de l&amp;rsquo;expérience développeur (DX : Developer Experience).&lt;/p>
&lt;hr>
&lt;h2 id="2-comparaison-des-architectures-des-services-dhébergement">2. Comparaison des architectures des services d&amp;rsquo;hébergement
&lt;/h2>&lt;p>Le prochain défi consiste à déterminer où héberger les fichiers statiques générés par Hugo. Les choix typiques incluent Cloudflare Pages, GitHub Pages et Netlify, mais chacun d&amp;rsquo;entre eux possède une architecture réseau sous-jacente différente.&lt;/p>
&lt;h3 id="21-cdn-et-edge-computing">2.1 CDN et Edge Computing
&lt;/h3>&lt;p>Toutes ces plateformes distribuent le contenu en utilisant des CDN (Content Delivery Network) répartis mondialement. Cependant, leur facteur de différenciation réside dans leur capacité, au-delà de la simple mise en cache de fichiers statiques, à utiliser &amp;ldquo;l&amp;rsquo;informatique en périphérie&amp;rdquo; (edge computing) pour effectuer le routage des requêtes ou la réécriture des en-têtes directement depuis le PoP (Point of Presence) le plus proche de l&amp;rsquo;utilisateur.&lt;/p>
&lt;pre class="mermaid">
graph TD
A[&amp;#34;Utilisateur (Tokyo)&amp;#34;] --&amp;gt;|Faible latence| B[&amp;#34;Nœud Edge (NRT)&amp;#34;]
C[&amp;#34;Utilisateur (New York)&amp;#34;] --&amp;gt;|Faible latence| D[&amp;#34;Nœud Edge (EWR)&amp;#34;]
E[&amp;#34;Utilisateur (Londres)&amp;#34;] --&amp;gt;|Faible latence| F[&amp;#34;Nœud Edge (LHR)&amp;#34;]
B --&amp;gt; G[&amp;#34;Stockage d&amp;#39;origine / Object Store&amp;#34;]
D --&amp;gt; G
F --&amp;gt; G
&lt;/pre>
&lt;h3 id="22-github-pages">2.2 GitHub Pages
&lt;/h3>&lt;p>GitHub Pages est un service qui permet de publier des fichiers HTML, CSS et JavaScript directement depuis un dépôt GitHub. En arrière-plan, il utilise des CDN comme Fastly et offre des performances tout à fait satisfaisantes. Toutefois, ses fonctionnalités en tant qu&amp;rsquo;infrastructure pure sont un peu modestes : il existe des restrictions sur la personnalisation des en-têtes (par exemple, la configuration de &lt;code>Cache-Control&lt;/code> ou des en-têtes de sécurité) et la configuration des redirections dépend des meta refresh HTML ou des plugins Jekyll.&lt;/p>
&lt;h3 id="23-cloudflare-pages">2.3 Cloudflare Pages
&lt;/h3>&lt;p>Cloudflare Pages est un service d&amp;rsquo;hébergement de sites statiques construit sur le plus grand réseau Anycast au monde dont Cloudflare est fier (déployé dans plus de 275 villes).
Il offre d&amp;rsquo;immenses possibilités d&amp;rsquo;optimisation des performances, telles que la prise en charge standard de HTTP/3 (QUIC), l&amp;rsquo;optimisation des images et l&amp;rsquo;intégration de fonctions en périphérie (Cloudflare Workers). De plus, il n&amp;rsquo;y a pas de facturation pour la bande passante, ce qui permet de l&amp;rsquo;utiliser gratuitement même en cas d&amp;rsquo;augmentation fulgurante du trafic.&lt;/p>
&lt;h3 id="24-netlify">2.4 Netlify
&lt;/h3>&lt;p>Netlify est un pionnier de la Jamstack et offre une expérience développeur (DX) tout-en-un intégrant des fonctionnalités de formulaire, d&amp;rsquo;authentification (Identity), de fonctions serverless, etc. Cependant, si vous dépassez la bande passante gratuite (100 Go par mois), des frais de paiement à l&amp;rsquo;usage élevés sont appliqués. Par conséquent, il est nécessaire de faire attention à la gestion des coûts pour les blogs qui utilisent beaucoup d&amp;rsquo;images ou de vidéos.&lt;/p>
&lt;hr>
&lt;h2 id="3-calcul-théorique-des-performances-et-de-la-latence-modèle-mathématique-avec-latex">3. Calcul théorique des performances et de la latence (Modèle mathématique avec LaTeX)
&lt;/h2>&lt;p>Lors de l&amp;rsquo;évaluation des performances web, la réduction de la latence est l&amp;rsquo;indicateur le plus important. Modélisons à quel point la latence est réduite en utilisant un CDN (Edge) par rapport à un accès direct au serveur d&amp;rsquo;origine.&lt;/p>
&lt;p>Soit $C$ le taux de réussite du cache (Cache Hit Ratio), c&amp;rsquo;est-à-dire la probabilité que la requête de l&amp;rsquo;utilisateur accède au cache. On a $0 \le C \le 1$.
Soit $L_{origin}$ la latence vers le serveur d&amp;rsquo;origine, et $L_{edge}$ la latence vers le nœud Edge le plus proche.&lt;/p>
&lt;p>La nouvelle latence moyenne $L_{new}$ se calcule avec l&amp;rsquo;espérance mathématique suivante :&lt;/p>
$$ L_{new} = C \times L_{edge} + (1 - C) \times (L_{edge} + L_{origin}) $$&lt;p>En simplifiant cette équation, nous obtenons :&lt;/p>
$$ L_{new} = L_{edge} + (1 - C) \times L_{origin} $$&lt;p>Par exemple, si un utilisateur à Tokyo accède à un serveur d&amp;rsquo;origine situé sur la côte est des États-Unis (New York), en tenant compte de la distance physique de la fibre optique et du délai de traitement par les routeurs, $L_{origin}$ sera d&amp;rsquo;environ 200 ms. En revanche, si on utilise un CDN comme Cloudflare, l&amp;rsquo;utilisateur peut se connecter à un nœud Edge à Tokyo, ce qui réduit $L_{edge}$ à environ 10 ms.&lt;/p>
&lt;p>Si le taux de réussite du cache est de $C = 0.95$ (95 %),&lt;/p>
$$ L_{new} = 10 + (1 - 0.95) \times 200 = 10 + 0.05 \times 200 = 10 + 10 = 20 \text{ ms} $$&lt;p>Ainsi, l&amp;rsquo;introduction d&amp;rsquo;un CDN permet de réduire de façon spectaculaire (d&amp;rsquo;environ 90 %) la latence moyenne, qui passe de 210 ms à 20 ms.&lt;/p>
&lt;hr>
&lt;h2 id="4-mise-en-place-dun-pipeline-cicd-avec-github-actions">4. Mise en place d&amp;rsquo;un pipeline CI/CD avec GitHub Actions
&lt;/h2>&lt;p>Pour automatiser le processus de mise à jour de notre blog Hugo, nous allons configurer un pipeline CI/CD utilisant GitHub Actions. De cette façon, il suffira de rédiger un article en Markdown localement et de faire un &lt;code>git push&lt;/code> pour lancer automatiquement le build et le déployer sur Cloudflare Pages ou GitHub Pages.&lt;/p>
&lt;p>Le diagramme de séquence ci-dessous illustre le flux global depuis le Push d&amp;rsquo;un article jusqu&amp;rsquo;à sa distribution à l&amp;rsquo;utilisateur.&lt;/p>
&lt;pre class="mermaid">
sequenceDiagram
participant U as &amp;#34;Utilisateur (Auteur)&amp;#34;
participant G as &amp;#34;Dépôt GitHub&amp;#34;
participant A as &amp;#34;GitHub Actions&amp;#34;
participant C as &amp;#34;Cloudflare Pages&amp;#34;
participant V as &amp;#34;Visiteur&amp;#34;
U-&amp;gt;&amp;gt;G: &amp;#34;git push origin main&amp;#34;
G-&amp;gt;&amp;gt;A: &amp;#34;Déclenche l&amp;#39;événement Push&amp;#34;
A-&amp;gt;&amp;gt;A: &amp;#34;Checkout &amp;amp; Setup Hugo&amp;#34;
A-&amp;gt;&amp;gt;A: &amp;#34;hugo --minify (Build)&amp;#34;
A-&amp;gt;&amp;gt;C: &amp;#34;Déploiement vers Cloudflare Pages (Direct Upload)&amp;#34;
C--&amp;gt;&amp;gt;A: &amp;#34;URL de déploiement (Succès)&amp;#34;
V-&amp;gt;&amp;gt;C: &amp;#34;Requête pour la page web&amp;#34;
C--&amp;gt;&amp;gt;V: &amp;#34;Renvoie le HTML mis en cache (Edge)&amp;#34;
&lt;/pre>
&lt;h3 id="41-configuration-du-déploiement-pour-cloudflare-pages-direct-upload">4.1 Configuration du déploiement pour Cloudflare Pages (Direct Upload)
&lt;/h3>&lt;p>Avec Cloudflare Pages, il existe deux méthodes : lier un dépôt GitHub pour effectuer le build sur l&amp;rsquo;infrastructure de Cloudflare, ou utiliser « Direct Upload » pour transférer directement les fichiers statiques générés par GitHub Actions. Si vous souhaitez gérer plus strictement la version de Hugo et la combiner avec d&amp;rsquo;autres tâches (comme les tests ou l&amp;rsquo;optimisation des images), il est recommandé de compiler sur GitHub Actions et d&amp;rsquo;utiliser la méthode Direct Upload.&lt;/p>
&lt;p>Voici un exemple pratique de fichier &lt;code>.github/workflows/deploy.yml&lt;/code> pour un déploiement vers Cloudflare Pages.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;Deploy Hugo site to Cloudflare Pages&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">on&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">push&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">branches&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="s2">&amp;#34;main&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">workflow_dispatch&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">jobs&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">build-and-deploy&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">runs-on&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;ubuntu-latest&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">steps&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;Checkout repository&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">uses&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;actions/checkout@v4&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">with&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">submodules&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;recursive&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">fetch-depth&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">0&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;Setup Hugo&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">uses&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;peaceiris/actions-hugo@v3&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">with&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">hugo-version&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;0.125.0&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">extended&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kc">true&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;Build Hugo Site&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">run&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;hugo --minify --gc&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">env&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">HUGO_ENVIRONMENT&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;production&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;Deploy to Cloudflare Pages&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">uses&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;cloudflare/pages-action@v1&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">with&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">apiToken&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">${{ secrets.CLOUDFLARE_API_TOKEN }}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">accountId&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">${{ secrets.CLOUDFLARE_ACCOUNT_ID }}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">projectName&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;your-project-name&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">directory&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;public&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">gitHubToken&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">${{ secrets.GITHUB_TOKEN }}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">branch&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;main&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Dans ce pipeline, l&amp;rsquo;option &lt;code>--minify&lt;/code> est utilisée pour minifier le HTML/CSS/JS, et &lt;code>--gc&lt;/code> est utilisé pour supprimer les fichiers inutiles. Ce sont les bases de l&amp;rsquo;optimisation des performances.&lt;/p>
&lt;hr>
&lt;h2 id="5-examen-approfondi-de-la-configuration-dns--domaine-personnalisé-et-enregistrements-cname--alias">5. Examen approfondi de la configuration DNS : Domaine personnalisé et enregistrements CNAME / ALIAS
&lt;/h2>&lt;p>Lors de l&amp;rsquo;utilisation d&amp;rsquo;un domaine personnalisé (par exemple, &lt;code>kenji.blog&lt;/code>), une configuration appropriée du DNS (Domain Name System) est indispensable.&lt;/p>
&lt;h3 id="51-restrictions-des-enregistrements-cname-et-zone-apex">5.1 Restrictions des enregistrements CNAME et Zone Apex
&lt;/h3>&lt;p>Normalement, lorsque vous pointez un sous-domaine (par exemple &lt;code>www.kenji.blog&lt;/code>) vers un service externe, vous utilisez un enregistrement &lt;code>CNAME&lt;/code>. Cependant, selon les spécifications DNS (RFC 1034), il n&amp;rsquo;est pas possible de configurer un enregistrement &lt;code>CNAME&lt;/code> pour le domaine racine (également appelé Zone Apex ou domaine nu, par ex. &lt;code>kenji.blog&lt;/code>). La raison est que la Zone Apex doit contenir obligatoirement un enregistrement SOA (Start of Authority), un enregistrement NS (Name Server) ou un enregistrement MX (Mail Exchange), et la règle dicte que le CNAME ne peut pas coexister avec d&amp;rsquo;autres enregistrements de ressources.&lt;/p>
&lt;h3 id="52-solutions--alias--aname--cname-flattening">5.2 Solutions : ALIAS / ANAME / CNAME Flattening
&lt;/h3>&lt;p>Pour résoudre ce problème, les fournisseurs DNS modernes offrent leurs propres fonctionnalités étendues.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Enregistrement ALIAS / ANAME&lt;/strong> : Le serveur DNS effectue dynamiquement la résolution de nom et renvoie l&amp;rsquo;enregistrement A final (adresse IP) au client. Des services comme Amazon Route 53 le prennent en charge.&lt;/li>
&lt;li>&lt;strong>CNAME Flattening&lt;/strong> : C&amp;rsquo;est une fonctionnalité offerte par Cloudflare. Elle agit comme si vous aviez configuré un CNAME sur votre Zone Apex, mais le serveur DNS faisant autorité de Cloudflare renvoie de manière transparente au client les adresses IP résolues automatiquement (enregistrements A et AAAA).&lt;/li>
&lt;/ul>
&lt;p>Si vous utilisez Cloudflare Pages, déléguer les serveurs de noms de votre domaine à Cloudflare et exploiter ce &amp;ldquo;CNAME Flattening&amp;rdquo; sera la configuration la plus transparente et la plus performante.&lt;/p>
&lt;hr>
&lt;h2 id="6-stratégies-de-cache-et-contrôle-des-en-têtes-http">6. Stratégies de cache et contrôle des en-têtes HTTP
&lt;/h2>&lt;p>Une autre clé pour accélérer les sites statiques est la &amp;ldquo;stratégie de cache&amp;rdquo;. Avec Cloudflare Pages, vous pouvez utiliser un fichier généré (le fichier &lt;code>_headers&lt;/code>) pour contrôler en détail les en-têtes de réponse HTTP.&lt;/p>
&lt;h3 id="61-edge-cache-vs-cache-du-navigateur">6.1 Edge Cache vs Cache du navigateur
&lt;/h3>&lt;p>Il existe deux grands types de cache : le &amp;ldquo;Edge Cache&amp;rdquo;, conservé du côté du CDN, et le &amp;ldquo;Cache du navigateur&amp;rdquo; (Browser Cache), stocké dans le navigateur de l&amp;rsquo;utilisateur.&lt;/p>
&lt;p>Pour les fichiers statiques (images, CSS, JS, etc. dont le nom de fichier inclut un hachage), l&amp;rsquo;idéal est de les mettre en cache sur le navigateur pendant une longue période. En revanche, pour que les mises à jour des fichiers HTML soient reflétées immédiatement, il est courant de raccourcir (ou de désactiver) le cache du navigateur et de traiter la requête via l&amp;rsquo;Edge Cache.&lt;/p>
&lt;p>Exemple de configuration de &lt;code>_headers&lt;/code> dans Cloudflare Pages :&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;span class="lnt">8
&lt;/span>&lt;span class="lnt">9
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="cl"># Les fichiers HTML ne sont pas mis en cache par le navigateur et sont validés à chaque fois
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">/*.html
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> Cache-Control: public, max-age=0, must-revalidate
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"># Les fichiers d&amp;#39;assets (CSS/JS/images) sont mis en cache sur le navigateur pendant 1 an
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">/assets/*
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> Cache-Control: public, max-age=31536000, immutable
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">/img/*
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> Cache-Control: public, max-age=31536000, immutable
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="62-formule-de-calcul-pour-la-réduction-des-coûts-de-bande-passante">6.2 Formule de calcul pour la réduction des coûts de bande passante
&lt;/h3>&lt;p>La configuration d&amp;rsquo;en-têtes de cache appropriés permet de réduire considérablement la quantité de données transférées depuis le serveur (Edge). Le coût mensuel de la bande passante $Cost$ peut être modélisé avec la quantité de transfert de chaque ressource $B_i$, le taux de réussite du cache $C_i$, et le coût unitaire de la bande passante $R$ comme suit :&lt;/p>
$$ Cost = \sum_{i=1}^{n} \left( B_i \times (1 - C_i) \times R \right) $$&lt;p>Étant donné que le transfert de données sortant est gratuit sur Cloudflare ($R = 0$), le coût financier direct sera de $0$. Cependant, si vous utilisez en parallèle d&amp;rsquo;autres infrastructures comme GitHub Pages, ou si vous utilisez AWS S3 comme backend, maximiser ce taux de réussite de cache $C_i$ sera la clé pour réduire les coûts d&amp;rsquo;infrastructure.&lt;/p>
&lt;hr>
&lt;h2 id="7-analyses-daudience-combinant-confidentialité-et-performances">7. Analyses d&amp;rsquo;audience combinant confidentialité et performances
&lt;/h2>&lt;p>Lors de la gestion d&amp;rsquo;un blog, l&amp;rsquo;analyse d&amp;rsquo;audience (Web Analytics) est essentielle pour savoir combien d&amp;rsquo;utilisateurs le visitent. Pendant longtemps, Google Analytics (GA4) a été le standard de facto, mais face aux récentes tendances de protection de la vie privée (RGPD, CCPA) et à la suppression progressive des cookies tiers, la situation évolue.&lt;/p>
&lt;h3 id="71-impact-sur-les-performances-web">7.1 Impact sur les performances web
&lt;/h3>&lt;p>L&amp;rsquo;intégration de Google Analytics (plus particulièrement &lt;code>gtag.js&lt;/code> ou Google Tag Manager) entraîne le chargement et l&amp;rsquo;exécution de nombreux scripts externes, ce qui a un impact négatif sur les performances (surtout sur le TTFB et le temps de blocage du thread principal).&lt;/p>
&lt;p>Prenons le temps de décomposer le temps de chargement d&amp;rsquo;un site de la façon suivante :&lt;/p>
&lt;pre class="mermaid">
pie title Répartition typique des temps de chargement d&amp;#39;un site
&amp;#34;TTFB (Time to First Byte)&amp;#34; : 15
&amp;#34;Téléchargement du contenu (HTML/CSS)&amp;#34; : 20
&amp;#34;Analyse du DOM et Rendu&amp;#34; : 45
&amp;#34;Analytique &amp;amp; JS Tiers&amp;#34; : 20
&lt;/pre>
&lt;p>Il n&amp;rsquo;est pas rare que les outils d&amp;rsquo;analyse JS tiers représentent environ 20 % à 30 % du temps de chargement global.&lt;/p>
&lt;h3 id="72-mise-en-place-de-cloudflare-web-analytics">7.2 Mise en place de Cloudflare Web Analytics
&lt;/h3>&lt;p>C&amp;rsquo;est pourquoi les solutions d&amp;rsquo;analyse &amp;ldquo;privacy-first&amp;rdquo; qui n&amp;rsquo;utilisent pas de cookies (cookieless), comme Cloudflare Web Analytics ou Plausible Analytics, attirent l&amp;rsquo;attention.&lt;/p>
&lt;p>Cloudflare Web Analytics fonctionne simplement en intégrant un extrait de JavaScript très léger. Il n&amp;rsquo;émet pas de cookies, vous n&amp;rsquo;avez donc pas besoin d&amp;rsquo;installer une bannière de consentement aux cookies contraignante.&lt;/p>
&lt;p>Son implémentation dans Hugo est également très simple. Il vous suffit d&amp;rsquo;ajouter l&amp;rsquo;extrait de code fourni dans &lt;code>layouts/partials/head.html&lt;/code> ou &lt;code>layouts/partials/analytics.html&lt;/code>.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-html" data-lang="html">&lt;span class="line">&lt;span class="cl">{{ if eq hugo.Environment &amp;#34;production&amp;#34; }}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&amp;lt;!-- Cloudflare Web Analytics --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">script&lt;/span> &lt;span class="na">defer&lt;/span> &lt;span class="na">src&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#39;https://static.cloudflareinsights.com/beacon.min.js&amp;#39;&lt;/span> &lt;span class="na">data-cf-beacon&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#39;{&amp;#34;token&amp;#34;: &amp;#34;YOUR_CLOUDFLARE_BEACON_TOKEN&amp;#34;}&amp;#39;&lt;/span>&lt;span class="p">&amp;gt;&amp;lt;/&lt;/span>&lt;span class="nt">script&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&amp;lt;!-- End Cloudflare Web Analytics --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">{{ end }}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>L&amp;rsquo;ajout de l&amp;rsquo;attribut &lt;code>defer&lt;/code> permet de charger le script de manière asynchrone sans bloquer l&amp;rsquo;analyse du document HTML, et de l&amp;rsquo;exécuter après la construction du DOM. Cela permet de minimiser l&amp;rsquo;impact sur la vitesse d&amp;rsquo;affichage initiale (LCP : Largest Contentful Paint et FCP : First Contentful Paint).&lt;/p>
&lt;hr>
&lt;h2 id="8-conclusion-et-bonnes-pratiques">8. Conclusion et bonnes pratiques
&lt;/h2>&lt;p>Dans le cadre de l&amp;rsquo;exploitation d&amp;rsquo;un site statique utilisant Hugo, l&amp;rsquo;adoption de plateformes d&amp;rsquo;hébergement modernes telles que Cloudflare Pages ou GitHub Pages offre d&amp;rsquo;énormes avantages en termes de rapport coût-performance, de vitesse d&amp;rsquo;affichage et de sécurité.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Build ultra-rapide&lt;/strong> : Tirer parti de la rapidité de Hugo pour minimiser le temps d&amp;rsquo;exécution des pipelines CI/CD (GitHub Actions).&lt;/li>
&lt;li>&lt;strong>Distribution via l&amp;rsquo;Edge&lt;/strong> : Utiliser le réseau Edge de Cloudflare pour distribuer le contenu aux utilisateurs du monde entier avec une latence de l&amp;rsquo;ordre de la milliseconde.&lt;/li>
&lt;li>&lt;strong>Configuration DNS appropriée&lt;/strong> : Exploiter le CNAME Flattening pour exploiter la Zone Apex (domaine personnalisé) de manière sécurisée et rapide.&lt;/li>
&lt;li>&lt;strong>Optimisation des stratégies de cache&lt;/strong> : Utiliser &lt;code>_headers&lt;/code> pour séparer correctement le cache du navigateur et l&amp;rsquo;Edge Cache en fonction du type de ressource.&lt;/li>
&lt;li>&lt;strong>Analytique légère&lt;/strong> : Intégrer des outils comme Cloudflare Web Analytics pour ne pas dégrader les performances tout en respectant la vie privée.&lt;/li>
&lt;/ol>
&lt;p>En combinant ces éléments, vous pouvez créer gratuitement un système de blog évolutif et robuste, capable de supporter des trafics massifs atteignant des millions de pages vues (PV) par mois. Si vous envisagez de lancer un blog technique, un site d&amp;rsquo;entreprise ou un site portfolio, je vous invite vivement à essayer cette configuration Jamstack + Hugo + Cloudflare Pages.&lt;/p></description></item><item><title>Prévenir le manque d'idées pour les articles techniques ! Méthodes efficaces d'assimilation et de génération d'idées</title><link>http://kenji.blog/fr/p/tech-blog-idea-generation-and-input-strategy/</link><pubDate>Sat, 12 Sep 2026 12:00:00 +0900</pubDate><guid>http://kenji.blog/fr/p/tech-blog-idea-generation-and-input-strategy/</guid><description>&lt;img src="http://kenji.blog/p/tech-blog-idea-generation-and-input-strategy/img/eyecatch.jpg" alt="Featured image of post Prévenir le manque d'idées pour les articles techniques ! Méthodes efficaces d'assimilation et de génération d'idées" />&lt;p>Lorsque vous tenez un blog technique en tant qu&amp;rsquo;ingénieur ou chercheur, il y a un mur auquel vous serez presque certainement confronté. C&amp;rsquo;est la &amp;ldquo;panne d&amp;rsquo;idées&amp;rdquo;. Même si les premiers articles s&amp;rsquo;écrivent facilement, au fur et à mesure que vous continuez, il n&amp;rsquo;est pas rare d&amp;rsquo;être tourmenté par des problèmes tels que &amp;ldquo;Je ne sais pas quoi écrire ensuite&amp;rdquo; ou &amp;ldquo;Je manque cruellement de matières premières (input) pour produire (output)&amp;rdquo;. La rédaction d&amp;rsquo;un blog technique ne dépend pas seulement de la compétence en écriture, mais repose fortement sur la conception d&amp;rsquo;un système pour collecter et organiser quotidiennement les connaissances, puis les combiner pour créer de la nouvelle valeur.&lt;/p>
&lt;p>Dans cet article, nous expliquerons de manière extrêmement détaillée et technique un &lt;strong>pipeline d&amp;rsquo;assimilation et de production systématisé&lt;/strong> permettant de générer de façon quasi permanente des idées d&amp;rsquo;articles techniques. Nous commencerons par un mécanisme qui extrait automatiquement les sujets tendances de sources d&amp;rsquo;informations de haute qualité à l&amp;rsquo;étranger, comme Hacker News et Lobsters, à l&amp;rsquo;aide d&amp;rsquo;API, et l&amp;rsquo;exécute régulièrement via GitHub Actions. Ensuite, nous construirons un système avancé de gestion des connaissances personnelles (PKM : Personal Knowledge Management) qui organise les informations collectées sous forme de connaissances avec la méthode Zettelkasten en utilisant Obsidian, et permet une recherche sémantique en combinant l&amp;rsquo;API Embeddings d&amp;rsquo;OpenAI et Pinecone (une base de données vectorielle).&lt;/p>
&lt;p>De plus, pour compenser les limites de la mémoire humaine, nous mettrons en pratique la répétition espacée (Spaced Repetition) basée sur la courbe de l&amp;rsquo;oubli d&amp;rsquo;Ebbinghaus en utilisant Anki. Nous explorerons en profondeur le processus continu qui sublime les connaissances mémorisées en de nouvelles idées grâce à la &amp;ldquo;Créativité combinatoire (Combinatorial Creativity)&amp;rdquo;, avec des modèles mathématiques concrets et des exemples d&amp;rsquo;implémentation de scripts Python.&lt;/p>
&lt;h2 id="1-lentropie-de-linformation-et-le-mécanisme-de-la-panne-didées">1. L&amp;rsquo;entropie de l&amp;rsquo;information et le mécanisme de la &amp;ldquo;panne d&amp;rsquo;idées&amp;rdquo;
&lt;/h2>&lt;p>Pourquoi sommes-nous à court d&amp;rsquo;idées ? Du point de vue de la théorie de l&amp;rsquo;information, on peut dire que la &amp;ldquo;quantité d&amp;rsquo;informations&amp;rdquo; de notre système de connaissances s&amp;rsquo;est épuisée ou homogénéisée.&lt;/p>
&lt;p>L&amp;rsquo;entropie de l&amp;rsquo;information $H(X)$, proposée par Claude Shannon, représente l&amp;rsquo;incertitude (ou le degré de surprise) des informations obtenues à partir d&amp;rsquo;une source d&amp;rsquo;information.&lt;/p>
$$ H(X) = - \sum_{i=1}^{n} P(x_i) \log_2 P(x_i) $$&lt;p>Ici, $X$ est une variable aléatoire des sujets obtenus de la source d&amp;rsquo;information, et $P(x_i)$ est la probabilité de rencontrer ce sujet $x_i$. Si vous consultez habituellement les mêmes sites Web (par exemple, uniquement certains sites d&amp;rsquo;actualités nationaux ou la documentation de la même pile technologique), un certain $P(x_i)$ devient extrêmement élevé, et par conséquent, l&amp;rsquo;entropie $H(X)$ de l&amp;rsquo;ensemble du système diminue. Un état de faible entropie est un état &amp;ldquo;sans nouvelles découvertes (surprises)&amp;rdquo;, ce qui est la cause fondamentale de la panne d&amp;rsquo;idées.&lt;/p>
&lt;p>Pour maintenir une entropie élevée, il est nécessaire d&amp;rsquo;introduire intentionnellement des sources d&amp;rsquo;informations que vous ne consultez pas habituellement comme &amp;ldquo;bruit&amp;rdquo;, et d&amp;rsquo;égaliser la distribution de probabilité de rencontrer des sujets inconnus. C&amp;rsquo;est la principale raison pour laquelle on automatise l&amp;rsquo;apport de sources d&amp;rsquo;informations diverses.&lt;/p>
&lt;h2 id="2-construction-dun-pipeline-automatisé-de-collecte-dinformations--hacker-news--api-lobsters">2. Construction d&amp;rsquo;un pipeline automatisé de collecte d&amp;rsquo;informations : Hacker News &amp;amp; API Lobsters
&lt;/h2>&lt;p>Pour obtenir des informations de qualité, il est efficace d&amp;rsquo;extraire des informations sur les tendances à partir de communautés d&amp;rsquo;ingénieurs de qualité avec peu de bruit. Hacker News (géré par Y Combinator) et Lobsters sont des endroits idéaux pour des discussions techniques approfondies. Cependant, parcourir ces sites tous les jours prend du temps et consomme des ressources cognitives.&lt;/p>
&lt;p>Par conséquent, nous allons créer un script en utilisant Python pour extraire automatiquement les articles dépassant un certain score à partir de ces API.&lt;/p>
&lt;h3 id="script-python-pour-lextraction-des-articles-tendances">Script Python pour l&amp;rsquo;extraction des articles tendances
&lt;/h3>&lt;p>Le script suivant récupère les articles répondant à certains critères à partir de l&amp;rsquo;API Firebase de Hacker News et du flux JSON de Lobsters, et les produit sous forme de fichiers Markdown.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;span class="lnt">40
&lt;/span>&lt;span class="lnt">41
&lt;/span>&lt;span class="lnt">42
&lt;/span>&lt;span class="lnt">43
&lt;/span>&lt;span class="lnt">44
&lt;/span>&lt;span class="lnt">45
&lt;/span>&lt;span class="lnt">46
&lt;/span>&lt;span class="lnt">47
&lt;/span>&lt;span class="lnt">48
&lt;/span>&lt;span class="lnt">49
&lt;/span>&lt;span class="lnt">50
&lt;/span>&lt;span class="lnt">51
&lt;/span>&lt;span class="lnt">52
&lt;/span>&lt;span class="lnt">53
&lt;/span>&lt;span class="lnt">54
&lt;/span>&lt;span class="lnt">55
&lt;/span>&lt;span class="lnt">56
&lt;/span>&lt;span class="lnt">57
&lt;/span>&lt;span class="lnt">58
&lt;/span>&lt;span class="lnt">59
&lt;/span>&lt;span class="lnt">60
&lt;/span>&lt;span class="lnt">61
&lt;/span>&lt;span class="lnt">62
&lt;/span>&lt;span class="lnt">63
&lt;/span>&lt;span class="lnt">64
&lt;/span>&lt;span class="lnt">65
&lt;/span>&lt;span class="lnt">66
&lt;/span>&lt;span class="lnt">67
&lt;/span>&lt;span class="lnt">68
&lt;/span>&lt;span class="lnt">69
&lt;/span>&lt;span class="lnt">70
&lt;/span>&lt;span class="lnt">71
&lt;/span>&lt;span class="lnt">72
&lt;/span>&lt;span class="lnt">73
&lt;/span>&lt;span class="lnt">74
&lt;/span>&lt;span class="lnt">75
&lt;/span>&lt;span class="lnt">76
&lt;/span>&lt;span class="lnt">77
&lt;/span>&lt;span class="lnt">78
&lt;/span>&lt;span class="lnt">79
&lt;/span>&lt;span class="lnt">80
&lt;/span>&lt;span class="lnt">81
&lt;/span>&lt;span class="lnt">82
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">requests&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">json&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">datetime&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">datetime&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">os&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Paramètres&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">HN_TOPSTORIES_URL&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;https://hacker-news.firebaseio.com/v0/topstories.json&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">HN_ITEM_URL&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;https://hacker-news.firebaseio.com/v0/item/&lt;/span>&lt;span class="si">{}&lt;/span>&lt;span class="s2">.json&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">LOBSTERS_URL&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;https://lobste.rs/hottest.json&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">MIN_HN_SCORE&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">100&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">MIN_LOBSTERS_SCORE&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">10&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">OUTPUT_DIR&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;./daily_inputs&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">get_hacker_news_trends&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;Récupérer les meilleurs articles avec des scores élevés depuis Hacker News&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Fetching Hacker News top stories...&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">response&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">requests&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">HN_TOPSTORIES_URL&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">response&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">status_code&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="mi">200&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="p">[]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">story_ids&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">response&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">json&lt;/span>&lt;span class="p">()[:&lt;/span>&lt;span class="mi">30&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="c1"># Restreindre aux 30 premiers&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">trending_stories&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">story_id&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">story_ids&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">item_resp&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">requests&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">HN_ITEM_URL&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">format&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">story_id&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">item_resp&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">status_code&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">200&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">item&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">item_resp&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">json&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">item&lt;/span> &lt;span class="ow">and&lt;/span> &lt;span class="n">item&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;score&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">&amp;gt;=&lt;/span> &lt;span class="n">MIN_HN_SCORE&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">trending_stories&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">append&lt;/span>&lt;span class="p">({&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;title&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">item&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;title&amp;#34;&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;url&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">item&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;url&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;https://news.ycombinator.com/item?id=&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">story_id&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;score&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">item&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;score&amp;#34;&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;source&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;Hacker News&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">})&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">trending_stories&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">get_lobsters_trends&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;Récupérer les articles avec des scores élevés depuis Lobsters&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Fetching Lobsters hottest stories...&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">response&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">requests&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">LOBSTERS_URL&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">response&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">status_code&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="mi">200&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="p">[]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">items&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">response&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">json&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">trending_stories&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">item&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">items&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">item&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;score&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">&amp;gt;=&lt;/span> &lt;span class="n">MIN_LOBSTERS_SCORE&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">trending_stories&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">append&lt;/span>&lt;span class="p">({&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;title&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">item&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;title&amp;#34;&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;url&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">item&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;url&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">item&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;comments_url&amp;#34;&lt;/span>&lt;span class="p">)),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;score&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">item&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;score&amp;#34;&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;source&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;Lobsters&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">})&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">trending_stories&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">save_to_markdown&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">stories&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;Enregistrer les articles récupérés en tant que fichier Markdown&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="ow">not&lt;/span> &lt;span class="n">os&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">path&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">exists&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">OUTPUT_DIR&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">os&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">makedirs&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">OUTPUT_DIR&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">today_str&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">datetime&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">now&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">strftime&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;%Y-%m-&lt;/span>&lt;span class="si">%d&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">filepath&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">os&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">path&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">join&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">OUTPUT_DIR&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;trends_&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">today_str&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">.md&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">with&lt;/span> &lt;span class="nb">open&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">filepath&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;w&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">encoding&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;utf-8&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="n">f&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">f&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">write&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;# Daily Tech Trends: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">today_str&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="se">\n\n&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">story&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">stories&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">f&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">write&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;## [&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">story&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;title&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">](&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">story&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;url&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">)&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">f&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">write&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;- **Source**: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">story&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;source&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">f&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">write&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;- **Score**: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">story&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;score&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">f&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">write&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;- **Notes**: (Ajoutez vos réflexions ici)&lt;/span>&lt;span class="se">\n\n&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Saved &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="nb">len&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">stories&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> stories to &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">filepath&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="vm">__name__&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s2">&amp;#34;__main__&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">hn_stories&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">get_hacker_news_trends&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">lobsters_stories&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">get_lobsters_trends&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">all_stories&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">hn_stories&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">lobsters_stories&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Trier par ordre décroissant de score&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">all_stories&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">sort&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">key&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="k">lambda&lt;/span> &lt;span class="n">x&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">x&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;score&amp;#34;&lt;/span>&lt;span class="p">],&lt;/span> &lt;span class="n">reverse&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">save_to_markdown&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">all_stories&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Ce script offre plus de valeur qu&amp;rsquo;un simple lecteur RSS. En filtrant par score, il est possible d&amp;rsquo;extraire uniquement les sujets techniques qui attirent vraiment l&amp;rsquo;attention de la communauté (signal élevé avec peu de bruit).&lt;/p>
&lt;h2 id="3-planification-et-automatisation-avec-github-actions">3. Planification et automatisation avec GitHub Actions
&lt;/h2>&lt;p>Exécuter manuellement le script Python créé tous les jours est fastidieux. La base de l&amp;rsquo;automatisation consiste à réduire au maximum l&amp;rsquo;intervention humaine. En utilisant la fonctionnalité Cron de GitHub Actions, nous construisons un système qui exécute le script à une heure spécifiée chaque jour et valide (commit) automatiquement les résultats dans le dépôt.&lt;/p>
&lt;p>Créez &lt;code>.github/workflows/daily_trends.yml&lt;/code> à la racine du projet et rédigez-le comme suit.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Daily Tech Trends Scraper&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">on&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">schedule&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">cron&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;0 0 * * *&amp;#39;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># Exécuter tous les jours à 0:00 UTC (9:00 heure du Japon)&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">workflow_dispatch&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># Pour l&amp;#39;exécution manuelle&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">jobs&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">scrape-and-commit&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">runs-on&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">ubuntu-latest&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">steps&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Checkout Repository&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">uses&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">actions/checkout@v3&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Setup Python&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">uses&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">actions/setup-python@v4&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">with&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">python-version&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;3.10&amp;#39;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Install Dependencies&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">run&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">|&lt;/span>&lt;span class="sd">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sd"> python -m pip install --upgrade pip
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sd"> pip install requests
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sd"> &lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Run Scraper Script&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">run&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">python scripts/fetch_trends.py&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Commit and Push Changes&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">run&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">|&lt;/span>&lt;span class="sd">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sd"> git config --local user.email &amp;#34;action@github.com&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sd"> git config --local user.name &amp;#34;GitHub Action&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sd"> git add daily_inputs/
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sd"> git commit -m &amp;#34;Auto-update daily tech trends [skip ci]&amp;#34; || echo &amp;#34;No changes to commit&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sd"> git push&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>De cette façon, lorsque vous ouvrez Obsidian chaque matin, les sujets importants de la journée seront automatiquement ajoutés à votre boîte de réception (&lt;code>daily_inputs/&lt;/code>) sous forme de Markdown.&lt;/p>
&lt;h2 id="4-mise-en-réseau-des-connaissances-à-laide-de-zettelkasten-et-obsidian">4. Mise en réseau des connaissances à l&amp;rsquo;aide de Zettelkasten et Obsidian
&lt;/h2>&lt;p>Les informations collectées automatiquement ne sont encore que de simples &amp;ldquo;données&amp;rdquo;. Il faut un processus pour les sublimer en &amp;ldquo;connaissances&amp;rdquo;. C&amp;rsquo;est ici que la méthode Zettelkasten et Obsidian entrent en jeu.&lt;/p>
&lt;p>Zettelkasten est une méthode de prise de notes inventée par le sociologue allemand Niklas Luhmann. Au lieu de classer les notes dans des dossiers hiérarchiques, chaque note est gardée petite (atomique), et les notes sont reliées entre elles par des liens, créant ainsi un réseau de connaissances semblable aux circuits neuronaux du cerveau.&lt;/p>
&lt;p>Il existe principalement 3 types de notes dans Zettelkasten :&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Fleeting Notes (Notes éphémères)&lt;/strong> : Pour enregistrer temporairement des idées qui vous viennent à l&amp;rsquo;esprit ou des informations que vous avez collectées. Le Markdown des informations de tendance généré automatiquement tout à l&amp;rsquo;heure correspond à cela.&lt;/li>
&lt;li>&lt;strong>Literature Notes (Notes de lecture)&lt;/strong> : Des résumés dans vos propres mots après avoir lu des articles ou des livres.&lt;/li>
&lt;li>&lt;strong>Permanent Notes (Notes permanentes)&lt;/strong> : Des réflexions complètes sur un sujet donné. Celles-ci deviendront les germes directs de vos articles de blog.&lt;/li>
&lt;/ol>
&lt;p>En utilisant la fonctionnalité de rétrolien (backlink) d&amp;rsquo;Obsidian (&lt;code>[[Nom de la note]]&lt;/code>), par exemple en liant la note &amp;ldquo;Propriété dans Rust&amp;rdquo; avec la note &amp;ldquo;Histoire du Garbage Collection&amp;rdquo;, vous pouvez découvrir des connexions d&amp;rsquo;idées inattendues.&lt;/p>
&lt;h2 id="5-recherche-sémantique-à-laide-de-bases-de-données-vectorielles-pinecone-et-dopenai-embeddings">5. Recherche sémantique à l&amp;rsquo;aide de bases de données vectorielles (Pinecone) et d&amp;rsquo;OpenAI Embeddings
&lt;/h2>&lt;p>Lorsque le nombre de notes atteint des centaines ou des milliers, il devient difficile de trouver la note souhaitée avec une simple recherche par mots-clés (recherche en texte intégral). C&amp;rsquo;est là que la recherche sémantique, qui utilise les Embeddings des grands modèles de langage (LLM), démontre sa puissance, particulièrement utile lorsque vous vous dites : &amp;ldquo;Je ne me souviens pas des mots-clés, mais je veux trouver des notes conceptuellement similaires.&amp;rdquo;&lt;/p>
&lt;p>En utilisant le modèle &lt;code>text-embedding-ada-002&lt;/code> (ou &lt;code>text-embedding-3-small&lt;/code>) d&amp;rsquo;OpenAI, chaque note Markdown d&amp;rsquo;Obsidian est convertie en un vecteur multidimensionnel (un tableau de nombres de centaines à milliers de dimensions). Dans ces espaces vectoriels, les vecteurs de phrases ayant des significations proches sont également physiquement proches l&amp;rsquo;un de l&amp;rsquo;autre.&lt;/p>
&lt;p>Pour mesurer la similarité entre les vecteurs, la similarité cosinus (Cosine Similarity) est largement utilisée.&lt;/p>
$$ \text{similarity} = \cos(\theta) = \frac{\mathbf{A} \cdot \mathbf{B}}{\|\mathbf{A}\| \|\mathbf{B}\|} = \frac{\sum_{i=1}^{n} A_i B_i}{\sqrt{\sum_{i=1}^{n} A_i^2} \sqrt{\sum_{i=1}^{n} B_i^2}} $$&lt;p>$\mathbf{A}$ et $\mathbf{B}$ sont respectivement le vecteur de la chaîne de requête et le vecteur de la note. Pour effectuer ce calcul rapidement, on utilise des bases de données vectorielles telles que Pinecone ou Qdrant.&lt;/p>
&lt;h3 id="exemple-dimplémentation-de-la-recherche-sémantique">Exemple d&amp;rsquo;implémentation de la recherche sémantique
&lt;/h3>&lt;p>Voici une partie d&amp;rsquo;un script Python qui parcourt le répertoire des notes d&amp;rsquo;Obsidian, les vectorise avec l&amp;rsquo;API OpenAI et les met à jour (upsert) dans Pinecone.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;span class="lnt">40
&lt;/span>&lt;span class="lnt">41
&lt;/span>&lt;span class="lnt">42
&lt;/span>&lt;span class="lnt">43
&lt;/span>&lt;span class="lnt">44
&lt;/span>&lt;span class="lnt">45
&lt;/span>&lt;span class="lnt">46
&lt;/span>&lt;span class="lnt">47
&lt;/span>&lt;span class="lnt">48
&lt;/span>&lt;span class="lnt">49
&lt;/span>&lt;span class="lnt">50
&lt;/span>&lt;span class="lnt">51
&lt;/span>&lt;span class="lnt">52
&lt;/span>&lt;span class="lnt">53
&lt;/span>&lt;span class="lnt">54
&lt;/span>&lt;span class="lnt">55
&lt;/span>&lt;span class="lnt">56
&lt;/span>&lt;span class="lnt">57
&lt;/span>&lt;span class="lnt">58
&lt;/span>&lt;span class="lnt">59
&lt;/span>&lt;span class="lnt">60
&lt;/span>&lt;span class="lnt">61
&lt;/span>&lt;span class="lnt">62
&lt;/span>&lt;span class="lnt">63
&lt;/span>&lt;span class="lnt">64
&lt;/span>&lt;span class="lnt">65
&lt;/span>&lt;span class="lnt">66
&lt;/span>&lt;span class="lnt">67
&lt;/span>&lt;span class="lnt">68
&lt;/span>&lt;span class="lnt">69
&lt;/span>&lt;span class="lnt">70
&lt;/span>&lt;span class="lnt">71
&lt;/span>&lt;span class="lnt">72
&lt;/span>&lt;span class="lnt">73
&lt;/span>&lt;span class="lnt">74
&lt;/span>&lt;span class="lnt">75
&lt;/span>&lt;span class="lnt">76
&lt;/span>&lt;span class="lnt">77
&lt;/span>&lt;span class="lnt">78
&lt;/span>&lt;span class="lnt">79
&lt;/span>&lt;span class="lnt">80
&lt;/span>&lt;span class="lnt">81
&lt;/span>&lt;span class="lnt">82
&lt;/span>&lt;span class="lnt">83
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">os&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">glob&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">openai&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">OpenAI&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">pinecone&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">Pinecone&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">ServerlessSpec&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Configuration de la clé API (obtenue à partir des variables d&amp;#39;environnement)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">OPENAI_API_KEY&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">os&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">getenv&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;OPENAI_API_KEY&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">PINECONE_API_KEY&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">os&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">getenv&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;PINECONE_API_KEY&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">client&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">OpenAI&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">api_key&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">OPENAI_API_KEY&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">pc&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Pinecone&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">api_key&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">PINECONE_API_KEY&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">INDEX_NAME&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;obsidian-notes&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">OBSIDIAN_DIR&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;/path/to/obsidian/vault/PermanentNotes&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">init_pinecone&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;Initialisation de l&amp;#39;index Pinecone&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">INDEX_NAME&lt;/span> &lt;span class="ow">not&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">pc&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">list_indexes&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">names&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">pc&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">create_index&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">INDEX_NAME&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">dimension&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">1536&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1"># Nombre de dimensions pour text-embedding-3-small / ada-002&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">metric&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;cosine&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">spec&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">ServerlessSpec&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">cloud&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;aws&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">region&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;us-east-1&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">pc&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">Index&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">INDEX_NAME&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">get_embedding&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">text&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;Vectorisation de texte avec l&amp;#39;API OpenAI&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">response&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">client&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">embeddings&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">create&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">input&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">text&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">model&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;text-embedding-3-small&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">response&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">embedding&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">sync_notes_to_pinecone&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">index&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;Lit les fichiers Markdown, les vectorise et les enregistre dans Pinecone&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">md_files&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">glob&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">glob&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">os&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">path&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">join&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">OBSIDIAN_DIR&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;*.md&amp;#34;&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">vectors&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">filepath&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">md_files&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">filename&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">os&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">path&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">basename&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">filepath&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">with&lt;/span> &lt;span class="nb">open&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">filepath&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;r&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">encoding&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;utf-8&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="n">f&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">content&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">f&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">read&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Traitement uniquement si le contenu de la note n&amp;#39;est pas vide&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">content&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">strip&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Embedding note: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">filename&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">embedding&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">get_embedding&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">content&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Format Pinecone (id, vecteur, métadonnées)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">vectors&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">append&lt;/span>&lt;span class="p">({&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;id&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">filename&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;values&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">embedding&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;metadata&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="s2">&amp;#34;text&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">content&lt;/span>&lt;span class="p">[:&lt;/span>&lt;span class="mi">500&lt;/span>&lt;span class="p">]}&lt;/span> &lt;span class="c1"># Extrait de texte pour l&amp;#39;affichage des résultats de recherche&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">})&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Mise à jour par traitement par lots (batch)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">vectors&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">index&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">upsert&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">vectors&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">vectors&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Successfully upserted &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="nb">len&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">vectors&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> notes.&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">search_similar_ideas&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">index&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">query_text&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">top_k&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">3&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;Rechercher des notes similaires à la requête pour aider à générer des idées&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">query_embedding&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">get_embedding&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">query_text&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">results&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">index&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">query&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">vector&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">query_embedding&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">top_k&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">top_k&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">include_metadata&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">--- Search Results for: &amp;#39;&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">query_text&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#39; ---&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="k">match&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">results&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;matches&amp;#34;&lt;/span>&lt;span class="p">]:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Score: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">match&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;score&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="si">:&lt;/span>&lt;span class="s2">.4f&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> | Note: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">match&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;id&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Preview: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">match&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;metadata&amp;#39;&lt;/span>&lt;span class="p">][&lt;/span>&lt;span class="s1">&amp;#39;text&amp;#39;&lt;/span>&lt;span class="p">][:&lt;/span>&lt;span class="mi">100&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">...&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="vm">__name__&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s2">&amp;#34;__main__&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">idx&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">init_pinecone&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Lors de la première exécution, appeler sync_notes_to_pinecone(idx) pour construire la BD&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">sync_notes_to_pinecone&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">idx&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Recherche d&amp;#39;idées pour le blog&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">search_similar_ideas&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">idx&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;Accélération de l&amp;#39;inférence de l&amp;#39;apprentissage automatique dans le navigateur à l&amp;#39;aide de WebAssembly&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Avec ce système, si vous vous demandez : &amp;ldquo;Je veux écrire sur &amp;lsquo;WebAssembly&amp;rsquo;, qui a fait le buzz sur Hacker News cette semaine, mais ai-je déjà écrit une note connexe dans le passé ?&amp;rdquo;, l&amp;rsquo;IA sélectionnera instantanément pour vous les Permanent Notes sémantiquement liées. Cela permet de structurer des articles approfondis en exploitant pleinement vos propres connaissances accumulées dans le passé.&lt;/p>
&lt;h2 id="6-la-courbe-de-loubli-debbinghaus-et-la-répétition-espacée-avec-anki">6. La courbe de l&amp;rsquo;oubli d&amp;rsquo;Ebbinghaus et la répétition espacée avec Anki
&lt;/h2>&lt;p>Peu importe la qualité des connaissances que vous consignez dans vos notes, si elles ne sont pas ancrées dans le cerveau même de l&amp;rsquo;auteur, il sera difficile de relier couramment plusieurs concepts lors de la rédaction. C&amp;rsquo;est ici qu&amp;rsquo;intervient la &amp;ldquo;courbe de l&amp;rsquo;oubli d&amp;rsquo;Ebbinghaus&amp;rdquo;, qui modélise mathématiquement le mécanisme de la mémoire humaine.&lt;/p>
&lt;p>La courbe de l&amp;rsquo;oubli est approchée par l&amp;rsquo;équation suivante :&lt;/p>
$$ R = e^{-\frac{t}{S}} $$&lt;p>Où,&lt;/p>
&lt;ul>
&lt;li>$R$ est le taux de rétention de la mémoire (Retrievability, plage de 0 à 1)&lt;/li>
&lt;li>$t$ est le temps écoulé depuis l&amp;rsquo;apprentissage&lt;/li>
&lt;li>$S$ est la stabilité (Stability) ou la force de la mémoire&lt;/li>
&lt;/ul>
&lt;p>Immédiatement après l&amp;rsquo;apprentissage d&amp;rsquo;un nouveau concept, $S$ est petit, et $R$ diminue rapidement (oubli) avec le temps $t$. Cependant, en révisant (Recall) au moment idéal où vous êtes sur le point d&amp;rsquo;oublier, la vitesse d&amp;rsquo;oubli ralentit (c&amp;rsquo;est-à-dire que $S$ augmente) et les informations s&amp;rsquo;ancrent dans la mémoire à long terme.&lt;/p>
&lt;p>Le logiciel &amp;ldquo;Anki&amp;rdquo; calcule automatiquement ce moment de révision optimal à l&amp;rsquo;aide d&amp;rsquo;algorithmes (comme SuperMemo 2) et vous le présente sous forme de flashcards (cartes-mémoire).&lt;/p>
&lt;p>Une approche puissante pour créer des sujets de blog technique consiste à &lt;strong>convertir le contenu des Permanent Notes d&amp;rsquo;Obsidian en flashcards Anki&lt;/strong>.
Par exemple, vous pouvez enregistrer des questions touchant aux fondements technologiques, telles que &amp;ldquo;Quels sont les 3 éléments du théorème CAP ?&amp;rdquo; ou &amp;ldquo;Pourquoi l&amp;rsquo;index B-Tree a-t-il une performance de recherche de O(log N) ?&amp;rdquo;, dans Anki et les réviser dans le cadre de votre routine quotidienne. Une fois que ces connaissances sont indexées dans votre cerveau comme mémoire à long terme, lorsque vous prenez une douche ou que vous vous promenez, les informations se connectent de manière subconsciente, générant des moments eurêka (&amp;ldquo;Ah, je pourrais écrire un article sur l&amp;rsquo;algorithme de consensus dans les systèmes distribués !&amp;rdquo;).&lt;/p>
&lt;h2 id="7-la-créativité-combinatoire-combinatorial-creativity">7. La créativité combinatoire (Combinatorial Creativity)
&lt;/h2>&lt;p>Grâce au pipeline décrit jusqu&amp;rsquo;à présent, nous avons réalisé &amp;ldquo;l&amp;rsquo;assimilation d&amp;rsquo;informations diverses&amp;rdquo;, &amp;ldquo;l&amp;rsquo;organisation par Zettelkasten et la recherche IA&amp;rdquo;, et &amp;ldquo;l&amp;rsquo;ancrage dans la mémoire à long terme par Anki&amp;rdquo;. La dernière étape est la &amp;ldquo;Créativité combinatoire (Combinatorial Creativity)&amp;rdquo;, qui multiplie ces éléments pour générer des idées d&amp;rsquo;articles techniques complètement nouvelles.&lt;/p>
&lt;p>On dit que l&amp;rsquo;innovation et la créativité ne naissent pas de rien, mais émergent d&amp;rsquo;une nouvelle combinaison d&amp;rsquo;éléments existants. La citation de Steve Jobs &amp;ldquo;Creativity is just connecting things.&amp;rdquo; en est un exemple célèbre.&lt;/p>
&lt;p>Les modèles de combinaisons pour les blogs techniques pourraient être représentés par la matrice suivante :&lt;/p>
&lt;ol>
&lt;li>&lt;strong>[Ancienne technologie] × [Nouveau paradigme]&lt;/strong> : Ex. &amp;ldquo;Les anti-patterns de conception de microservices modernes appris de l&amp;rsquo;architecture COBOL&amp;rdquo;&lt;/li>
&lt;li>&lt;strong>[Front-end] × [Concepts Back-end]&lt;/strong> : Ex. &amp;ldquo;Explication de l&amp;rsquo;algorithme de mise à jour du DOM virtuel de React du point de vue des niveaux d&amp;rsquo;isolation des transactions de base de données&amp;rdquo;&lt;/li>
&lt;li>&lt;strong>[Mathématiques/Théorie abstraites] × [Implémentation concrète]&lt;/strong> : Ex. &amp;ldquo;Déchiffrer l&amp;rsquo;optimisation de la planification des pods Kubernetes par la théorie des graphes&amp;rdquo;&lt;/li>
&lt;/ol>
&lt;p>Pour susciter intentionnellement ces combinaisons, vous pouvez utiliser le système de recherche sémantique de Pinecone construit précédemment pour extraire aléatoirement un concept A et un concept B, et lancer un prompt à une IA (comme ChatGPT) tel que : &amp;ldquo;Propose-moi 5 idées de titres et de plans d&amp;rsquo;articles de blog technique combinant ces 2 concepts&amp;rdquo;. Vous pourrez ainsi générer à l&amp;rsquo;infini des idées d&amp;rsquo;articles avec des angles originaux auxquels vous n&amp;rsquo;auriez pas pensé vous-même.&lt;/p>
&lt;h2 id="8-architecture-globale-du-système">8. Architecture globale du système
&lt;/h2>&lt;p>L&amp;rsquo;architecture globale expliquée jusqu&amp;rsquo;à présent, de la &amp;ldquo;collecte d&amp;rsquo;informations à la génération d&amp;rsquo;idées&amp;rdquo; pour éviter la panne d&amp;rsquo;idées d&amp;rsquo;articles techniques, est résumée dans le diagramme de flux Mermaid suivant.&lt;/p>
&lt;pre class="mermaid">
flowchart TD
A[&amp;#34;Hacker News / Lobsters API&amp;#34;] --&amp;gt;|Script d&amp;#39;extraction Python| B[&amp;#34;Données de tendance brutes&amp;#34;]
C[&amp;#34;GitHub Actions (Cron)&amp;#34;] --&amp;gt;|Calendrier d&amp;#39;exécution régulière| A
B --&amp;gt;|Conversion au format Markdown| D[&amp;#34;Daily Inputs (Fleeting Notes)&amp;#34;]
D --&amp;gt;|Travail manuel de lecture et de résumé| E[&amp;#34;Obsidian Zettelkasten&amp;#34;]
E --&amp;gt;|Conversion en notes permanentes| F[&amp;#34;Permanent Notes&amp;#34;]
F --&amp;gt;|Processus de synchronisation automatique| G[&amp;#34;OpenAI Embeddings API&amp;#34;]
G --&amp;gt;|Conversion vectorielle| H[&amp;#34;Pinecone Vector Database&amp;#34;]
H --&amp;gt;|Recherche sémantique| I[&amp;#34;Découverte et extraction de connaissances liées&amp;#34;]
F --&amp;gt;|Création de cartes-mémoire (flashcards)| J[&amp;#34;Anki (Spaced Repetition)&amp;#34;]
J --&amp;gt;|Inspiration depuis la mémoire à long terme| K[&amp;#34;Combinatorial Creativity&amp;#34;]
I --&amp;gt; K
K --&amp;gt;|Création de l&amp;#39;intrigue / Planification| L[&amp;#34;Blog Post Draft (Rédaction de l&amp;#39;article)&amp;#34;]
&lt;/pre>
&lt;p>La caractéristique de ce système est que &lt;strong>&amp;ldquo;le travail intellectuel à effectuer manuellement (résumé, réflexion, écriture)&amp;rdquo; et &amp;ldquo;le travail à déléguer à la machine (collecte, recherche, planification de la répétition espacée)&amp;rdquo; sont complètement séparés&lt;/strong>. Cela permet à l&amp;rsquo;auteur de se concentrer sur &amp;ldquo;penser&amp;rdquo; et &amp;ldquo;combiner&amp;rdquo;, qui ont la plus grande valeur ajoutée.&lt;/p>
&lt;h2 id="9-modèle-de-transition-détat-de-lidée-à-la-publication">9. Modèle de transition d&amp;rsquo;état de l&amp;rsquo;idée à la publication
&lt;/h2>&lt;p>Le cycle de vie des idées accumulées dans Zettelkasten, de leur création à leur publication finale en tant qu&amp;rsquo;article de blog, peut être représenté par le diagramme de transition d&amp;rsquo;état suivant. Les outils et approches appropriés sont utilisés dans chaque état.&lt;/p>
&lt;pre class="mermaid">
stateDiagram-v2
[*] --&amp;gt; Capture[&amp;#34;Idea Capture (Capture d&amp;#39;idées)&amp;#34;]
Capture[&amp;#34;Idea Capture (Capture d&amp;#39;idées)&amp;#34;] --&amp;gt; Fleeting[&amp;#34;Fleeting Notes (Notes éphémères)&amp;#34;]
Fleeting[&amp;#34;Fleeting Notes (Notes éphémères)&amp;#34;] --&amp;gt; Permanent[&amp;#34;Permanent Notes (Notes permanentes)&amp;#34;]
Permanent[&amp;#34;Permanent Notes (Notes permanentes)&amp;#34;] --&amp;gt; Brainstorming[&amp;#34;Brainstorming (Recherche sémantique IA)&amp;#34;]
Permanent[&amp;#34;Permanent Notes (Notes permanentes)&amp;#34;] --&amp;gt; Memorization[&amp;#34;Memorization (Révisions Anki)&amp;#34;]
Memorization[&amp;#34;Memorization (Révisions Anki)&amp;#34;] --&amp;gt; Brainstorming[&amp;#34;Brainstorming (Recherche sémantique IA)&amp;#34;]
Brainstorming[&amp;#34;Brainstorming (Recherche sémantique IA)&amp;#34;] --&amp;gt; Outlining[&amp;#34;Outlining (Structuration et plan)&amp;#34;]
Outlining[&amp;#34;Outlining (Structuration et plan)&amp;#34;] --&amp;gt; Drafting[&amp;#34;Drafting (Rédaction du premier jet)&amp;#34;]
Drafting[&amp;#34;Drafting (Rédaction du premier jet)&amp;#34;] --&amp;gt; Review[&amp;#34;Review &amp;amp; Edit (Révision et correction)&amp;#34;]
Review[&amp;#34;Review &amp;amp; Edit (Révision et correction)&amp;#34;] --&amp;gt; Published[&amp;#34;Published (Publication sur le blog)&amp;#34;]
Published[&amp;#34;Published (Publication sur le blog)&amp;#34;] --&amp;gt; [*]
&lt;/pre>
&lt;p>En gardant ce flux de travail à l&amp;rsquo;esprit, vous savez clairement &amp;ldquo;dans quelle phase vous êtes bloqué actuellement&amp;rdquo;. Si vous manquez d&amp;rsquo;idées, il suffit de retourner à la phase de &amp;ldquo;Capture&amp;rdquo; ou &amp;ldquo;Permanent&amp;rdquo; et de vérifier si le pipeline d&amp;rsquo;assimilation fonctionne correctement.&lt;/p>
&lt;h2 id="conclusion--lécriture-est-un-système">Conclusion : L&amp;rsquo;écriture est un &amp;ldquo;système&amp;rdquo;
&lt;/h2>&lt;p>Le &amp;ldquo;manque d&amp;rsquo;idées pour les blogs techniques&amp;rdquo; n&amp;rsquo;est pas causé par un manque de capacités personnelles ou une baisse de motivation, mais est le &lt;strong>résultat inévitable de l&amp;rsquo;absence de construction d&amp;rsquo;un système de circulation des connaissances&lt;/strong>.&lt;/p>
&lt;p>Comme présenté dans cet article :&lt;/p>
&lt;ol>
&lt;li>Assurer une assimilation de qualité et sans bruit grâce aux &lt;strong>API et à l&amp;rsquo;automatisation&lt;/strong>&lt;/li>
&lt;li>Mettre en réseau les connaissances grâce à Zettelkasten en utilisant &lt;strong>Obsidian&lt;/strong>&lt;/li>
&lt;li>Recherche sémantique de ses propres ressources via &lt;strong>OpenAI et Pinecone&lt;/strong>&lt;/li>
&lt;li>Renforcement de l&amp;rsquo;indexation cérébrale à l&amp;rsquo;aide d&amp;rsquo;&lt;strong>Anki&lt;/strong> et de la courbe de l&amp;rsquo;oubli d&amp;rsquo;Ebbinghaus&lt;/li>
&lt;li>&lt;strong>Créativité combinatoire&lt;/strong> pour croiser des concepts existants&lt;/li>
&lt;/ol>
&lt;p>En construisant un pipeline complet combinant ces éléments, vos idées de blog ne s&amp;rsquo;épuiseront pas ; au contraire, plus vous écrirez, plus de nouvelles idées s&amp;rsquo;auto-multiplieront.&lt;/p>
&lt;p>Il n&amp;rsquo;est pas nécessaire de tout construire parfaitement dès le début. Commencez par créer un script simple qui interroge l&amp;rsquo;API de Hacker News, et prenez l&amp;rsquo;habitude de noter les articles qui vous intéressent en Markdown. J&amp;rsquo;espère que votre blog technique deviendra une source d&amp;rsquo;excellence pour la prochaine génération d&amp;rsquo;idées.&lt;/p></description></item><item><title>SEO pour les blogs Hugo : Paramètres du frontmatter pour augmenter considérablement le trafic</title><link>http://kenji.blog/fr/p/hugo-blog-seo-frontmatter-tips/</link><pubDate>Sat, 12 Sep 2026 12:00:00 +0900</pubDate><guid>http://kenji.blog/fr/p/hugo-blog-seo-frontmatter-tips/</guid><description>&lt;img src="http://kenji.blog/p/hugo-blog-seo-frontmatter-tips/img/eyecatch.jpg" alt="Featured image of post SEO pour les blogs Hugo : Paramètres du frontmatter pour augmenter considérablement le trafic" />&lt;p>Hugo est l&amp;rsquo;un des générateurs de sites statiques (SSG) les plus rapides au monde, écrit en langage Go. Grâce à sa vitesse de compilation impressionnante et à son système de templates flexible, il bénéficie d&amp;rsquo;un grand soutien de la part de nombreux ingénieurs et blogueurs. Cependant, le simple fait qu&amp;rsquo;un site soit généré et affiché rapidement ne suffit pas pour qu&amp;rsquo;il soit bien évalué par les moteurs de recherche (comme Google ou Bing) et pour que les articles atteignent les utilisateurs.&lt;/p>
&lt;p>Pour améliorer le classement dans les résultats de recherche, augmenter la viralité sur les réseaux sociaux et, par conséquent, accroître considérablement le trafic vers votre blog, des mesures SEO (Optimisation pour les Moteurs de Recherche) rigoureuses sont indispensables. Le cœur du SEO dans Hugo réside dans la coordination entre le &lt;strong>frontmatter&lt;/strong>, écrit au début de chaque article Markdown, et les &lt;strong>templates (Layouts)&lt;/strong> qui l&amp;rsquo;interprètent pour déployer les métadonnées dans la balise &lt;code>&amp;lt;head&amp;gt;&lt;/code> du HTML.&lt;/p>
&lt;p>Dans cet article, nous expliquerons en détail, avec un volume impressionnant de plus de 10 000 caractères, comment tirer pleinement parti des fonctionnalités de Hugo et mettre en œuvre des mesures SEO avancées : de la configuration du frontmatter aux différentes balises meta, en passant par l&amp;rsquo;OGP (Open Graph Protocol), les Twitter Cards, jusqu&amp;rsquo;à la génération de données structurées à l&amp;rsquo;aide de JSON-LD.&lt;/p>
&lt;hr>
&lt;h2 id="1-contexte-mathématique-du-seo-et-du-trafic">1. Contexte mathématique du SEO et du trafic
&lt;/h2>&lt;p>Avant d&amp;rsquo;entrer dans les détails de l&amp;rsquo;implémentation, comprenons mathématiquement pourquoi les métadonnées SEO précises sont si importantes. Le trafic de recherche $T$ qu&amp;rsquo;un site Web peut acquérir est déterminé par le volume de recherche des mots-clés ciblés et le taux de clics (CTR) basé sur le classement dans les résultats de recherche.&lt;/p>
&lt;p>Ceci peut être exprimé par la formule suivante :&lt;/p>
$$ T = \sum_{i=1}^{n} V_i \times CTR(R_i) $$&lt;ul>
&lt;li>$V_i$ : Volume de recherche mensuel pour le mot-clé $i$&lt;/li>
&lt;li>$R_i$ : Classement de recherche pour le mot-clé $i$&lt;/li>
&lt;li>$CTR(R_i)$ : Taux de clics au classement $R_i$&lt;/li>
&lt;/ul>
&lt;p>Parmi ces éléments, le classement de recherche $R_i$ dépend de nombreux facteurs tels que la qualité du contenu et les backlinks (PageRank), mais l&amp;rsquo;algorithme initial de PageRank de Google est modélisé comme suit :&lt;/p>
$$ PR(u) = \frac{1-d}{N} + d \sum_{v \in B(u)} \frac{PR(v)}{L(v)} $$&lt;ul>
&lt;li>$PR(u)$ : PageRank de la page $u$&lt;/li>
&lt;li>$d$ : Facteur d&amp;rsquo;amortissement (généralement 0,85)&lt;/li>
&lt;li>$B(u)$ : Ensemble des pages contenant un lien vers la page $u$&lt;/li>
&lt;li>$L(v)$ : Nombre de liens sortants de la page $v$&lt;/li>
&lt;/ul>
&lt;p>Ce qui est important ici, c&amp;rsquo;est &lt;strong>en plus des efforts pour améliorer le classement de recherche $R_i$, comment maximiser le taux de clics $CTR(R_i)$&lt;/strong>. En optimisant le titre et l&amp;rsquo;extrait (description) affichés dans les pages de résultats des moteurs de recherche (SERP), ainsi que l&amp;rsquo;image d&amp;rsquo;accroche (OGP) lors du partage sur les réseaux sociaux, il est possible d&amp;rsquo;augmenter intentionnellement le $CTR(R_i)$. Les paramètres SEO du frontmatter sont directement liés à cette maximisation du $CTR$.&lt;/p>
&lt;hr>
&lt;h2 id="2-le-processus-de-compilation-de-hugo-et-le-rôle-du-frontmatter">2. Le processus de compilation de Hugo et le rôle du frontmatter
&lt;/h2>&lt;p>Hugo lit le frontmatter (YAML/TOML/JSON) dans les fichiers Markdown et le transmet au moteur de template en tant que variables de page. Tout d&amp;rsquo;abord, comprenons visuellement ce flux d&amp;rsquo;informations.&lt;/p>
&lt;pre class="mermaid">
flowchart TD
A[&amp;#34;Fichier Markdown&amp;#34;] --&amp;gt; B[&amp;#34;Analyse du Frontmatter&amp;#34;]
A --&amp;gt; C[&amp;#34;Analyse du Contenu&amp;#34;]
B --&amp;gt; D[&amp;#34;Variables de Page Hugo (.Title, .Params)&amp;#34;]
C --&amp;gt; D
E[&amp;#34;layouts/partials/head.html&amp;#34;] --&amp;gt; F[&amp;#34;Moteur de Template Go&amp;#34;]
D --&amp;gt; F
F --&amp;gt; G[&amp;#34;Balise HTML &amp;lt;head&amp;gt; Finale&amp;#34;]
G --&amp;gt; H[&amp;#34;Googlebot / Robots d&amp;#39;exploration&amp;#34;]
G --&amp;gt; I[&amp;#34;Scrapers de Médias Sociaux (OGP)&amp;#34;]
&lt;/pre>
&lt;p>Ainsi, les valeurs définies dans le frontmatter sont transmises à &lt;code>head.html&lt;/code> en tant que variables telles que &lt;code>.Title&lt;/code> ou &lt;code>.Params.description&lt;/code>, et sont finalement affichées sous forme de métadonnées HTML. Par conséquent, le succès du SEO repose sur deux étapes : &amp;ldquo;définir les informations appropriées dans le frontmatter&amp;rdquo; et &amp;ldquo;les convertir correctement en HTML à l&amp;rsquo;aide de templates&amp;rdquo;.&lt;/p>
&lt;hr>
&lt;h2 id="3-configuration-des-métadonnées-de-base--titre-description-url-canonique">3. Configuration des métadonnées de base : Titre, Description, URL canonique
&lt;/h2>&lt;p>Les balises les plus fondamentales pour que les moteurs de recherche comprennent le contenu de la page sont &lt;code>&amp;lt;title&amp;gt;&lt;/code> et &lt;code>&amp;lt;meta name=&amp;quot;description&amp;quot;&amp;gt;&lt;/code>. De plus, &lt;code>&amp;lt;link rel=&amp;quot;canonical&amp;quot;&amp;gt;&lt;/code> est essentiel pour éviter les pénalités de contenu dupliqué.&lt;/p>
&lt;h3 id="31-exemple-de-configuration-du-frontmatter">3.1. Exemple de configuration du frontmatter
&lt;/h3>&lt;p>Nous préparons des champs dédiés au SEO dans le frontmatter de l&amp;rsquo;article.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nn">---&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">title&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;SEO pour les blogs Hugo : Paramètres du frontmatter pour augmenter considérablement le trafic&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">seo_title&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;Guide complet du SEO pour Hugo : Augmentez votre trafic avec le frontmatter&amp;#34;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># Optionnel : pour les moteurs de recherche&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">description&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;Méthodes avancées de SEO utilisant le frontmatter de Hugo. Explications détaillées sur la configuration de l&amp;#39;OGP, JSON-LD et des métadonnées.&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">slug&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;hugo-seo-frontmatter-tips&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">canonicalUrl&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;https://example.com/post/hugo-seo-frontmatter-tips/&amp;#34;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># URL canonique explicite&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nn">---&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="32-implémentation-de-layoutspartialsheadhtml">3.2. Implémentation de &lt;code>layouts/partials/head.html&lt;/code>
&lt;/h3>&lt;p>Nous créons un template HTML pour afficher correctement ces variables.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-html" data-lang="html">&lt;span class="line">&lt;span class="cl">&lt;span class="c">&amp;lt;!-- Optimisation du titre --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">{{ $title := .Title }}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">{{ if .Params.seo_title }}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> {{ $title = .Params.seo_title }}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">{{ end }}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">title&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>{{ $title }} | {{ .Site.Title }}&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">title&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&amp;lt;!-- Optimisation de la description --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">{{ $description := .Summary | plainify | truncate 120 }}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">{{ if .Params.description }}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> {{ $description = .Params.description }}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">{{ end }}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">meta&lt;/span> &lt;span class="na">name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;description&amp;#34;&lt;/span> &lt;span class="na">content&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;{{ $description }}&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&amp;lt;!-- URL canonique (Normalisation) --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">{{ $canonical := .Permalink }}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">{{ if .Params.canonicalUrl }}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> {{ $canonical = .Params.canonicalUrl }}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">{{ end }}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">link&lt;/span> &lt;span class="na">rel&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;canonical&amp;#34;&lt;/span> &lt;span class="na">href&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;{{ $canonical }}&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&amp;lt;!-- Contrôle des robots (ex. désactivation de l&amp;#39;indexation) --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">{{ if .Params.noindex }}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">meta&lt;/span> &lt;span class="na">name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;robots&amp;#34;&lt;/span> &lt;span class="na">content&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;noindex, nofollow&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">{{ else }}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">meta&lt;/span> &lt;span class="na">name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;robots&amp;#34;&lt;/span> &lt;span class="na">content&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;index, follow&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">{{ end }}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>En utilisant &lt;code>.Summary&lt;/code> de Hugo comme solution de repli, le texte d&amp;rsquo;introduction de l&amp;rsquo;article peut être extrait automatiquement même si &lt;code>description&lt;/code> n&amp;rsquo;est pas définie.&lt;/p>
&lt;hr>
&lt;h2 id="4-ogp-et-twitter-cards--maximiser-le-ctr-sur-les-réseaux-sociaux">4. OGP et Twitter Cards : Maximiser le CTR sur les réseaux sociaux
&lt;/h2>&lt;p>Lorsque des articles sont partagés sur des réseaux sociaux comme Twitter (X) ou Facebook, la configuration de l&amp;rsquo;Open Graph Protocol (OGP) et des Twitter Cards est indispensable pour les afficher sous la forme de cartes attrayantes. Celles-ci sont également générées dynamiquement à partir du frontmatter.&lt;/p>
&lt;h3 id="41-limites-du-template-intégré">4.1. Limites du template intégré
&lt;/h3>&lt;p>Hugo dispose d&amp;rsquo;un template intégré pratique &lt;code>{{ template &amp;quot;_internal/opengraph.html&amp;quot; . }}&lt;/code>, mais il manque de personnalisation et peut ne pas convenir à des environnements en japonais ou à des exigences spécifiques. Il est donc fortement recommandé d&amp;rsquo;implémenter vos propres balises OGP dans &lt;code>head.html&lt;/code>.&lt;/p>
&lt;h3 id="42-spécification-de-limage-dans-le-frontmatter">4.2. Spécification de l&amp;rsquo;image dans le frontmatter
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nn">---&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">image&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;img/eyecatch.jpg&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">images&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="s2">&amp;#34;img/eyecatch-large.jpg&amp;#34;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># Pour spécifier plusieurs images ou des chemins absolus&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nn">---&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="43-code-dimplémentation-personnalisé-pour-ogp-et-twitter-cards">4.3. Code d&amp;rsquo;implémentation personnalisé pour OGP et Twitter Cards
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-html" data-lang="html">&lt;span class="line">&lt;span class="cl">&lt;span class="c">&amp;lt;!-- Open Graph Protocol --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">meta&lt;/span> &lt;span class="na">property&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;og:title&amp;#34;&lt;/span> &lt;span class="na">content&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;{{ $title }}&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">meta&lt;/span> &lt;span class="na">property&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;og:description&amp;#34;&lt;/span> &lt;span class="na">content&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;{{ $description }}&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">meta&lt;/span> &lt;span class="na">property&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;og:type&amp;#34;&lt;/span> &lt;span class="na">content&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;{{ if .IsPage }}article{{ else }}website{{ end }}&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">meta&lt;/span> &lt;span class="na">property&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;og:url&amp;#34;&lt;/span> &lt;span class="na">content&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;{{ .Permalink }}&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">meta&lt;/span> &lt;span class="na">property&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;og:site_name&amp;#34;&lt;/span> &lt;span class="na">content&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;{{ .Site.Title }}&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&amp;lt;!-- Résolution de l&amp;#39;image OGP --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">{{ $ogImage := &amp;#34;&amp;#34; }}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">{{ if .Params.image }}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> {{ $ogImage = .Params.image | absURL }}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">{{ else if .Params.images }}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> {{ $ogImage = index .Params.images 0 | absURL }}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">{{ else if .Site.Params.defaultImage }}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> {{ $ogImage = .Site.Params.defaultImage | absURL }}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">{{ end }}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">{{ if $ogImage }}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">meta&lt;/span> &lt;span class="na">property&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;og:image&amp;#34;&lt;/span> &lt;span class="na">content&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;{{ $ogImage }}&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">meta&lt;/span> &lt;span class="na">name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;twitter:image&amp;#34;&lt;/span> &lt;span class="na">content&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;{{ $ogImage }}&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">meta&lt;/span> &lt;span class="na">name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;twitter:card&amp;#34;&lt;/span> &lt;span class="na">content&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;summary_large_image&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">{{ else }}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">meta&lt;/span> &lt;span class="na">name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;twitter:card&amp;#34;&lt;/span> &lt;span class="na">content&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;summary&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">{{ end }}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&amp;lt;!-- Twitter Cards --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">meta&lt;/span> &lt;span class="na">name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;twitter:title&amp;#34;&lt;/span> &lt;span class="na">content&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;{{ $title }}&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">meta&lt;/span> &lt;span class="na">name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;twitter:description&amp;#34;&lt;/span> &lt;span class="na">content&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;{{ $description }}&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">{{ if .Site.Params.twitterAccount }}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">meta&lt;/span> &lt;span class="na">name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;twitter:site&amp;#34;&lt;/span> &lt;span class="na">content&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;@{{ .Site.Params.twitterAccount }}&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">{{ end }}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>En appliquant la fonction &lt;code>absURL&lt;/code>, l&amp;rsquo;URL de l&amp;rsquo;image spécifiée avec un chemin relatif est convertie en un chemin absolu. Ce traitement est extrêmement important car les chemins absolus sont obligatoires dans l&amp;rsquo;OGP.&lt;/p>
&lt;hr>
&lt;h2 id="5-implémentation-des-données-structurées-json-ld">5. Implémentation des données structurées (JSON-LD)
&lt;/h2>&lt;p>Dans le SEO actuel, &lt;strong>JSON-LD (JavaScript Object Notation for Linked Data)&lt;/strong> est devenu la norme pour communiquer avec précision la structure sémantique d&amp;rsquo;une page aux moteurs de recherche. Sa configuration facilite l&amp;rsquo;apparition d&amp;rsquo;extraits enrichis (rich snippets : évaluations par étoiles, nom de l&amp;rsquo;auteur, date de publication, etc.) dans les résultats de recherche.&lt;/p>
&lt;h3 id="51-structure-du-json-ld">5.1. Structure du JSON-LD
&lt;/h3>&lt;p>Pour les articles de blog, nous implémentons principalement deux schémas : le schéma &lt;code>Article&lt;/code> (Article) et le schéma &lt;code>BreadcrumbList&lt;/code> (Fil d&amp;rsquo;Ariane).&lt;/p>
&lt;pre class="mermaid">
flowchart TD
A[&amp;#34;Définitions Schema.org&amp;#34;] --&amp;gt; B[&amp;#34;Schéma Article&amp;#34;]
A --&amp;gt; C[&amp;#34;Schéma BreadcrumbList&amp;#34;]
B --&amp;gt; D[&amp;#34;headline&amp;#34;]
B --&amp;gt; E[&amp;#34;datePublished&amp;#34;]
B --&amp;gt; F[&amp;#34;dateModified&amp;#34;]
B --&amp;gt; G[&amp;#34;author&amp;#34;]
B --&amp;gt; H[&amp;#34;image&amp;#34;]
C --&amp;gt; I[&amp;#34;Élément de liste 1&amp;#34;]
C --&amp;gt; J[&amp;#34;Élément de liste 2&amp;#34;]
I --&amp;gt; K[&amp;#34;position: 1&amp;#34;]
I --&amp;gt; L[&amp;#34;name: Accueil&amp;#34;]
J --&amp;gt; M[&amp;#34;position: 2&amp;#34;]
J --&amp;gt; N[&amp;#34;name: Catégorie / Blog&amp;#34;]
&lt;/pre>
&lt;h3 id="52-génération-de-json-ld-avec-les-templates-hugo">5.2. Génération de JSON-LD avec les templates Hugo
&lt;/h3>&lt;p>Nous utilisons des variables telles que &lt;code>.Date&lt;/code> et &lt;code>.Lastmod&lt;/code> du frontmatter pour afficher dynamiquement le JSON-LD. Il s&amp;rsquo;écrit dans &lt;code>head.html&lt;/code> en utilisant la balise &lt;code>&amp;lt;script type=&amp;quot;application/ld+json&amp;quot;&amp;gt;&lt;/code>.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;span class="lnt">40
&lt;/span>&lt;span class="lnt">41
&lt;/span>&lt;span class="lnt">42
&lt;/span>&lt;span class="lnt">43
&lt;/span>&lt;span class="lnt">44
&lt;/span>&lt;span class="lnt">45
&lt;/span>&lt;span class="lnt">46
&lt;/span>&lt;span class="lnt">47
&lt;/span>&lt;span class="lnt">48
&lt;/span>&lt;span class="lnt">49
&lt;/span>&lt;span class="lnt">50
&lt;/span>&lt;span class="lnt">51
&lt;/span>&lt;span class="lnt">52
&lt;/span>&lt;span class="lnt">53
&lt;/span>&lt;span class="lnt">54
&lt;/span>&lt;span class="lnt">55
&lt;/span>&lt;span class="lnt">56
&lt;/span>&lt;span class="lnt">57
&lt;/span>&lt;span class="lnt">58
&lt;/span>&lt;span class="lnt">59
&lt;/span>&lt;span class="lnt">60
&lt;/span>&lt;span class="lnt">61
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-html" data-lang="html">&lt;span class="line">&lt;span class="cl">{{ if .IsPage }}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">script&lt;/span> &lt;span class="na">type&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;application/ld+json&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;@context&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;https://schema.org&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;@type&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;Article&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;mainEntityOfPage&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;@type&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;WebPage&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;@id&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;{{ .Permalink }}&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;headline&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;{{ .Title | htmlEscape }}&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;description&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;{{ $description | htmlEscape }}&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;image&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;{{ $ogImage }}&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;datePublished&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;{{ .Date.Format &amp;#34;&lt;/span>&lt;span class="mi">2006&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">01&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">02&lt;/span>&lt;span class="nx">T15&lt;/span>&lt;span class="o">:&lt;/span>&lt;span class="mi">04&lt;/span>&lt;span class="o">:&lt;/span>&lt;span class="mi">05&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">07&lt;/span>&lt;span class="o">:&lt;/span>&lt;span class="mi">00&lt;/span>&lt;span class="s2">&amp;#34; }}&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;dateModified&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;{{ .Lastmod.Format &amp;#34;&lt;/span>&lt;span class="mi">2006&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">01&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">02&lt;/span>&lt;span class="nx">T15&lt;/span>&lt;span class="o">:&lt;/span>&lt;span class="mi">04&lt;/span>&lt;span class="o">:&lt;/span>&lt;span class="mi">05&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">07&lt;/span>&lt;span class="o">:&lt;/span>&lt;span class="mi">00&lt;/span>&lt;span class="s2">&amp;#34; }}&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;author&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;@type&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;Person&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;{{ if .Params.author }}{{ .Params.author }}{{ else }}{{ .Site.Params.author }}{{ end }}&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;publisher&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;@type&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;Organization&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;{{ .Site.Title }}&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;logo&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;@type&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;ImageObject&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;url&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;{{ .Site.Params.logo | absURL }}&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">script&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&amp;lt;!-- Schéma BreadcrumbList --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">script&lt;/span> &lt;span class="na">type&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;application/ld+json&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;@context&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;https://schema.org&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;@type&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;BreadcrumbList&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;itemListElement&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;@type&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;ListItem&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;position&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;Home&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;item&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;{{ .Site.BaseURL }}&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{{&lt;/span> &lt;span class="nx">$position&lt;/span> &lt;span class="o">:=&lt;/span> &lt;span class="mi">2&lt;/span> &lt;span class="p">}}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{{&lt;/span> &lt;span class="nx">range&lt;/span> &lt;span class="p">.&lt;/span>&lt;span class="nx">Params&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">categories&lt;/span> &lt;span class="p">}}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">,{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;@type&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;ListItem&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;position&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="p">{{&lt;/span> &lt;span class="nx">$position&lt;/span> &lt;span class="p">}},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;{{ . }}&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;item&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;{{ &amp;#34;&lt;/span>&lt;span class="nx">categories&lt;/span>&lt;span class="o">/&lt;/span>&lt;span class="s2">&amp;#34; | relLangURL }}{{ . | urlize | lower }}/&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{{&lt;/span> &lt;span class="nx">$position&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">add&lt;/span> &lt;span class="nx">$position&lt;/span> &lt;span class="mi">1&lt;/span> &lt;span class="p">}}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{{&lt;/span> &lt;span class="nx">end&lt;/span> &lt;span class="p">}}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">,{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;@type&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;ListItem&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;position&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="p">{{&lt;/span> &lt;span class="nx">$position&lt;/span> &lt;span class="p">}},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;{{ .Title | htmlEscape }}&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;item&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;{{ .Permalink }}&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">script&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">{{ end }}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Lors du déploiement de chaînes de caractères dans JSON-LD, il est important d&amp;rsquo;utiliser &lt;code>htmlEscape&lt;/code> (ou &lt;code>jsonify&lt;/code>) pour éviter la destruction par des guillemets doubles. Cela permet d&amp;rsquo;éviter les erreurs de syntaxe JSON, quels que soient les symboles utilisés dans le frontmatter.&lt;/p>
&lt;hr>
&lt;h2 id="6-techniques-dutilisation-avancées-du-frontmatter">6. Techniques d&amp;rsquo;utilisation avancées du frontmatter
&lt;/h2>&lt;p>En plus des métadonnées SEO de base, le frontmatter de Hugo propose des fonctionnalités permettant de mettre en œuvre des stratégies SEO encore plus avancées.&lt;/p>
&lt;h3 id="61-traitement-des-redirections-via-les-alias-aliases">6.1. Traitement des redirections via les alias (Aliases)
&lt;/h3>&lt;p>Lorsque vous migrez vers Hugo à partir d&amp;rsquo;un ancien service de blog ou que vous modifiez la structure des permaliens, vous devez rediriger le trafic des anciennes URL vers les nouvelles. En utilisant le champ &lt;code>aliases&lt;/code> de Hugo, vous pouvez générer automatiquement des pages d&amp;rsquo;actualisation HTTP-Equiv (redirection meta) pour les anciennes URL.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nn">---&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">title&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;Nouveau titre de l&amp;#39;article&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">slug&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;new-seo-post&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">aliases&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="s2">&amp;#34;/old-category/old-seo-post/&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="s2">&amp;#34;/2020/05/12/seo-tips/&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nn">---&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="62-date-dexpiration-et-planification-des-articles">6.2. Date d&amp;rsquo;expiration et planification des articles
&lt;/h3>&lt;p>Pour les articles de campagnes à durée limitée ou les informations qui perdent de leur valeur en vieillissant, la définition d&amp;rsquo;une date d&amp;rsquo;expiration &lt;code>expiryDate&lt;/code> permet de les exclure des résultats de compilation après une date et une heure spécifiques, afin qu&amp;rsquo;elles ne s&amp;rsquo;affichent plus sur le site (en renvoyant une erreur 404). Cela évite que du contenu ancien de mauvaise qualité ne reste dans l&amp;rsquo;indexation et ne diminue l&amp;rsquo;évaluation globale du site.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nn">---&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">title&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;Techniques SEO exclusives à 2026&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">publishDate&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;2026-01-01T00:00:00Z&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">expiryDate&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;2026-12-31T23:59:59Z&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nn">---&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;hr>
&lt;h2 id="7-performances-du-site-et-core-web-vitals">7. Performances du site et Core Web Vitals
&lt;/h2>&lt;p>En SEO, la &lt;strong>vitesse de chargement de la page&lt;/strong> est tout aussi importante que l&amp;rsquo;optimisation des balises. Google a intégré les Core Web Vitals (LCP, FID/INP, CLS) en tant que facteurs de classement.&lt;/p>
&lt;p>Hugo, en tant que site statique, a naturellement un excellent TTFB (Time to First Byte), mais pour les blogs utilisant beaucoup d&amp;rsquo;images, l&amp;rsquo;optimisation de ces dernières est indispensable. En combinant les puissantes fonctionnalités de traitement d&amp;rsquo;images de Hugo (Image Processing) avec le frontmatter, vous pouvez automatiser la conversion vers des formats de nouvelle génération (comme WebP) et le redimensionnement lors de la compilation.&lt;/p>
&lt;p>Par exemple, il est possible de créer un shortcode qui génère automatiquement des images WebP du côté du template à partir du chemin de l&amp;rsquo;image spécifié dans le frontmatter. Cela peut améliorer considérablement l&amp;rsquo;évaluation SEO.&lt;/p>
&lt;hr>
&lt;h2 id="8-conclusion">8. Conclusion
&lt;/h2>&lt;p>Lors de la gestion d&amp;rsquo;un blog avec Hugo, le frontmatter n&amp;rsquo;est pas seulement une &amp;ldquo;liste de paramètres&amp;rdquo;, mais un &amp;ldquo;panneau de contrôle&amp;rdquo; pour dialoguer avec les moteurs de recherche et les réseaux sociaux.&lt;/p>
&lt;p>En mettant parfaitement en œuvre les points expliqués dans cet article, les bases SEO de votre blog deviendront solides.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Génération dynamique des métadonnées de base&lt;/strong> : Affichage fiable du Titre, de la Description et du Canonical.&lt;/li>
&lt;li>&lt;strong>Optimisation du partage social&lt;/strong> : Amélioration du CTR grâce à l&amp;rsquo;implémentation personnalisée de l&amp;rsquo;OGP et des Twitter Cards.&lt;/li>
&lt;li>&lt;strong>Prise en charge complète des données structurées&lt;/strong> : Compatibilité avec les résultats enrichis grâce à JSON-LD (Article, Breadcrumb).&lt;/li>
&lt;li>&lt;strong>Gestion avancée du trafic&lt;/strong> : Redirections avec Aliases et contrôle des robots avec des balises meta.&lt;/li>
&lt;/ol>
&lt;p>Bien que les algorithmes des moteurs de recherche évoluent de jour en jour, le principe fondamental du SEO, qui est de fournir des signaux pour que les moteurs de recherche &amp;ldquo;comprennent correctement le contenu de la page&amp;rdquo;, reste inchangé. En maîtrisant le moteur de templates flexible et le frontmatter de Hugo, continuez d&amp;rsquo;émettre ces signaux avec la plus haute qualité et augmentez considérablement le trafic vers votre blog.&lt;/p></description></item><item><title>Stratégie de réécriture d'articles techniques passés à l'aide de Google Search Console</title><link>http://kenji.blog/fr/p/google-search-console-rewrite-strategy/</link><pubDate>Sat, 12 Sep 2026 12:00:00 +0900</pubDate><guid>http://kenji.blog/fr/p/google-search-console-rewrite-strategy/</guid><description>&lt;img src="http://kenji.blog/p/google-search-console-rewrite-strategy/img/eyecatch.jpg" alt="Featured image of post Stratégie de réécriture d'articles techniques passés à l'aide de Google Search Console" />&lt;h2 id="1-introduction--limportance-de-la-réécriture-dans-les-blogs-techniques-et-lapproche-axée-sur-les-données">1. Introduction : L&amp;rsquo;importance de la réécriture dans les blogs techniques et l&amp;rsquo;approche axée sur les données
&lt;/h2>&lt;p>Lors de la gestion d&amp;rsquo;un blog technique ou d&amp;rsquo;un média propriétaire pour les développeurs, la réécriture d&amp;rsquo;articles passés est tout aussi importante, voire plus, que la rédaction continue de nouveaux articles. En particulier pour les sujets liés à l&amp;rsquo;informatique et à la technologie, l&amp;rsquo;information devient rapidement obsolète, et il n&amp;rsquo;est pas rare que des extraits de code ou des spécifications d&amp;rsquo;API écrits il y a quelques années soient désormais obsolètes (Deprecated). Cependant, le simple fait de mettre à jour aveuglément les articles passés ne permet pas de maximiser le trafic (afflux) en provenance des moteurs de recherche.&lt;/p>
&lt;p>Dans cet article, nous utiliserons les données de &lt;strong>Google Search Console (GSC)&lt;/strong> et &lt;strong>Google Analytics 4 (GA4)&lt;/strong>, et emploierons une approche basée sur les données et mathématique pour identifier les articles techniques qui doivent être réécrits. Nous expliquerons une stratégie avancée pour améliorer considérablement le classement de recherche et le taux de clics (CTR).&lt;/p>
&lt;p>Plus précisément, de l&amp;rsquo;intégration des données de GSC et GA4 à l&amp;rsquo;aide de Python et BigQuery pour découvrir des « articles d&amp;rsquo;opportunité perdue » avec un CTR faible par rapport aux impressions (nombre d&amp;rsquo;affichages), jusqu&amp;rsquo;à l&amp;rsquo;utilisation de l&amp;rsquo;analyse TF-IDF de la NLP (traitement du langage naturel) pour identifier les mots-clés manquants dans les titres H2 ou H3, nous couvrirons de manière exhaustive les méthodes pour combler efficacement les lacunes de contenu.&lt;/p>
&lt;hr>
&lt;h2 id="2-analyse-de-lécart-entre-le-ctr-attendu-et-le-ctr-réel-introduction-de-modèles-mathématiques">2. Analyse de l&amp;rsquo;écart entre le CTR attendu et le CTR réel (Introduction de modèles mathématiques)
&lt;/h2>&lt;p>L&amp;rsquo;un des indicateurs les plus fondamentaux du SEO est le « taux de clics par rapport au classement de recherche (CTR) ». En général, la nature est que le CTR est d&amp;rsquo;environ 25 à 30 % pour un classement de recherche de 1ère place, d&amp;rsquo;environ 15 % pour la 2ème place, et diminue fortement par la suite. Cette relation entre le classement et le CTR peut être modélisée comme une distribution obéissant à une loi de puissance (Power Law).&lt;/p>
&lt;p>On sait que le taux de clics attendu $CTR(r)$ pour le classement $r$ est approximé par la formule suivante :&lt;/p>
$$
CTR(r) = a \cdot r^{-b}
$$&lt;p>Ici, $a$ représente le CTR attendu à la 1ère place (par exemple : $0.30$ pour 30 %), et $b$ représente le paramètre d&amp;rsquo;atténuation (généralement entre $1.0$ et $1.5$).&lt;/p>
&lt;p>L&amp;rsquo;approche la plus efficace lors de la sélection des articles cibles pour la réécriture est de &lt;strong>trouver les articles (mots-clés) dont le « CTR réel » est nettement inférieur à ce « CTR attendu »&lt;/strong>. Par exemple, si le classement de recherche est 3ème (CTR attendu d&amp;rsquo;environ 10 %) mais que le CTR réel n&amp;rsquo;est que de 2 %, il est fort probable qu&amp;rsquo;il y ait un décalage entre l&amp;rsquo;intention de recherche et le titre/la description, ou que les clics soient volés par des facteurs concurrentiels tels que les extraits enrichis (rich snippets).&lt;/p>
&lt;p>Le graphique ci-dessous est une image montrant l&amp;rsquo;écart entre le CTR attendu et le CTR réel dans un certain blog technique.&lt;/p>
&lt;pre class="mermaid">
xychart-beta
title CTR attendu vs CTR réel par position
x-axis [&amp;#34;1&amp;#34;, &amp;#34;2&amp;#34;, &amp;#34;3&amp;#34;, &amp;#34;4&amp;#34;, &amp;#34;5&amp;#34;, &amp;#34;6&amp;#34;, &amp;#34;7&amp;#34;, &amp;#34;8&amp;#34;, &amp;#34;9&amp;#34;, &amp;#34;10&amp;#34;]
y-axis &amp;#34;CTR (%)&amp;#34; 0 --&amp;gt; 35
line [30.5, 15.2, 10.1, 7.5, 5.2, 4.1, 3.2, 2.5, 2.0, 1.5]
bar [32.1, 14.0, 8.5, 4.0, 5.0, 2.1, 1.5, 1.0, 1.2, 0.5]
&lt;/pre>
&lt;p>(※ Le graphique linéaire indique le CTR attendu et le graphique à barres indique le CTR réel. On peut constater qu&amp;rsquo;il est nettement inférieur aux 4ème et 8ème places.)&lt;/p>
&lt;hr>
&lt;h2 id="3-extraction-automatique-des-données-de-performances-de-recherche-à-laide-de-lapi-gsc-python">3. Extraction automatique des données de performances de recherche à l&amp;rsquo;aide de l&amp;rsquo;API GSC (Python)
&lt;/h2>&lt;p>Bien qu&amp;rsquo;il soit possible de télécharger des fichiers CSV à partir de l&amp;rsquo;interface Web de GSC pour les analyser, pour les blogs à grande échelle ou les analyses continues, il est préférable de créer un système pour extraire automatiquement les données avec Python à l&amp;rsquo;aide de l&amp;rsquo;API GSC.&lt;/p>
&lt;p>Vous trouverez ci-dessous un extrait Python utilisant &lt;code>google-api-python-client&lt;/code> pour obtenir les données de performances (clics, impressions, CTR, position moyenne) par page et par requête pour une période donnée.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;span class="lnt">40
&lt;/span>&lt;span class="lnt">41
&lt;/span>&lt;span class="lnt">42
&lt;/span>&lt;span class="lnt">43
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">pandas&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="nn">pd&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">google.oauth2&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">service_account&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">googleapiclient.discovery&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">build&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">get_gsc_data&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">key_path&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">site_url&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">start_date&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">end_date&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Chargement des informations d&amp;#39;identification et construction du client API&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">credentials&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">service_account&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">Credentials&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">from_service_account_file&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">key_path&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">scopes&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;https://www.googleapis.com/auth/webmasters.readonly&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">service&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">build&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;searchconsole&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;v1&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">credentials&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">credentials&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Configuration de la charge utile de la requête API (spécification de la page et de la requête comme dimensions)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">request&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;startDate&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">start_date&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;endDate&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">end_date&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;dimensions&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;page&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;query&amp;#39;&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;rowLimit&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">25000&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Exécution de l&amp;#39;API&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">response&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">service&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">searchanalytics&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">query&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">siteUrl&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">site_url&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">body&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">request&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">execute&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Extraction des données à partir de la réponse et conversion en Pandas DataFrame&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">rows&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">response&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;rows&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="p">[])&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">data&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">row&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">rows&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">keys&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">row&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;keys&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">data&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">append&lt;/span>&lt;span class="p">({&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;page&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">keys&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;query&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">keys&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;clicks&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">row&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;clicks&amp;#39;&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;impressions&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">row&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;impressions&amp;#39;&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;ctr&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">row&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;ctr&amp;#39;&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;position&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">row&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;position&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">})&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">pd&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">DataFrame&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Exemple d&amp;#39;exécution&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># df_gsc = get_gsc_data(&amp;#39;credentials.json&amp;#39;, &amp;#39;https://kenji.blog/&amp;#39;, &amp;#39;2026-08-01&amp;#39;, &amp;#39;2026-08-31&amp;#39;)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># print(df_gsc.head())&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Avec ce script, vous pouvez obtenir des données détaillées liées aux URL de page et aux requêtes de recherche sous forme de DataFrame. Cela permet de comprendre de manière exhaustive avec quels mots-clés un article spécifique est affiché.&lt;/p>
&lt;hr>
&lt;h2 id="4-filtrage-des-mots-clés-techniques-à-laide-dexpressions-régulières-regex">4. Filtrage des mots-clés techniques à l&amp;rsquo;aide d&amp;rsquo;expressions régulières (Regex)
&lt;/h2>&lt;p>Une fonctionnalité très puissante dans l&amp;rsquo;analyse de blogs techniques est le &lt;strong>filtre d&amp;rsquo;expression régulière (Regex)&lt;/strong> de GSC.
Par exemple, si vous écrivez des articles sur un large éventail de sujets, du front-end au back-end en passant par l&amp;rsquo;infrastructure, vous voudrez peut-être extraire uniquement les « articles sur les erreurs ou tutoriels concernant Python ou Pandas » pour déterminer la priorité de réécriture.&lt;/p>
&lt;p>À l&amp;rsquo;aide des filtres d&amp;rsquo;expressions régulières personnalisés de GSC, vous pouvez affiner les requêtes avec des conditions complexes.&lt;/p>
&lt;p>&lt;strong>Exemples réels de filtrage de mots-clés techniques :&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>Enquête sur les erreurs liées à Python : &lt;code>^(python|pandas|numpy|matplotlib).* (error|exception|bug|erreur|panne)&lt;/code>&lt;/li>
&lt;li>Construction d&amp;rsquo;infrastructure liée à AWS : &lt;code>(aws|amazon web services|ec2|s3|lambda).* (construction|configuration|tutoriel|tutorial|how to)&lt;/code>&lt;/li>
&lt;li>Mise à jour de version d&amp;rsquo;une bibliothèque spécifique : &lt;code>(react|vue|angular) (v17|v18|v3) (migration|mise à niveau|transition)&lt;/code>&lt;/li>
&lt;/ul>
&lt;p>Lors de l&amp;rsquo;intégration de cela dans une requête API GSC, utilisez &lt;code>dimensionFilterGroups&lt;/code> pour appliquer des conditions d&amp;rsquo;expression régulière. En utilisant pleinement ce filtrage, vous pouvez extraire précisément des mots-clés de type résolution de problèmes de grande valeur pour lesquels les développeurs « cherchent des solutions parce qu&amp;rsquo;ils sont bloqués en ce moment ».&lt;/p>
&lt;hr>
&lt;h2 id="5-intégration-des-données-ga4-et-gsc-avec-bigquerypandas">5. Intégration des données GA4 et GSC avec BigQuery/Pandas
&lt;/h2>&lt;p>Les données GSC seules ne fournissent que le « classement de recherche et le taux de clics ». Pour savoir « combien de temps les utilisateurs qui sont arrivés sur cet article y sont restés et s&amp;rsquo;ils ont converti (par exemple, passage à un dépôt GitHub, abonnement à une newsletter, etc.) », vous devez les intégrer (JOIN) avec les données de &lt;strong>Google Analytics 4 (GA4)&lt;/strong>.&lt;/p>
&lt;p>Si vous stockez les données d&amp;rsquo;exportation de GA4 et les données d&amp;rsquo;exportation en masse de GSC dans BigQuery, vous pouvez utiliser une requête SQL comme la suivante pour combiner les deux et extraire les articles avec « beaucoup d&amp;rsquo;impressions et un classement de recherche décent, mais avec un taux de rebond élevé ou un temps d&amp;rsquo;engagement court ».&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;span class="lnt">40
&lt;/span>&lt;span class="lnt">41
&lt;/span>&lt;span class="lnt">42
&lt;/span>&lt;span class="lnt">43
&lt;/span>&lt;span class="lnt">44
&lt;/span>&lt;span class="lnt">45
&lt;/span>&lt;span class="lnt">46
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-sql" data-lang="sql">&lt;span class="line">&lt;span class="cl">&lt;span class="k">WITH&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">gsc_data&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">AS&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">SELECT&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">url&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">AS&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">page_path&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">SUM&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">impressions&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">AS&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">total_impressions&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">SUM&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">clicks&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">AS&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">total_clicks&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">AVG&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">sum_top_position&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">AS&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">avg_position&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">FROM&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="o">`&lt;/span>&lt;span class="n">project&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">searchconsole&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">searchdata_url_impression&lt;/span>&lt;span class="o">`&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">WHERE&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">data_date&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">BETWEEN&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;2026-08-01&amp;#39;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">AND&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;2026-08-31&amp;#39;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">GROUP&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">BY&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">url&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">),&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="n">ga4_data&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">AS&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">SELECT&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">REGEXP_REPLACE&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">SELECT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">value&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">string_value&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">FROM&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">UNNEST&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">event_params&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">WHERE&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">key&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;page_location&amp;#39;&lt;/span>&lt;span class="p">),&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">r&lt;/span>&lt;span class="s1">&amp;#39;^https?://[^/]+&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;&amp;#39;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">AS&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">page_path&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">COUNT&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">DISTINCT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">user_pseudo_id&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">AS&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">users&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">AVG&lt;/span>&lt;span class="p">((&lt;/span>&lt;span class="k">SELECT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">value&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">int_value&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">FROM&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">UNNEST&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">event_params&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">WHERE&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">key&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;engagement_time_msec&amp;#39;&lt;/span>&lt;span class="p">))&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">/&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="mi">1000&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">AS&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">avg_engagement_sec&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">FROM&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="o">`&lt;/span>&lt;span class="n">project&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">analytics_123456789&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">events_&lt;/span>&lt;span class="o">*`&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">WHERE&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">event_name&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;page_view&amp;#39;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">GROUP&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">BY&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">page_path&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="k">SELECT&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">g&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">page_path&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">g&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">total_impressions&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">g&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">total_clicks&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">SAFE_DIVIDE&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">g&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">total_clicks&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">g&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">total_impressions&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">AS&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">ctr&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">g&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">avg_position&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">a&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">users&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">a&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">avg_engagement_sec&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="k">FROM&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">gsc_data&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">g&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="k">JOIN&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">ga4_data&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">a&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">ON&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">g&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">page_path&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">a&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">page_path&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="k">WHERE&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">g&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">total_impressions&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="mi">1000&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">AND&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">g&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">avg_position&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">BETWEEN&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="mi">3&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">AND&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="mi">15&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="k">ORDER&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">BY&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">g&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">total_impressions&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">DESC&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>En utilisant ce résultat, nous classerons les cibles de réécriture avec la matrice suivante.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>High Impression, Low CTR, High Engagement&lt;/strong> :
Tant qu&amp;rsquo;il est cliqué dans les résultats de recherche, les lecteurs sont satisfaits de l&amp;rsquo;article. La priorité absolue doit être donnée à la &lt;strong>correction du titre et de la méta description&lt;/strong> uniquement.&lt;/li>
&lt;li>&lt;strong>High CTR, Low Engagement&lt;/strong> :
Il reçoit des clics, mais le contenu déçoit et les utilisateurs quittent la page. Une réécriture majeure du corps de l&amp;rsquo;article est nécessaire, comme &lt;strong>l&amp;rsquo;amélioration de l&amp;rsquo;introduction, la mise à jour avec le code le plus récent et l&amp;rsquo;amélioration de l&amp;rsquo;exhaustivité des informations (ajout de H2/H3)&lt;/strong>.&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="6-analyse-des-lacunes-de-contenu-avec-la-nlp-et-le-tf-idf">6. Analyse des lacunes de contenu avec la NLP et le TF-IDF
&lt;/h2>&lt;p>Une fois les articles à réécrire identifiés, la prochaine étape est d&amp;rsquo;analyser « quels titres (H2/H3) et mots-clés spécifiques devraient être ajoutés ». Ici aussi, au lieu de nous fier à l&amp;rsquo;intuition, nous utiliserons le &lt;strong>TF-IDF (Term Frequency-Inverse Document Frequency) en traitement du langage naturel (NLP)&lt;/strong>.&lt;/p>
&lt;p>Le TF-IDF est une statistique permettant d&amp;rsquo;évaluer l&amp;rsquo;importance d&amp;rsquo;un mot au sein d&amp;rsquo;un document.&lt;/p>
$$
TF\text{-}IDF(t, d) = tf(t, d) \times \log\left(\frac{N}{df(t)}\right)
$$&lt;p>Où,&lt;/p>
&lt;ul>
&lt;li>$tf(t, d)$ est la fréquence d&amp;rsquo;apparition du mot $t$ dans le document $d$&lt;/li>
&lt;li>$N$ est le nombre total de documents&lt;/li>
&lt;li>$df(t)$ est le nombre de documents dans lesquels le mot $t$ apparaît&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>Approche :&lt;/strong>&lt;/p>
&lt;ol>
&lt;li>Obtenez les données textuelles des 10 meilleurs articles (sites concurrents) pour le mot-clé cible, via le web scraping par exemple.&lt;/li>
&lt;li>Préparez les données textuelles de l&amp;rsquo;article cible de votre propre site.&lt;/li>
&lt;li>À l&amp;rsquo;aide du &lt;code>TfidfVectorizer&lt;/code> de &lt;code>scikit-learn&lt;/code> en Python, extrayez les mots-clés (mots caractéristiques) qui apparaissent avec un score élevé en commun parmi les meilleurs articles concurrents, mais qui n&amp;rsquo;existent pas dans l&amp;rsquo;article de votre site, ou qui ont un score significativement plus bas.&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">sklearn.feature_extraction.text&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">TfidfVectorizer&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">pandas&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="nn">pd&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">numpy&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="nn">np&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># documents = [Texte de votre propre site, Texte de l&amp;#39;article concurrent 1, Texte de l&amp;#39;article concurrent 2, ...]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Ici, nous supposons une liste de textes qui ont déjà été tokenisés pour l&amp;#39;analyse morphologique (MeCab, etc.)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">extract_missing_keywords&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">documents&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">vectorizer&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">TfidfVectorizer&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">max_df&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mf">0.9&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">min_df&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">tfidf_matrix&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">vectorizer&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">fit_transform&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">documents&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">feature_names&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">vectorizer&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get_feature_names_out&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Calculer le score TF-IDF moyen des articles concurrents (index 1 et suivants)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">competitor_mean_tfidf&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">np&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">mean&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">tfidf_matrix&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">:]&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">toarray&lt;/span>&lt;span class="p">(),&lt;/span> &lt;span class="n">axis&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Obtenir le score TF-IDF de l&amp;#39;article de votre propre site (index 0)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">my_article_tfidf&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">tfidf_matrix&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">toarray&lt;/span>&lt;span class="p">()[&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Calculer l&amp;#39;écart des mots qui sont importants pour les concurrents, mais absents (ou rares) sur votre site&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">gap_scores&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">competitor_mean_tfidf&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">my_article_tfidf&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Extraire les meilleurs mots avec un écart important&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">df_gap&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">pd&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">DataFrame&lt;/span>&lt;span class="p">({&lt;/span>&lt;span class="s1">&amp;#39;keyword&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">feature_names&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;gap_score&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">gap_scores&lt;/span>&lt;span class="p">})&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">df_gap&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">df_gap&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">sort_values&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">by&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;gap_score&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">ascending&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">False&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">df_gap&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">head&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">20&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Exemple : missing_keywords = extract_missing_keywords(processed_docs)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># print(missing_keywords)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Grâce à cette analyse, vous pouvez découvrir quantitativement &lt;strong>des omissions de sujets (lacunes de contenu)&lt;/strong>, comme « En fait, les meilleurs articles mentionnent également &amp;lsquo;comment déployer sur des conteneurs Docker&amp;rsquo; et &amp;rsquo;la construction de pipelines CI/CD&amp;rsquo;, mais mon article ne l&amp;rsquo;aborde pas ».&lt;/p>
&lt;p>Au lieu de simplement disperser les mots-clés importants découverts dans le texte, l&amp;rsquo;ajout de sections significatives en tant que &lt;strong>titres H2 ou H3 (balises de titre)&lt;/strong> et la rédaction d&amp;rsquo;explications techniques détaillées et d&amp;rsquo;extraits de code pour ces titres peuvent améliorer considérablement l&amp;rsquo;évaluation de Google.&lt;/p>
&lt;hr>
&lt;h2 id="7-pipeline-de-données-et-cycle-damélioration-continue">7. Pipeline de données et cycle d&amp;rsquo;amélioration continue
&lt;/h2>&lt;p>Les processus expliqués jusqu&amp;rsquo;à présent ne sont pas quelque chose que vous faites une fois et que vous terminez. En faire un pipeline et l&amp;rsquo;exécuter en continu est la clé du succès SEO. L&amp;rsquo;architecture globale et le flux opérationnel sont présentés ci-dessous dans un organigramme Mermaid.&lt;/p>
&lt;pre class="mermaid">
flowchart TD
A[&amp;#34;Données de l&amp;#39;API GSC (Impressions, Clics, Positions)&amp;#34;] --&amp;gt; C[&amp;#34;BigQuery / Entrepôt de données&amp;#34;]
B[&amp;#34;Données d&amp;#39;exportation GA4 (Pages vues, Temps d&amp;#39;engagement)&amp;#34;] --&amp;gt; C
C --&amp;gt; D[&amp;#34;Jointure et analyse de données avec Python / Pandas&amp;#34;]
D --&amp;gt; E[&amp;#34;Identifier les articles à fortes impressions / faible CTR&amp;#34;]
E --&amp;gt; F[&amp;#34;Scraping des concurrents NLP et extraction de mots-clés TF-IDF&amp;#34;]
F --&amp;gt; G[&amp;#34;Optimiser les balises H2/H3 et réécrire le contenu&amp;#34;]
G --&amp;gt; H[&amp;#34;Publier l&amp;#39;article mis à jour&amp;#34;]
H --&amp;gt; I[&amp;#34;Surveiller les changements de CTR (Attendu vs Réel)&amp;#34;]
I --&amp;gt; |&amp;#34;Boucle de rétroaction&amp;#34;| A
&lt;/pre>
&lt;p>En systématisant cette série d&amp;rsquo;étapes : de la collecte de données à partir de GSC et GA4, la sélection des cibles par l&amp;rsquo;analyse, l&amp;rsquo;optimisation du contenu par la NLP, jusqu&amp;rsquo;au suivi des résultats, votre média de blog deviendra un atout qui continuera à se développer automatiquement.&lt;/p>
&lt;hr>
&lt;h2 id="8-conclusion-et-perspectives-futures">8. Conclusion et perspectives futures
&lt;/h2>&lt;p>La réécriture d&amp;rsquo;articles techniques à l&amp;rsquo;aide de Google Search Console n&amp;rsquo;est pas une simple correction de texte. C&amp;rsquo;est une ingénierie avancée qui utilise des données et des modèles mathématiques pour présenter des solutions optimales face à la boîte noire qu&amp;rsquo;est l&amp;rsquo;algorithme du moteur de recherche.&lt;/p>
&lt;p>Pour résumer les méthodes expliquées dans cet article :&lt;/p>
&lt;ol>
&lt;li>Calculer &lt;strong>l&amp;rsquo;écart entre le CTR attendu et le CTR réel&lt;/strong> pour identifier les articles dont la modification aura un impact important.&lt;/li>
&lt;li>Extraire automatiquement les données de performances en utilisant &lt;strong>l&amp;rsquo;API GSC et Python&lt;/strong>.&lt;/li>
&lt;li>Combiner cela avec les données d&amp;rsquo;engagement de GA4 sur &lt;strong>BigQuery&lt;/strong> et corriger le corps des articles ayant un taux de rebond élevé.&lt;/li>
&lt;li>Découvrir les lacunes de contenu avec les concurrents par &lt;strong>l&amp;rsquo;analyse NLP utilisant le TF-IDF&lt;/strong>, et optimiser les titres (H2/H3).&lt;/li>
&lt;/ol>
&lt;p>Les tendances technologiques changent constamment. Afin de répondre avec précision aux erreurs et aux défis auxquels vos lecteurs sont actuellement confrontés, nous vous encourageons à intégrer une réécriture stratégique, avec les données de votre côté, dans vos opérations quotidiennes.&lt;/p></description></item></channel></rss>