<?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/es/categories/blogging/</link><description>Recent content in Blogging on kenji.blog</description><generator>Hugo -- gohugo.io</generator><language>es</language><copyright>kenjinote</copyright><lastBuildDate>Sun, 13 Sep 2026 02:00:00 +0900</lastBuildDate><atom:link href="http://kenji.blog/es/categories/blogging/index.xml" rel="self" type="application/rss+xml"/><item><title>Introducción al generador de sitios estáticos Hugo (Guía de migración desde WordPress)</title><link>http://kenji.blog/es/p/hugo-static-site-generator-wordpress-migration/</link><pubDate>Sun, 13 Sep 2026 02:00:00 +0900</pubDate><guid>http://kenji.blog/es/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 Introducción al generador de sitios estáticos Hugo (Guía de migración desde WordPress)" />&lt;p>En el desarrollo web moderno y la gestión de blogs, la velocidad de carga de un sitio, su seguridad y su mantenibilidad son factores extremadamente importantes. Durante mucho tiempo, &amp;ldquo;WordPress&amp;rdquo;, que ha tenido una cuota de mercado abrumadora como base para blogs y sitios web corporativos, ha sido utilizado por muchos usuarios debido a su flexible ecosistema de plugins y su panel de administración intuitivo. Sin embargo, debido a que implica la comunicación con bases de datos y la generación dinámica de páginas en el lado del servidor (procesamiento con PHP), también enfrenta desafíos como la vulnerabilidad ante aumentos repentinos de tráfico y retrasos en la visualización (latencia).&lt;/p>
&lt;p>Por lo tanto, en los últimos años, los &amp;ldquo;Generadores de Sitios Estáticos&amp;rdquo; (SSG: Static Site Generator) se han popularizado rápidamente. En este artículo, profundizaremos en &amp;ldquo;&lt;strong>Hugo&lt;/strong>&amp;rdquo;, desarrollado en el lenguaje Go y conocido por su abrumadora velocidad de construcción entre los muchos SSG disponibles. Explicaremos exhaustivamente desde la comparación técnica de arquitectura con CMS (Sistemas de Gestión de Contenidos) dinámicos como WordPress, hasta los pasos concretos de migración, evaluación de rendimiento mediante modelos matemáticos, la estructura de directorios propia de Hugo y el orden de búsqueda de plantillas.&lt;/p>
&lt;hr>
&lt;h2 id="1-diferencias-técnicas-entre-un-cms-dinámico-wordpress-y-un-generador-de-sitios-estáticos-hugo">1. Diferencias técnicas entre un CMS dinámico (WordPress) y un generador de sitios estáticos (Hugo)
&lt;/h2>&lt;p>En el mecanismo de entrega de sitios web, WordPress y Hugo adoptan enfoques fundamentalmente diferentes.&lt;/p>
&lt;h3 id="11-arquitectura-de-wordpress-generación-dinámica">1.1 Arquitectura de WordPress (Generación dinámica)
&lt;/h3>&lt;p>WordPress es un claro ejemplo de CMS dinámico que ensambla páginas en el lado del servidor con cada solicitud. Cuando hay un acceso a una página por parte de un usuario (navegador), el servidor web (Apache, Nginx, etc.) ejecuta un script PHP y realiza consultas a una base de datos relacional como MySQL (o MariaDB). Combina el contenido obtenido de la base de datos (datos de artículos, categorías, etiquetas, configuración del sitio, etc.) con archivos de plantillas para generar el HTML final y devolverlo al cliente.&lt;/p>
&lt;p>Este mecanismo tiene la ventaja de poder generar contenido diferente para cada visitante en tiempo real (por ejemplo: carrito de compras de comercio electrónico, página exclusiva para usuarios que han iniciado sesión), pero consume intensamente los recursos del servidor a menos que se diseñe adecuadamente un mecanismo de caché (como proxy inverso o plugins).&lt;/p>
&lt;h3 id="12-arquitectura-de-hugo-generación-previa-en-tiempo-de-construcción">1.2 Arquitectura de Hugo (Generación previa en tiempo de construcción)
&lt;/h3>&lt;p>Por otro lado, como su nombre indica, Hugo, un &amp;ldquo;generador de sitios estáticos&amp;rdquo;, genera contenido en el &amp;ldquo;tiempo de construcción&amp;rdquo; y no en el &amp;ldquo;tiempo de solicitud&amp;rdquo;. El contenido no se mantiene en una base de datos, sino como archivos locales &amp;ldquo;Markdown&amp;rdquo; controlados por versiones con herramientas como Git.
Cuando un desarrollador ejecuta el comando (&lt;code>hugo&lt;/code>), Hugo lee los archivos Markdown, inyecta los datos en plantillas HTML especificadas (archivos de diseño) y genera un conjunto completo de archivos HTML/CSS/JS puros.&lt;/p>
&lt;p>Los archivos generados (activos estáticos) se pueden entregar simplemente colocándolos en &amp;ldquo;entornos de alojamiento estático&amp;rdquo; como Amazon S3, Cloudflare Pages, Netlify, Vercel o un simple servidor Nginx. Como no se requiere una base de datos ni un lenguaje de lado del servidor (como PHP), los riesgos de seguridad (inyección SQL, vulnerabilidades de PHP, etc.) disminuyen drásticamente, y la velocidad de entrega se acelera al máximo al ser almacenada en caché en nodos de borde de una CDN (Content Delivery Network).&lt;/p>
&lt;p>A continuación, ilustramos la diferencia entre las dos arquitecturas con un diagrama Mermaid.&lt;/p>
&lt;pre class="mermaid">
flowchart TD
subgraph WordPress[&amp;#34;CMS Dinámico (WordPress)&amp;#34;]
direction TB
Req1[&amp;#34;Solicitud del usuario&amp;#34;] --&amp;gt; WebServer1[&amp;#34;Servidor web (Nginx/Apache)&amp;#34;]
WebServer1 --&amp;gt; PHP[&amp;#34;Entorno PHP&amp;#34;]
PHP &amp;lt;--&amp;gt; DB[&amp;#34;Base de datos (MySQL)&amp;#34;]
PHP --&amp;gt; HTML1[&amp;#34;Generación de HTML&amp;#34;]
HTML1 --&amp;gt; Res1[&amp;#34;Devolución de respuesta&amp;#34;]
end
subgraph Hugo[&amp;#34;Generador de Sitios Estáticos (Hugo)&amp;#34;]
direction TB
Dev[&amp;#34;Desarrollador / CI・CD&amp;#34;] --&amp;gt; HugoBuild[&amp;#34;Proceso de construcción de Hugo&amp;#34;]
Markdown[&amp;#34;Archivos Markdown&amp;#34;] --&amp;gt; HugoBuild
Templates[&amp;#34;Plantillas (HTML)&amp;#34;] --&amp;gt; HugoBuild
HugoBuild --&amp;gt; StaticFiles[&amp;#34;Archivos estáticos (HTML/CSS/JS)&amp;#34;]
StaticFiles --&amp;gt; CDN[&amp;#34;CDN / Alojamiento estático&amp;#34;]
Req2[&amp;#34;Solicitud del usuario&amp;#34;] --&amp;gt; CDN
CDN --&amp;gt; Res2[&amp;#34;Devolución de respuesta instantánea&amp;#34;]
end
&lt;/pre>
&lt;hr>
&lt;h2 id="2-evaluación-del-rendimiento-mediante-modelos-matemáticos">2. Evaluación del rendimiento mediante modelos matemáticos
&lt;/h2>&lt;p>Uno de los mayores beneficios de migrar de WordPress a Hugo es la mejora en el rendimiento (velocidad de carga). Para entender esto cuantitativamente, expresémoslo con un modelo matemático simple.&lt;/p>
&lt;p>El tiempo hasta que se completa la carga de una página (Load Time: $T_{load}$) se divide principalmente en el tiempo de respuesta del servidor (TTFB: Time To First Byte) y el tiempo de renderizado y obtención de recursos por parte del navegador ($T_{render}$).&lt;/p>
$$ T_{load} = T_{ttfb} + T_{render} $$&lt;p>En el caso de un CMS dinámico (WordPress), $T_{ttfb}$ es la suma de los siguientes elementos: latencia de la red ($T_{network}$), tiempo de ejecución del script del lado del servidor ($T_{php}$) y tiempo de procesamiento de consultas a la base de datos ($T_{db}$).&lt;/p>
$$ T_{ttfb\_wp} = T_{network} + T_{php} + T_{db} $$&lt;p>En un estado de accesos concentrados (alta carga), $T_{php}$ y $T_{db}$ aumentan de manera no lineal, y el sistema en su conjunto puede convertirse en un cuello de botella. Expresado en una fórmula, con respecto al número de solicitudes ($N$), se observa el siguiente deterioro en el tiempo de respuesta ($k$ es el coeficiente de sobrecarga de procesamiento).&lt;/p>
$$ T_{php}(N) \approx O(N^k), \quad T_{db}(N) \approx O(N^k) \quad \text{where } k > 1 $$&lt;p>Por otro lado, en una arquitectura que combina un generador de sitios estáticos (Hugo) y una CDN, no existe un procesamiento dinámico del lado del servidor (PHP o consultas DB). Dado que el contenido se almacena en caché en servidores de borde distribuidos por todo el mundo, $T_{ttfb}$ depende puramente de la latencia de la red desde el cliente hasta el servidor de borde más cercano ($T_{edge}$).&lt;/p>
$$ T_{ttfb\_hugo} = T_{edge} $$&lt;p>Con esto, se cumple $T_{edge} \ll (T_{network} + T_{php} + T_{db})$, y el TTFB se reduce drásticamente desde varios cientos de milisegundos a unas pocas decenas de milisegundos. Además, incluso si aumenta el número de solicitudes $N$, el tiempo de respuesta se mantiene casi constante ($O(1)$) debido a la función de equilibrio de carga de los servidores de borde.&lt;/p>
$$ \lim_{N \to \infty} T_{ttfb\_hugo}(N) \approx \text{Constant} $$&lt;p>Esta es la base matemática por la cual Hugo (un sitio estático) es extremadamente robusto contra picos de tráfico (como cuando el contenido se vuelve viral).&lt;/p>
&lt;hr>
&lt;h2 id="3-estructura-básica-y-principios-de-funcionamiento-de-hugo">3. Estructura básica y principios de funcionamiento de Hugo
&lt;/h2>&lt;p>Para dominar Hugo, es esencial comprender su estructura de directorios única y los conceptos de &amp;ldquo;Front Matter&amp;rdquo; y &amp;ldquo;Template Lookup Order&amp;rdquo; (Orden de búsqueda de plantillas).&lt;/p>
&lt;h3 id="31-explicación-detallada-de-la-estructura-de-directorios">3.1 Explicación detallada de la estructura de directorios
&lt;/h3>&lt;p>Cuando creas un nuevo proyecto de Hugo (&lt;code>hugo new site mysite&lt;/code>), se genera la siguiente estructura de directorios.&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/ # Plantillas al crear nuevo contenido (esqueleto de Front Matter)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── assets/ # Archivos procesados por Hugo Pipes (SCSS/Sass, JavaScript, etc.)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── content/ # Contenido real del sitio (archivos Markdown). Esto reemplaza a la DB.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── data/ # Datos externos y configuración usados en todo el sitio (JSON, TOML, YAML, CSV, etc.)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── layouts/ # Plantillas HTML que determinan la apariencia del sitio (utiliza Go html/template)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── public/ # Lugar donde se generan los archivos estáticos después de ejecutar el comando build
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── static/ # Archivos estáticos publicados tal cual (imágenes, favicon, txt para robots, etc.)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── themes/ # Directorio de temas de terceros o creados por uno mismo
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">└── hugo.toml # Archivo de configuración global del sitio (anteriormente config.toml era la norma)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>En WordPress, el contenido se almacena en la tabla &lt;code>wp_posts&lt;/code> de MySQL, pero en Hugo todo se gestiona como archivos de texto (principalmente Markdown) dentro del directorio &lt;code>content/&lt;/code>. Esto facilita el control de versiones (Git) del contenido.&lt;/p>
&lt;h3 id="32-gestión-de-contenido-markdown-y-front-matter">3.2 Gestión de contenido: Markdown y Front Matter
&lt;/h3>&lt;p>Cada archivo de artículo de Hugo tiene un bloque de metadatos llamado &amp;ldquo;Front Matter&amp;rdquo; en la parte superior, seguido del texto principal (Markdown). Front Matter se puede escribir en TOML, YAML o JSON, pero YAML es ampliamente utilizado.&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;Comprendiendo la taxonomía 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;Explicación técnica&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">A partir de aquí comienza el texto. Se escribe 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">Explicaremos las potentes funciones 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>Aquí, un punto a destacar es la clave &lt;code>aliases&lt;/code>. Al migrar desde WordPress, si cambian los enlaces permanentes (URL), será una gran desventaja para el SEO. Si usas la función de alias de Hugo, con solo especificar la URL antigua, Hugo generará automáticamente el HTML de redireccionamiento (redirección mediante meta refresh). Es extremadamente útil, ya que no se requiere configuración de redirección en el lado del servidor (como .htaccess).&lt;/p>
&lt;h3 id="33-orden-de-búsqueda-de-plantillas-template-lookup-order">3.3 Orden de búsqueda de plantillas (Template Lookup Order)
&lt;/h3>&lt;p>Una de las potentes características de Hugo es su mecanismo flexible de búsqueda de plantillas (Template Lookup Order). Cuando Hugo renderiza una página específica, busca directorios y nombres de archivos en un orden particular para encontrar la mejor plantilla.&lt;/p>
&lt;p>Por ejemplo, al renderizar un artículo individual (Single Page) como &lt;code>content/post/hello-world.md&lt;/code>, Hugo busca el archivo de diseño aproximadamente en el siguiente orden:&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> (no es un error, pero normalmente es para listas)&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>Los desarrolladores pueden &lt;strong>sobrescribir (override)&lt;/strong> las plantillas de un tema simplemente creando un archivo con el mismo nombre en el directorio &lt;code>layouts/&lt;/code> de su propio proyecto, sin tener que reescribir directamente el código fuente del tema. Esto permite aplicar personalizaciones propias sin obstaculizar la actualización del tema base.&lt;/p>
&lt;h3 id="34-taxonomía-taxonomy">3.4 Taxonomía (Taxonomy)
&lt;/h3>&lt;p>En Hugo, el sistema de clasificación equivalente a &amp;ldquo;Categorías&amp;rdquo; y &amp;ldquo;Etiquetas&amp;rdquo; de WordPress se llama &amp;ldquo;Taxonomía&amp;rdquo; (Taxonomy).
Hugo admite de forma predeterminada las taxonomías &lt;code>categories&lt;/code> y &lt;code>tags&lt;/code>, pero editando &lt;code>hugo.toml&lt;/code>, puedes agregar libremente taxonomías personalizadas (por ejemplo: &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"># Ejemplo 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>Esto permite organizar y listar el contenido bajo diversas perspectivas.&lt;/p>
&lt;hr>
&lt;h2 id="4-proceso-de-migración-de-wordpress-a-hugo">4. Proceso de migración de WordPress a Hugo
&lt;/h2>&lt;p>La clave del éxito al migrar de WordPress a Hugo es cómo convertir el contenido dinámico de la base de datos en archivos estáticos limpios (Markdown + Front Matter) y mantener la estructura de URL existente.&lt;/p>
&lt;p>A continuación se muestra el flujo general de la canalización de migración.&lt;/p>
&lt;pre class="mermaid">
flowchart LR
WPDB[&amp;#34;Base de datos WP&amp;#34;] --&amp;gt;|Plugin| Exporter[&amp;#34;Herramienta de exportación&amp;#34;]
Exporter --&amp;gt;| Extrae texto, \nMetadatos, Imágenes | ZipFile[&amp;#34;Archivo Zip / Carpeta&amp;#34;]
ZipFile --&amp;gt;|Unpack| MarkdownFiles[&amp;#34;Archivos Markdown \n(content/)&amp;#34;]
ZipFile --&amp;gt;|Unpack| ImageFiles[&amp;#34;Imágenes \n(static/wp-content/)&amp;#34;]
MarkdownFiles --&amp;gt; Formatting[&amp;#34;Revisión y formato \n(Corregir Shortcodes)&amp;#34;]
Formatting --&amp;gt; Git[&amp;#34;Commit a Git&amp;#34;]
&lt;/pre>
&lt;h3 id="41-extracción-de-datos-y-conversión-a-markdown">4.1 Extracción de datos y conversión a Markdown
&lt;/h3>&lt;p>Para exportar datos de WordPress a Hugo, usar un plugin dedicado es el método más sencillo y seguro. Presentamos algunos enfoques representativos:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Uso del plugin Jekyll Exporter&lt;/strong>
Como Hugo tiene una estructura de datos muy similar a Jekyll, otro SSG, utilizar el plugin &amp;ldquo;Jekyll Exporter&amp;rdquo; para WordPress es una práctica común. Al instalar y ejecutar este plugin, todas las entradas y páginas estáticas se convierten a archivos Markdown con Front Matter y se pueden descargar como un archivo ZIP junto con los archivos de imagen.&lt;/li>
&lt;li>&lt;strong>Script propio usando la API de WordPress&lt;/strong>
Este método consiste en usar Python, Node.js, etc., para hacer llamadas a la API REST de WordPress (&lt;code>/wp-json/wp/v2/posts&lt;/code>), analizar los datos JSON y crear un script para generar archivos Markdown. Es eficaz para sitios que utilizan en gran medida campos personalizados complejos (como ACF) que los plugins no pueden manejar completamente.&lt;/li>
&lt;li>&lt;strong>Aprovechamiento de la herramienta wp2hugo&lt;/strong>
También hay un enfoque para usar herramientas CLI escritas en lenguajes como Go para convertir directamente desde el archivo XML de exportación de WordPress (WXR) al formato de Hugo.&lt;/li>
&lt;/ol>
&lt;h3 id="42-mantenimiento-de-la-estructura-de-enlaces-permanentes-url">4.2 Mantenimiento de la estructura de enlaces permanentes (URL)
&lt;/h3>&lt;p>Para heredar la evaluación de SEO, es extremadamente importante mantener la estructura de URL de la era de WordPress tal como está. Si habías configurado enlaces permanentes en WordPress como &lt;code>https://example.com/2026/09/13/my-post/&lt;/code>, debes especificar la estructura de enlaces permanentes en el archivo &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>Alternativamente, es posible fijar la URL de forma forzada especificando directamente el parámetro &lt;code>url&lt;/code> en el Front Matter de cada artículo.
Además, para las páginas cuyas URL cambiarán, configuras redirecciones usando los &lt;code>aliases&lt;/code> mencionados anteriormente.&lt;/p>
&lt;h3 id="43-conversión-de-shortcodes-códigos-cortos">4.3 Conversión de Shortcodes (códigos cortos)
&lt;/h3>&lt;p>Los shortcodes específicos de WordPress (por ejemplo: &lt;code>[gallery]&lt;/code>, &lt;code>[caption]&lt;/code>, códigos únicos de varios plugins) a menudo permanecen como cadenas de texto tras la exportación, por lo que es necesario abordarlos.
Estos se pueden eliminar por completo mediante scripts de reemplazo (sed o Python) o se pueden migrar utilizando la poderosa &lt;strong>función de shortcodes personalizados&lt;/strong> de Hugo (creando diseños propios en &lt;code>layouts/shortcodes/&lt;/code>) para que se rendericen adecuadamente en el lado de Hugo.&lt;/p>
&lt;hr>
&lt;h2 id="5-herramienta-cli-de-hugo-y-construcción--despliegue">5. Herramienta CLI de Hugo y construcción / despliegue
&lt;/h2>&lt;p>Una vez que se completan las tareas de migración, es hora de usar Hugo para construir el sitio y publicarlo para el mundo. Hugo, que se proporciona como un binario de Go, presume de una velocidad asombrosa, completando la construcción en unos pocos segundos incluso para sitios de miles a decenas de miles de páginas.&lt;/p>
&lt;h3 id="51-inicio-del-servidor-de-desarrollo-local">5.1 Inicio del servidor de desarrollo local
&lt;/h3>&lt;p>Cuando escribas artículos o ajustes el diseño, inicia el servidor 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"># Comando de inicio del servidor de desarrollo (usa -D para incluir borradores)&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>Al ejecutar este comando, podrás previsualizar el sitio en &lt;code>http://localhost:1313/&lt;/code>. Hugo tiene una poderosa función integrada llamada &amp;ldquo;LiveReload&amp;rdquo;; en el momento en que edites y guardes un archivo Markdown, plantilla o CSS, la pantalla del navegador se actualizará automáticamente a alta velocidad. Como resultado, la experiencia de escritura y desarrollo se vuelve mucho más cómoda que el panel de administración de WordPress.&lt;/p>
&lt;h3 id="52-construcción-para-producción-y-optimización-de-rendimiento">5.2 Construcción para producción y optimización de rendimiento
&lt;/h3>&lt;p>Para generar archivos estáticos que se desplegarán en un entorno de producción, simplemente escribe &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"># Ejecución de la compilación para producción. Minimiza HTML/CSS/JS con la opción --minify&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>Con este comando, los archivos de todo el sitio se generarán en el directorio &lt;code>public/&lt;/code>. Al agregar la opción &lt;code>--minify&lt;/code>, se eliminan los saltos de línea y espacios innecesarios, lo que reduce aún más el tamaño de los archivos. Esto contribuye directamente a reducir la latencia de la red ($T_{network}$) en el modelo matemático mencionado anteriormente.&lt;/p>
&lt;h3 id="53-automatización-del-despliegue-cicd">5.3 Automatización del despliegue (CI/CD)
&lt;/h3>&lt;p>Generar archivos estáticos localmente cada vez y subirlos por FTP, etc., es ineficiente. En las operaciones modernas de SSG, la mejor práctica es construir un entorno de CI/CD que realice automáticamente la construcción y el despliegue cuando se desencadena por un push a un repositorio Git (como GitHub).&lt;/p>
&lt;p>Por ejemplo, la forma básica de una configuración (archivo YAML) para implementar en Cloudflare Pages o GitHub Pages usando GitHub Actions es la siguiente:&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"># Ejemplo 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">Deploy Hugo site 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>&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 los temas se administran como submódulos&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>Configurándolo de esta manera, se completará un canal de automatización en el que solo con &amp;ldquo;escribir un artículo en Markdown y hacer Push a GitHub&amp;rdquo;, el sitio más reciente se publicará en el entorno de producción en unos pocos minutos.&lt;/p>
&lt;hr>
&lt;h2 id="6-beneficios-de-seo-y-operativos-tras-la-migración">6. Beneficios de SEO y operativos tras la migración
&lt;/h2>&lt;p>Los administradores de sitios que han completado la migración de WordPress a Hugo a menudo notan los tres siguientes beneficios significativos.&lt;/p>
&lt;h3 id="61-mejora-drástica-de-la-velocidad-del-sitio-y-los-core-web-vitals">6.1 Mejora drástica de la velocidad del sitio y los Core Web Vitals
&lt;/h3>&lt;p>Como resultado de eliminar las consultas a la base de datos y la renderización en el servidor, el tiempo de carga de la página se reduce a milisegundos. Esto se traduce directamente en una mejora masiva de las puntuaciones de &amp;ldquo;Core Web Vitals&amp;rdquo; (LCP, FID/INP, CLS), que son factores de clasificación de Google. Se puede esperar una reducción en la tasa de rebote de los usuarios y una mejora en la evaluación del SEO.&lt;/p>
&lt;h3 id="62-liberación-de-amenazas-de-seguridad">6.2 Liberación de amenazas de seguridad
&lt;/h3>&lt;p>Dado que WordPress se usa ampliamente en todo el mundo, siempre es objeto de ataques. Siempre existe el riesgo de manipulación de vulnerabilidades de plugins e intentos de inicio de sesión por ataques de fuerza bruta.
Sin embargo, un sitio estático generado por Hugo no tiene base de datos, entorno PHP ni pantalla de administración (formulario de inicio de sesión). No hay espacio para que un hacker ingrese al servidor y reescriba la base de datos, con lo que los riesgos de seguridad se acercan a cero al máximo.&lt;/p>
&lt;h3 id="63-operación-libre-de-mantenimiento">6.3 Operación libre de mantenimiento
&lt;/h3>&lt;p>La operación de WordPress requiere tareas de mantenimiento continuas, como la actualización del propio núcleo, la actualización de plugins y el seguimiento de las versiones de PHP. Siempre hay que temer el riesgo de que el sitio se rompa debido a problemas de compatibilidad.
En el caso de Hugo, solo necesitas actualizar la herramienta en sí cuando sea necesario, y dado que el código del sitio está compuesto de archivos de texto independientes, ofrece la abrumadora tranquilidad de saber que &amp;ldquo;no se romperá aunque lo dejes desatendido&amp;rdquo;.&lt;/p>
&lt;hr>
&lt;h2 id="7-resumen">7. Resumen
&lt;/h2>&lt;p>En este artículo, hemos explicado en detalle la migración de un CMS dinámico como WordPress al poderoso generador de sitios estáticos basado en Go, &amp;ldquo;Hugo&amp;rdquo;, abordando desde las diferencias de arquitectura técnica y la demostración matemática del rendimiento hasta los pasos de migración específicos.&lt;/p>
&lt;p>Migrar a un generador de sitios estáticos conlleva un costo inicial de aprendizaje (manejo de Git, sintaxis de Markdown, ejecución de comandos CLI en terminales, comprensión del funcionamiento del motor de plantillas), pero los beneficios compensan con creces mediante su &amp;ldquo;abrumadora velocidad de visualización&amp;rdquo;, &amp;ldquo;seguridad sólida&amp;rdquo; y la característica de ser &amp;ldquo;libre de mantenimiento&amp;rdquo;.&lt;/p>
&lt;p>Si tu sitio web no requiere cambios de diseño frecuentes ni procesos dinámicos complejos (como funciones exclusivas para miembros o características avanzadas de comercio electrónico) y su propósito es principalmente transmitir información (blogs, medios, sitios corporativos), migrar a Hugo será una de las inversiones técnicas más efectivas. Te animamos a usar este artículo como guía para dar tu primer paso en la operación de un sitio web de próxima generación con Hugo.&lt;/p></description></item><item><title>¡Evita quedarte sin ideas para artículos técnicos! Método eficiente de entrada y generación de ideas</title><link>http://kenji.blog/es/p/tech-blog-idea-generation-and-input-strategy/</link><pubDate>Sat, 12 Sep 2026 12:00:00 +0900</pubDate><guid>http://kenji.blog/es/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 ¡Evita quedarte sin ideas para artículos técnicos! Método eficiente de entrada y generación de ideas" />&lt;p>Al administrar un blog técnico como ingeniero o investigador, hay un obstáculo que casi siempre enfrentarás. Es el &amp;ldquo;quedarse sin ideas&amp;rdquo;. Aunque los primeros artículos se escriban sin problemas, a medida que continúas, no es raro que te atormente la preocupación de &amp;ldquo;no sé sobre qué escribir a continuación&amp;rdquo; o &amp;ldquo;me falta abrumadoramente información de entrada (input) para poder generar salidas (output)&amp;rdquo;. La escritura de un blog técnico no depende solo de la habilidad de redactar, sino en gran medida del diseño de un sistema continuo para recopilar conocimientos diarios, organizarlos y combinarlos para crear nuevo valor.&lt;/p>
&lt;p>En este artículo, explicaré de manera muy detallada y técnica sobre un &lt;strong>pipeline de entrada y salida sistematizado&lt;/strong> para continuar generando ideas de artículos técnicos de forma semipermanente. Comenzaremos con un mecanismo para extraer automáticamente temas en tendencia utilizando APIs de fuentes de información extranjeras de alta calidad como Hacker News o Lobsters, y ejecutarlos periódicamente con GitHub Actions. Luego, construiremos un avanzado sistema de Gestión de Conocimiento Personal (PKM: Personal Knowledge Management) que sistematiza la información recopilada como conocimiento mediante el método Zettelkasten usando Obsidian, y que permite realizar búsquedas semánticas combinando la API de Embeddings de OpenAI y Pinecone (una base de datos vectorial).&lt;/p>
&lt;p>Además, para compensar los límites de la memoria humana, profundizaremos en una serie de procesos para poner en práctica la repetición espaciada (Spaced Repetition) basada en la curva del olvido de Ebbinghaus utilizando Anki, y para elevar el conocimiento consolidado a nuevas ideas mediante la &amp;ldquo;creatividad combinatoria (Combinatorial Creativity)&amp;rdquo;, acompañados de modelos matemáticos concretos y ejemplos de implementación de scripts en Python.&lt;/p>
&lt;h2 id="1-la-entropía-de-la-información-y-el-mecanismo-de-quedarse-sin-ideas">1. La entropía de la información y el mecanismo de &amp;ldquo;quedarse sin ideas&amp;rdquo;
&lt;/h2>&lt;p>¿Por qué nos &amp;ldquo;quedamos sin ideas&amp;rdquo;? Desde la perspectiva de la teoría de la información, se puede decir que es un estado en el cual la &amp;ldquo;cantidad de información&amp;rdquo; de nuestro sistema de conocimiento se ha agotado o se ha homogeneizado.&lt;/p>
&lt;p>La entropía de la información $H(X)$ propuesta por Claude Shannon representa la incertidumbre (o el grado de sorpresa) de la información que se puede obtener de una fuente de información.&lt;/p>
$$ H(X) = - \sum_{i=1}^{n} P(x_i) \log_2 P(x_i) $$&lt;p>Aquí, $X$ es la variable aleatoria de un tema obtenido de una fuente de información, y $P(x_i)$ es la probabilidad de encontrarse con ese tema $x_i$. Si normalmente visitas los mismos sitios web (por ejemplo, solo sitios de noticias nacionales específicos o documentación de la misma pila tecnológica), un $P(x_i)$ específico se vuelve extremadamente alto y, como resultado, la entropía $H(X)$ de todo el sistema disminuye. Un estado de baja entropía es un estado en el que &amp;ldquo;no hay nuevos descubrimientos (sorpresas)&amp;rdquo;, y esta es la causa fundamental de &amp;ldquo;quedarse sin ideas&amp;rdquo;.&lt;/p>
&lt;p>Para mantener una entropía alta, es necesario incorporar intencionalmente fuentes de información que no sueles frecuentar como ruido y nivelar la distribución de probabilidad de entrar en contacto con temas desconocidos. Esta es la razón principal para automatizar la entrada desde diversas fuentes de información.&lt;/p>
&lt;h2 id="2-construcción-de-un-pipeline-de-recopilación-de-información-automatizado-hacker-news--lobsters-api">2. Construcción de un pipeline de recopilación de información automatizado: Hacker News &amp;amp; Lobsters API
&lt;/h2>&lt;p>Para obtener información de entrada de alta calidad, es efectivo extraer información sobre tendencias de comunidades de ingenieros de calidad y con poco ruido. Hacker News (operado por Y Combinator) y Lobsters son lugares óptimos donde se llevan a cabo discusiones técnicas profundas. Sin embargo, navegar por estos sitios todos los días lleva tiempo y consume recursos cognitivos.&lt;/p>
&lt;p>Por lo tanto, crearemos un script utilizando Python para extraer automáticamente artículos con una puntuación superior a cierto umbral desde estas APIs.&lt;/p>
&lt;h3 id="script-de-extracción-de-artículos-en-tendencia-con-python">Script de extracción de artículos en tendencia con Python
&lt;/h3>&lt;p>El siguiente script obtiene artículos que cumplen ciertos criterios desde la Firebase API de Hacker News y el feed JSON de Lobsters, y los exporta como un archivo 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"># Configuración&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;Obtener los mejores artículos con alta puntuación de 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"># Limitar a los 30 mejores&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;Obtener artículos con alta puntuación de 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;Guardar los artículos obtenidos como un archivo 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**: (Añadir consideraciones aquí)&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"># Ordenar por puntuación en orden descendente&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>Este script proporciona un valor superior a un simple lector de RSS. Al realizar un filtrado por puntuación, puedes extraer solo los temas técnicos que realmente están llamando la atención en la comunidad (señal alta con poco ruido).&lt;/p>
&lt;h2 id="3-programación-y-automatización-con-github-actions">3. Programación y automatización con GitHub Actions
&lt;/h2>&lt;p>Ejecutar manualmente el script de Python creado todos los días es tedioso. La base de la automatización es reducir la intervención humana al mínimo. Utilizando la función Cron de GitHub Actions, construiremos un mecanismo para ejecutar el script a una hora designada todos los días y confirmar (commit) automáticamente los resultados en el repositorio.&lt;/p>
&lt;p>Crea un archivo &lt;code>.github/workflows/daily_trends.yml&lt;/code> en la raíz del proyecto y escribe lo siguiente:&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"># Ejecutar todos los días a las 0:00 UTC (9:00 hora de Japón)&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"># Para ejecución manual&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>Gracias a esto, puedes crear un estado en el que, cada mañana al abrir Obsidian, los temas importantes del día se habrán añadido automáticamente a tu bandeja de entrada (&lt;code>daily_inputs/&lt;/code>) en formato Markdown.&lt;/p>
&lt;h2 id="4-creación-de-una-red-de-conocimiento-utilizando-zettelkasten-y-obsidian">4. Creación de una red de conocimiento utilizando Zettelkasten y Obsidian
&lt;/h2>&lt;p>La información recopilada automáticamente todavía es solo &amp;ldquo;datos&amp;rdquo;. Es necesario un proceso para elevarla a &amp;ldquo;conocimiento&amp;rdquo;. Aquí es donde entran en juego el método Zettelkasten y Obsidian.&lt;/p>
&lt;p>Zettelkasten es un método de toma de notas ideado por el sociólogo alemán Niklas Luhmann. En lugar de clasificar las notas en carpetas jerárquicas, mantiene cada nota pequeña (atómica) y conecta las notas entre sí con enlaces, construyendo una red de conocimiento similar a los circuitos neuronales del cerebro.&lt;/p>
&lt;p>Existen principalmente 3 tipos de notas en Zettelkasten:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Fleeting Notes (Notas fugaces)&lt;/strong>: Para registrar temporalmente ideas que se te ocurren o información recopilada. El archivo Markdown de información de tendencias generado automáticamente anteriormente entra en esta categoría.&lt;/li>
&lt;li>&lt;strong>Literature Notes (Notas de literatura)&lt;/strong>: Resúmenes con tus propias palabras tras leer artículos o libros.&lt;/li>
&lt;li>&lt;strong>Permanent Notes (Notas permanentes)&lt;/strong>: Consideraciones completas escritas sobre un tema único. Estas serán directamente la semilla para tus artículos del blog.&lt;/li>
&lt;/ol>
&lt;p>Al utilizar la función de retroenlace (backlink) de Obsidian (&lt;code>[[Nombre de la nota]]&lt;/code>), puedes, por ejemplo, enlazar una nota sobre &amp;ldquo;La propiedad en Rust&amp;rdquo; con una sobre &amp;ldquo;La historia del recolector de basura&amp;rdquo;, y descubrir conexiones inesperadas de ideas.&lt;/p>
&lt;h2 id="5-búsqueda-semántica-utilizando-una-base-de-datos-vectorial-pinecone-y-openai-embeddings">5. Búsqueda semántica utilizando una base de datos vectorial (Pinecone) y OpenAI Embeddings
&lt;/h2>&lt;p>Cuando el número de notas aumenta a cientos o miles, resulta difícil encontrar la nota deseada mediante una simple búsqueda de palabras clave (búsqueda de texto completo). La búsqueda semántica (de significado) que aprovecha los Embeddings de los Modelos de Lenguaje Grande (LLM) demuestra su poder cuando &amp;ldquo;no puedes recordar las palabras clave, pero quieres encontrar una nota que sea conceptualmente similar&amp;rdquo;.&lt;/p>
&lt;p>Utilizando el modelo &lt;code>text-embedding-ada-002&lt;/code> (o &lt;code>text-embedding-3-small&lt;/code>) de OpenAI, cada nota Markdown de Obsidian se convierte en un vector multidimensional (un arreglo de números de cientos a miles de dimensiones). En este espacio vectorial, los vectores de frases con significados similares también tienen una distancia física cercana.&lt;/p>
&lt;p>Para medir la similitud entre vectores, se utiliza ampliamente la similitud del coseno (Cosine Similarity).&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}$ y $\mathbf{B}$ son el vector de la cadena de consulta y el vector de la nota, respectivamente. Para realizar este cálculo a alta velocidad, se utilizan bases de datos vectoriales como Pinecone o Qdrant.&lt;/p>
&lt;h3 id="ejemplo-de-implementación-de-búsqueda-semántica">Ejemplo de implementación de búsqueda semántica
&lt;/h3>&lt;p>A continuación se muestra una parte de un script en Python que escanea el directorio de notas de Obsidian, las vectoriza usando la API de OpenAI y las actualiza (upsert) en 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"># Configuración de la clave API (Obtenida de variables de entorno)&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;Inicialización del índice de 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"># Número de dimensiones de 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;Vectorizar texto utilizando la API de 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;Leer archivos Markdown, vectorizarlos y guardarlos en 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"># Procesar solo si el contenido de la nota no está vacío&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"># Formato de Pinecone (id, vector, metadata)&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"># Texto parcial para mostrar en los resultados de búsqueda&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"># Upsert mediante procesamiento por lotes (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;Buscar notas similares a la consulta y utilizarlas para la generación de ideas&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"># En la primera ejecución, llamar a sync_notes_to_pinecone(idx) para construir 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"># Búsqueda para generación de ideas del 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;Aceleración de la inferencia de aprendizaje automático en el navegador utilizando 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>Con este sistema, frente a la pregunta &amp;ldquo;Quiero escribir sobre &amp;lsquo;WebAssembly&amp;rsquo;, que fue tema de conversación esta semana en Hacker News, pero ¿he escrito notas relacionadas en el pasado?&amp;rdquo;, la IA seleccionará instantáneamente las Permanent Notes pasadas que estén semánticamente relacionadas. Esto hace posible estructurar un artículo profundo aprovechando al máximo tus propios activos de conocimiento pasados.&lt;/p>
&lt;h2 id="6-repetición-espaciada-aprovechando-la-curva-del-olvido-de-ebbinghaus-y-anki">6. Repetición espaciada aprovechando la curva del olvido de Ebbinghaus y Anki
&lt;/h2>&lt;p>Por excelente que sea el conocimiento registrado en tus notas, si no está consolidado en el propio cerebro del escritor, será difícil conectar fluidamente múltiples conceptos durante la escritura. Aquí es donde entra en juego la &amp;ldquo;curva del olvido de Ebbinghaus&amp;rdquo;, que modela matemáticamente los mecanismos de la memoria humana.&lt;/p>
&lt;p>La curva del olvido se aproxima con la siguiente fórmula:&lt;/p>
$$ R = e^{-\frac{t}{S}} $$&lt;p>Aquí,&lt;/p>
&lt;ul>
&lt;li>$R$ es la tasa de retención de la memoria (Retrievability, en un rango de 0 a 1)&lt;/li>
&lt;li>$t$ es el tiempo transcurrido desde el aprendizaje&lt;/li>
&lt;li>$S$ es la estabilidad (Stability) o fuerza de la memoria&lt;/li>
&lt;/ul>
&lt;p>Inmediatamente después de aprender un nuevo concepto, $S$ es pequeña y, a medida que el tiempo $t$ avanza, $R$ disminuye (olvido) rápidamente. Sin embargo, al realizar repasos (Recall) en el momento exacto en que se está a punto de olvidar, la velocidad hasta el próximo olvido se vuelve más gradual (haciendo que $S$ sea mayor), consolidándose en la memoria a largo plazo.&lt;/p>
&lt;p>El software que calcula automáticamente este momento óptimo de repaso mediante algoritmos (como SuperMemo 2) y lo presenta como tarjetas de memoria (flashcards) es &amp;ldquo;Anki&amp;rdquo;.&lt;/p>
&lt;p>Un enfoque poderoso para crear ideas para el blog técnico es &lt;strong>convertir el contenido de las Permanent Notes de Obsidian en tarjetas de Anki&lt;/strong>.
Por ejemplo, registrar en Anki preguntas relacionadas con fundamentos técnicos como &amp;ldquo;¿Cuáles son los 3 elementos del teorema CAP?&amp;rdquo; o &amp;ldquo;¿Por qué los índices B-Tree tienen un rendimiento de búsqueda de O(log N)?&amp;rdquo; y repasarlas como parte de tu rutina diaria. Cuando el conocimiento se indexa en el cerebro como memoria a largo plazo, la información se conectará inconscientemente mientras te bañas o caminas, generando momentos de inspiración (momentos Eureka) como: &amp;ldquo;Ah, creo que podría escribir un artículo sobre los algoritmos de consenso en sistemas distribuidos&amp;rdquo;.&lt;/p>
&lt;h2 id="7-creatividad-combinatoria-combinatorial-creativity">7. Creatividad combinatoria (Combinatorial Creativity)
&lt;/h2>&lt;p>En el pipeline desarrollado hasta ahora hemos logrado la &amp;ldquo;entrada de información diversa&amp;rdquo;, la &amp;ldquo;organización con Zettelkasten y búsqueda con IA&amp;rdquo; y la &amp;ldquo;consolidación en la memoria a largo plazo con Anki&amp;rdquo;. El último paso es la &amp;ldquo;creatividad combinatoria (Combinatorial Creativity)&amp;rdquo;, que consiste en multiplicar estos elementos para generar ideas completamente nuevas para artículos técnicos.&lt;/p>
&lt;p>Se dice que la innovación y la creatividad no nacen de crear algo de la nada, sino de nuevas combinaciones de elementos existentes. Es famosa la cita de Steve Jobs: &amp;ldquo;La creatividad es simplemente conectar cosas (Creativity is just connecting things.)&amp;rdquo;.&lt;/p>
&lt;p>Como patrones de combinación en blogs técnicos, se puede considerar la siguiente matriz:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>[Tecnología antigua] × [Nuevo paradigma]&lt;/strong>: Ejemplo: &amp;ldquo;Aprendiendo de la arquitectura de COBOL: Antipatrones en el diseño de microservicios modernos&amp;rdquo;.&lt;/li>
&lt;li>&lt;strong>[Frontend] × [Concepto de backend]&lt;/strong>: Ejemplo: &amp;ldquo;Explicando el algoritmo de actualización del DOM virtual de React desde la perspectiva de los niveles de aislamiento de transacciones de bases de datos&amp;rdquo;.&lt;/li>
&lt;li>&lt;strong>[Matemáticas abstractas y teorías] × [Implementación concreta]&lt;/strong>: Ejemplo: &amp;ldquo;Descifrando la optimización de la programación (scheduling) de Pods en Kubernetes con la teoría de grafos&amp;rdquo;.&lt;/li>
&lt;/ol>
&lt;p>Para generar estas combinaciones intencionadamente, puedes usar el sistema de búsqueda semántica de Pinecone que construimos anteriormente para extraer dos conceptos aleatorios, A y B. Luego, pasándole a una IA (como ChatGPT) un prompt diciendo: &amp;ldquo;Propón 5 títulos y borradores de índice para un blog técnico que combine estos dos&amp;rdquo;, podrás generar infinitamente ideas de artículos con enfoques novedosos que no se te habrían ocurrido por tu cuenta.&lt;/p>
&lt;h2 id="8-arquitectura-general-del-sistema">8. Arquitectura general del sistema
&lt;/h2>&lt;p>A continuación, se resume en el siguiente diagrama de flujo de Mermaid la arquitectura general de &amp;ldquo;desde la recopilación de información hasta la generación de ideas&amp;rdquo; que hemos explicado hasta ahora para evitar quedarse sin ideas de artículos técnicos.&lt;/p>
&lt;pre class="mermaid">
flowchart TD
A[&amp;#34;Hacker News / Lobsters API&amp;#34;] --&amp;gt;|Script de extracción en Python| B[&amp;#34;Datos de tendencias sin procesar&amp;#34;]
C[&amp;#34;GitHub Actions (Cron)&amp;#34;] --&amp;gt;|Programa de ejecución periódica| A
B --&amp;gt;|Conversión de formato a Markdown| D[&amp;#34;Entradas Diarias (Fleeting Notes)&amp;#34;]
D --&amp;gt;|Trabajo manual de lectura y resumen| E[&amp;#34;Obsidian Zettelkasten&amp;#34;]
E --&amp;gt;|Conversión a notas permanentes| F[&amp;#34;Notas Permanentes (Permanent Notes)&amp;#34;]
F --&amp;gt;|Procesamiento de sincronización automática| G[&amp;#34;OpenAI Embeddings API&amp;#34;]
G --&amp;gt;|Conversión a vectores| H[&amp;#34;Base de Datos Vectorial Pinecone&amp;#34;]
H --&amp;gt;|Búsqueda semántica| I[&amp;#34;Descubrimiento y extracción de conocimientos relacionados&amp;#34;]
F --&amp;gt;|Creación de tarjetas de memoria (flashcards)| J[&amp;#34;Anki (Repetición Espaciada)&amp;#34;]
J --&amp;gt;|Inspiración desde la memoria a largo plazo| K[&amp;#34;Creatividad Combinatoria&amp;#34;]
I --&amp;gt; K
K --&amp;gt;|Creación de trama y borrador de estructura| L[&amp;#34;Borrador del Artículo del Blog (Escritura del artículo)&amp;#34;]
&lt;/pre>
&lt;p>La característica de este sistema es que &lt;strong>el &amp;ldquo;trabajo intelectual que se debe hacer manualmente (resumen, consideración, redacción)&amp;rdquo; y el &amp;ldquo;trabajo que se debe delegar a la máquina (recopilación, búsqueda, programación de la repetición espaciada)&amp;rdquo; están completamente separados&lt;/strong>. Gracias a esto, el escritor puede concentrarse en &amp;ldquo;pensar&amp;rdquo; y &amp;ldquo;combinar&amp;rdquo;, que es lo que proporciona el mayor valor añadido.&lt;/p>
&lt;h2 id="9-modelo-de-transición-de-estado-desde-la-idea-hasta-su-publicación">9. Modelo de transición de estado: desde la idea hasta su publicación
&lt;/h2>&lt;p>El ciclo de vida desde que las ideas acumuladas en Zettelkasten se publican finalmente como artículos del blog, se puede representar mediante el siguiente diagrama de transición de estados. Se debe utilizar la herramienta y el enfoque adecuados para cada estado.&lt;/p>
&lt;pre class="mermaid">
stateDiagram-v2
[*] --&amp;gt; Capture[&amp;#34;Idea Capture (Captura de información)&amp;#34;]
Capture[&amp;#34;Idea Capture (Captura de información)&amp;#34;] --&amp;gt; Fleeting[&amp;#34;Fleeting Notes (Notas temporales)&amp;#34;]
Fleeting[&amp;#34;Fleeting Notes (Notas temporales)&amp;#34;] --&amp;gt; Permanent[&amp;#34;Permanent Notes (Notas permanentes)&amp;#34;]
Permanent[&amp;#34;Permanent Notes (Notas permanentes)&amp;#34;] --&amp;gt; Brainstorming[&amp;#34;Brainstorming (Búsqueda semántica con IA)&amp;#34;]
Permanent[&amp;#34;Permanent Notes (Notas permanentes)&amp;#34;] --&amp;gt; Memorization[&amp;#34;Memorization (Repaso con Anki)&amp;#34;]
Memorization[&amp;#34;Memorization (Repaso con Anki)&amp;#34;] --&amp;gt; Brainstorming[&amp;#34;Brainstorming (Búsqueda semántica con IA)&amp;#34;]
Brainstorming[&amp;#34;Brainstorming (Búsqueda semántica con IA)&amp;#34;] --&amp;gt; Outlining[&amp;#34;Outlining (Creación de estructura e índice)&amp;#34;]
Outlining[&amp;#34;Outlining (Creación de estructura e índice)&amp;#34;] --&amp;gt; Drafting[&amp;#34;Drafting (Redacción del primer borrador)&amp;#34;]
Drafting[&amp;#34;Drafting (Redacción del primer borrador)&amp;#34;] --&amp;gt; Review[&amp;#34;Review &amp;amp; Edit (Revisión y edición)&amp;#34;]
Review[&amp;#34;Review &amp;amp; Edit (Revisión y edición)&amp;#34;] --&amp;gt; Published[&amp;#34;Published (Publicación del blog)&amp;#34;]
Published[&amp;#34;Published (Publicación del blog)&amp;#34;] --&amp;gt; [*]
&lt;/pre>
&lt;p>Al ser consciente de este flujo de trabajo, quedará claro &amp;ldquo;en qué fase te encuentras atascado actualmente&amp;rdquo;. Cuando no tengas ideas, simplemente debes regresar a la fase de &amp;ldquo;Capture&amp;rdquo; o &amp;ldquo;Permanent&amp;rdquo;, y verificar si el pipeline de entrada está funcionando correctamente.&lt;/p>
&lt;h2 id="conclusión-escribir-es-un-sistema">Conclusión: Escribir es un &amp;ldquo;sistema&amp;rdquo;
&lt;/h2>&lt;p>&amp;ldquo;Quedarse sin ideas para el blog técnico&amp;rdquo; no es el resultado de la falta de capacidad individual o la disminución de la motivación, sino &lt;strong>una consecuencia inevitable de no tener construido un sistema que permita circular el conocimiento&lt;/strong>.&lt;/p>
&lt;p>Como hemos presentado en este artículo:&lt;/p>
&lt;ol>
&lt;li>Asegurar una entrada (input) de alta calidad y con poco ruido mediante &lt;strong>APIs y automatización&lt;/strong>.&lt;/li>
&lt;li>Creación de una red de conocimiento mediante Zettelkasten utilizando &lt;strong>Obsidian&lt;/strong>.&lt;/li>
&lt;li>Búsqueda semántica de los propios activos usando &lt;strong>OpenAI y Pinecone&lt;/strong>.&lt;/li>
&lt;li>Fortalecimiento del índice mental aprovechando &lt;strong>Anki&lt;/strong> y la curva del olvido de Ebbinghaus.&lt;/li>
&lt;li>&lt;strong>Creatividad combinatoria&lt;/strong> que multiplica conceptos existentes.&lt;/li>
&lt;/ol>
&lt;p>Al construir un pipeline integral que combina todo esto, lejos de que se agoten las ideas para el blog, se puede crear un estado en el que las nuevas ideas se auto-multiplican cuanto más escribes.&lt;/p>
&lt;p>No es necesario construir todo a la perfección desde el principio. Comienza por crear un script sencillo que llame a la API de Hacker News y adquiere el hábito de tomar notas en formato Markdown sobre los artículos que te interesen. Espero que tu blog técnico se convierta en una fuente de excelentes ideas para la próxima generación.&lt;/p></description></item><item><title>Blog técnico escrito en Markdown: Configuración del editor para duplicar la velocidad de escritura</title><link>http://kenji.blog/es/p/markdown-editor-setup-for-tech-blogs/</link><pubDate>Sat, 12 Sep 2026 12:00:00 +0900</pubDate><guid>http://kenji.blog/es/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 técnico escrito en Markdown: Configuración del editor para duplicar la velocidad de escritura" />&lt;p>Para escribir continuamente un blog técnico, es indispensable optimizar el entorno de escritura. En este artículo, profundizaremos en configuraciones avanzadas del editor para mejorar drásticamente la velocidad de escritura de un blog técnico utilizando Markdown. Explicaremos exhaustivamente desde la personalización extrema de Visual Studio Code (VS Code) y Neovim, el uso de fragmentos (snippets), la introducción de textlint como herramienta de revisión gramatical, la automatización en canalizaciones CI/CD, hasta las técnicas de escritura más vanguardistas utilizando LLM como GitHub Copilot.&lt;/p>
&lt;h2 id="1-modelo-matemático-para-mejorar-la-velocidad-de-escritura">1. Modelo matemático para mejorar la velocidad de escritura
&lt;/h2>&lt;p>Veamos primero con un modelo matemático simple cuánto impacta la optimización de la configuración del editor en el tiempo de escritura. Supongamos que el tiempo total de entrada al escribir un artículo de blog es $T_{total}$.&lt;/p>
$$
T_{total} = T_{think} + T_{type} + T_{format} + T_{review}
$$&lt;p>Aquí, $T_{think}$ es el tiempo de pensamiento, $T_{type}$ es el tiempo de escritura (tipeo), $T_{format}$ es el tiempo de ajuste de formato como Markdown, y $T_{review}$ es el tiempo de revisión y corrección.&lt;/p>
&lt;p>El tiempo ahorrado $T_{saved}$ mediante la personalización del editor (como la introducción de fragmentos y configuración de Linter) se puede expresar de la siguiente manera, utilizando el número de apariciones $N$ de un patrón específico (por ejemplo, shortcodes de Hugo o tablas de Markdown), el tiempo necesario para la entrada manual $t_{manual}$, y el tiempo necesario para la automatización mediante fragmentos, etc., $t_{snippet}$.&lt;/p>
$$
T_{saved} = \sum_{i=1}^{k} N_i \times (t_{manual, i} - t_{snippet, i}) + T_{review\_saved}
$$&lt;p>Además, al introducir herramientas de formateo automático o de Lint, el tiempo de confirmación visual humano $T_{review}$ se reduce considerablemente. Maximizar este $T_{saved}$ es precisamente el objetivo de este artículo.&lt;/p>
&lt;h2 id="2-la-configuración-definitiva-para-visual-studio-code-vs-code">2. La configuración definitiva para Visual Studio Code (VS Code)
&lt;/h2>&lt;p>VS Code es uno de los editores más populares actualmente y cuenta con un ecosistema de extensiones muy potente incluso para la escritura en Markdown.&lt;/p>
&lt;h3 id="extensiones-recomendadas">Extensiones recomendadas
&lt;/h3>&lt;p>Para acelerar la escritura, se recomienda encarecidamente instalar las siguientes extensiones.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Markdown All in One&lt;/strong>: Cuenta con todas las funciones básicas necesarias para escribir en Markdown, como poner en negrita o cursiva mediante atajos de teclado, continuación automática de listas y generación automática de la tabla de contenido (TOC).&lt;/li>
&lt;li>&lt;strong>markdownlint&lt;/strong>: Advierte en tiempo real sobre errores de sintaxis y violaciones de estilo en Markdown.&lt;/li>
&lt;li>&lt;strong>vscode-textlint&lt;/strong>: Aplica un conjunto de reglas orientado a documentos técnicos, previniendo inconsistencias y errores gramaticales.&lt;/li>
&lt;/ol>
&lt;h3 id="configuración-de-fragmentos-personalizados-para-hugo-markdownjson">Configuración de fragmentos personalizados para Hugo (&lt;code>markdown.json&lt;/code>)
&lt;/h3>&lt;p>Si estás utilizando generadores de sitios estáticos como Hugo o Docusaurus para tu blog técnico, es probable que ingreses Frontmatter o tus propios shortcodes con frecuencia. Usando la función de fragmentos (snippets) de VS Code, puedes desplegarlos en un instante.&lt;/p>
&lt;p>Selecciona &lt;code>Preferences: Configure User Snippets&lt;/code> desde la paleta de comandos y agrega la siguiente configuración en &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:Título}\&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:Categoría}\&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:Etiqueta1}\&amp;#34;, \&amp;#34;${5:Etiqueta2}\&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;Despliega el YAML Frontmatter para 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:Título de la imagen}\&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 de 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:Header 1} | ${2:Header 2} | ${3:Header 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:Row 1} | ${5:Data} | ${6:Data} |&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:Row 2} | ${8:Data} | ${9:Data} |&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;Genera una tabla Markdown de 3 columnas&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>Con esta configuración, con solo escribir &lt;code>frontmatter&lt;/code> y presionar la tecla Tabulador, el YAML Frontmatter que incluye la hora actual se desplegará instantáneamente, aumentando drásticamente la velocidad inicial de escritura.&lt;/p>
&lt;h3 id="asistencia-de-escritura-con-github-copilot">Asistencia de escritura con GitHub Copilot
&lt;/h3>&lt;p>Cuando habilitas GitHub Copilot en VS Code, la autocompletación de IA sensible al contexto también funciona en Markdown. Especialmente en el caso de blogs técnicos, la IA predice y propone &amp;ldquo;la siguiente estructura a explicar&amp;rdquo; o &amp;ldquo;bloques de código relacionados&amp;rdquo;, lo que permite reducir significativamente el tiempo de escritura $T_{type}$.&lt;/p>
&lt;h2 id="3-personalización-extrema-en-neovim">3. Personalización extrema en Neovim
&lt;/h2>&lt;p>Aunque la interfaz gráfica (GUI) de VS Code es excelente, para los entusiastas de la terminal y los usuarios de Vim, Neovim es la opción más poderosa, ya que permite hacer todo sin soltar las manos del teclado.&lt;/p>
&lt;h3 id="arquitectura-lsp-de-neovim">Arquitectura LSP de Neovim
&lt;/h3>&lt;p>La arquitectura de LSP (Language Server Protocol) y Linter de Neovim en un entorno Markdown es la siguiente.&lt;/p>
&lt;pre class="mermaid">
classDiagram
class Neovim {
+&amp;#34;Búfer de texto&amp;#34;
+&amp;#34;Mapas de teclado&amp;#34;
}
class nvim_lspconfig {
+&amp;#34;marksman (LSP para Markdown)&amp;#34;
}
class null_ls_or_none_ls {
+&amp;#34;markdownlint&amp;#34;
+&amp;#34;textlint&amp;#34;
}
class LuaSnip {
+&amp;#34;Fragmentos dinámicos&amp;#34;
}
class CMP {
+&amp;#34;Motor de autocompletado&amp;#34;
}
Neovim --&amp;gt; nvim_lspconfig : &amp;#34;Proporciona funciones semánticas&amp;#34;
Neovim --&amp;gt; null_ls_or_none_ls : &amp;#34;Diagnósticos y formato&amp;#34;
Neovim --&amp;gt; CMP : &amp;#34;Solicitud de autocompletado&amp;#34;
CMP --&amp;gt; nvim_lspconfig : &amp;#34;Fuente LSP&amp;#34;
CMP --&amp;gt; LuaSnip : &amp;#34;Fuente de fragmentos&amp;#34;
&lt;/pre>
&lt;h3 id="despliegue-avanzado-de-fragmentos-usando-luasnip">Despliegue avanzado de fragmentos usando LuaSnip
&lt;/h3>&lt;p>Más potente que los fragmentos JSON de VS Code es el plugin para Neovim &lt;code>LuaSnip&lt;/code>. Utilizando la lógica de Lua, permite calcular y desplegar dinámicamente el contenido de los fragmentos.&lt;/p>
&lt;p>A continuación se muestra un ejemplo de configuración de LuaSnip que obtiene la fecha y hora actuales dinámicamente y despliega el 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">-- Función para obtener la hora actual 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;Título&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;slug-name&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;Categoría&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;Etiqueta&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;Encabezado 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;Encabezado 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;Celda 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;Celda 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>De esta manera, aprovechando el poder del lenguaje de programación (Lua), es posible crear fragmentos asombrosos que no solo contienen cadenas fijas, sino que también incrustan los valores de retorno de funciones, o aumentan y disminuyen dinámicamente el número de columnas de una tabla según la cantidad de caracteres ingresados.&lt;/p>
&lt;h2 id="4-análisis-estático-para-equilibrar-calidad-y-velocidad-de-escritura-textlint-y-expresiones-regulares">4. Análisis estático para equilibrar calidad y velocidad de escritura (textlint y expresiones regulares)
&lt;/h2>&lt;p>Para asegurar la calidad del blog, es necesario prevenir errores tipográficos e inconsistencias. Si esto se hace manualmente, $T_{review}$ aumentaría de manera explosiva, por lo que introduciremos el análisis estático usando &lt;code>textlint&lt;/code>.&lt;/p>
&lt;h3 id="introducción-a-textlint-y-el-conjunto-de-reglas-para-japonés">Introducción a textlint y el conjunto de reglas para japonés
&lt;/h3>&lt;p>Instalaremos textlint en un entorno de 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>Crea un archivo &lt;code>.textlintrc.json&lt;/code> en la raíz del proyecto y configúralo de la siguiente manera.&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>Crea &lt;code>prh.yml&lt;/code> y define la inconsistencia de los términos técnicos. Por ejemplo, unifica &amp;ldquo;サーバー&amp;rdquo; (servidor) y &amp;ldquo;サーバ&amp;rdquo;, o &amp;ldquo;Javascript&amp;rdquo; y &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;サーバー&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;サーバ&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;インターフェース&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;インターフェイス&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>Gracias a esto, cada vez que escribas en el editor, se te advertirá en tiempo real sobre las inconsistencias en la escritura, reduciendo el tiempo de corrección a casi cero.&lt;/p>
&lt;h3 id="patrones-estructurados-y-reemplazo-masivo-utilizando-expresiones-regulares">Patrones estructurados y reemplazo masivo utilizando expresiones regulares
&lt;/h3>&lt;p>Cuando migras artículos existentes a Markdown o traes texto de fuentes externas, el reemplazo masivo usando expresiones regulares resulta muy útil.&lt;/p>
&lt;p>Por ejemplo, la expresión regular para convertir la etiqueta HTML &lt;code>&amp;lt;b&amp;gt;énfasis&amp;lt;/b&amp;gt;&lt;/code> a &lt;code>**énfasis**&lt;/code> en Markdown:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Patrón de búsqueda&lt;/strong>: &lt;code>&amp;lt;b&amp;gt;(.*?)&amp;lt;/b&amp;gt;&lt;/code>&lt;/li>
&lt;li>&lt;strong>Patrón de reemplazo&lt;/strong>: &lt;code>**$1**&lt;/code>&lt;/li>
&lt;/ul>
&lt;p>Para combinar saltos de línea consecutivos innecesarios en uno solo:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Patrón de búsqueda&lt;/strong>: &lt;code>\n{3,}&lt;/code>&lt;/li>
&lt;li>&lt;strong>Patrón de reemplazo&lt;/strong>: &lt;code>\n\n&lt;/code>&lt;/li>
&lt;/ul>
&lt;p>Al ejecutar esto con la función de búsqueda y reemplazo de VS Code (modo de expresiones regulares) o el comando &lt;code>%s&lt;/code> de Neovim (&lt;code>:%s/&amp;lt;b&amp;gt;\(.*?\)&amp;lt;\/b&amp;gt;/**\1**/g&lt;/code>), puedes unificar el formato al instante.&lt;/p>
&lt;h3 id="comprobación-automática-mediante-el-canal-pipeline-cicd">Comprobación automática mediante el canal (pipeline) CI/CD
&lt;/h3>&lt;p>Además, usando GitHub Actions, puedes construir una canalización CI que ejecute automáticamente textlint cuando subas (push) artículos al blog. Esto evita proactivamente el despliegue de artículos que infrinjan las reglas.&lt;/p>
&lt;pre class="mermaid">
flowchart TD
A[&amp;#34;Autor&amp;#34;] --&amp;gt;|Empujar cambios| B[&amp;#34;Repositorio de GitHub&amp;#34;]
B --&amp;gt; C{&amp;#34;GitHub Actions Activado&amp;#34;}
C --&amp;gt; D[&amp;#34;Checkout del repositorio&amp;#34;]
D --&amp;gt; E[&amp;#34;Configurar Node.js&amp;#34;]
E --&amp;gt; F[&amp;#34;npm install&amp;#34;]
F --&amp;gt; G[&amp;#34;Ejecutar textlint&amp;#34;]
G --&amp;gt;|Éxito| H[&amp;#34;Construir sitio Hugo&amp;#34;]
G --&amp;gt;|Fallo| I[&amp;#34;Informar error al PR/Commit&amp;#34;]
H --&amp;gt; J[&amp;#34;Desplegar en Hosting (Vercel/Netlify)&amp;#34;]
&lt;/pre>
&lt;h2 id="5-técnicas-de-escritura-en-markdown-en-la-era-de-los-llm">5. Técnicas de escritura en Markdown en la era de los LLM
&lt;/h2>&lt;p>En la redacción moderna de blogs técnicos, el uso de LLM (Grandes Modelos de Lenguaje) es inevitable. Al aprovechar las herramientas de IA integradas en el editor, la velocidad de escritura se duplica aún más.&lt;/p>
&lt;h3 id="ingeniería-de-prompts-dentro-del-editor">Ingeniería de prompts dentro del editor
&lt;/h3>&lt;p>Usando GitHub Copilot Chat en VS Code, o plugins como &lt;code>ChatGPT.nvim&lt;/code> o &lt;code>Copilot.vim&lt;/code> en Neovim, puedes lanzar prompts como los siguientes sin salir del editor.&lt;/p>
&lt;blockquote>
&lt;p>&amp;ldquo;Crea un esquema en estructura jerárquica de Markdown para principiantes sobre los siguientes elementos técnicos: Docker, Kubernetes, CI/CD&amp;rdquo;&lt;/p>
&lt;/blockquote>
&lt;p>De este modo, se generarán instantáneamente los encabezados y listas en Markdown. Solo tenemos que desarrollar y añadir contenido a esa estructura.&lt;/p>
&lt;p>Además, al darle instrucciones a la IA, también puede generar una sintaxis precisa para diagramas complejos de Mermaid y fórmulas matemáticas (LaTeX). Por ejemplo, la base de las fórmulas matemáticas y los diseños de diagramas de este artículo también se aceleró gracias a la escritura colaborativa (pair writing) con un LLM.&lt;/p>
&lt;h2 id="6-conclusión">6. Conclusión
&lt;/h2>&lt;p>En este artículo explicamos configuraciones del editor que duplicarán tu velocidad de escritura al crear un blog técnico en Markdown.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Conciencia del modelo matemático&lt;/strong>: Erradicar el trabajo repetitivo para maximizar $T_{saved}$.&lt;/li>
&lt;li>&lt;strong>Aprovechar VS Code&lt;/strong>: Omitir la entrada manual utilizando extensiones y fragmentos en &lt;code>markdown.json&lt;/code>.&lt;/li>
&lt;li>&lt;strong>Personalización extrema de Neovim&lt;/strong>: Fragmentos dinámicos a través de &lt;code>LuaSnip&lt;/code> y control total mediante el teclado.&lt;/li>
&lt;li>&lt;strong>textlint y análisis estático&lt;/strong>: Integración de CI/CD y Linters locales para acercar el tiempo de revisión a cero.&lt;/li>
&lt;li>&lt;strong>Integración de LLM&lt;/strong>: Hacer que la IA genere directamente la estructura del Markdown y el código de diagramas o tablas dentro del editor.&lt;/li>
&lt;/ol>
&lt;p>Al incorporar estas configuraciones a tu propio entorno, desaparecerá lo &amp;ldquo;tedioso&amp;rdquo; de la escritura y, con seguridad, la cantidad y calidad de tus publicaciones técnicas mejorarán drásticamente. ¿Por qué no empezar hoy mismo registrando al menos un pequeño fragmento (snippet)?&lt;/p></description></item><item><title>Cómo alojar tu blog Hugo gratis y ultrarrápido con Cloudflare Pages y GitHub Pages</title><link>http://kenji.blog/es/p/hugo-hosting-cloudflare-vs-github-pages/</link><pubDate>Sat, 12 Sep 2026 12:00:00 +0900</pubDate><guid>http://kenji.blog/es/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 Cómo alojar tu blog Hugo gratis y ultrarrápido con Cloudflare Pages y GitHub Pages" />&lt;p>Al administrar un sitio web o un blog, la velocidad de carga (rendimiento), los costos operativos y la seguridad son factores extremadamente importantes. En el pasado, la combinación de un CMS (Sistema de Gestión de Contenidos) dinámico como WordPress y un servidor de alojamiento era la corriente principal, pero actualmente la arquitectura llamada &amp;ldquo;Jamstack&amp;rdquo; está atrayendo mucha atención. Entre ellos, combinando &amp;ldquo;Hugo&amp;rdquo;, un generador de sitios estáticos (SSG) ultrarrápido escrito en Go, con servicios de alojamiento modernos como Cloudflare Pages y GitHub Pages, es posible construir un entorno de blog &lt;strong>completamente gratuito y ultrarrápido&lt;/strong>.&lt;/p>
&lt;p>En este artículo, profundizaremos desde un punto de vista técnico en los pasos específicos para publicar un sitio estático usando Hugo en Cloudflare Pages o GitHub Pages, las diferencias en la arquitectura de cada plataforma, la construcción de CI/CD (Integración Continua / Despliegue Continuo) usando GitHub Actions, la optimización de DNS, las estrategias de caché, y la introducción de análisis de acceso que respetan la privacidad.&lt;/p>
&lt;hr>
&lt;h2 id="1-fundamentos-de-los-generadores-de-sitios-estáticos-ssg-y-jamstack">1. Fundamentos de los Generadores de Sitios Estáticos (SSG) y Jamstack
&lt;/h2>&lt;h3 id="11-por-qué-un-sitio-estático">1.1 ¿Por qué un sitio estático?
&lt;/h3>&lt;p>Los CMS dinámicos tradicionales (ej. WordPress) consultan la base de datos (como MySQL) por cada solicitud del usuario y generan HTML dinámicamente en el lado del servidor (como PHP) para devolverlo. Si bien este método es altamente flexible, tiene poca resistencia a los aumentos repentinos de tráfico (los llamados picos de popularidad o ataques DDoS) y a menudo complica la configuración de la infraestructura, requiriendo colocar servidores de caché (Redis o Varnish) en primer plano.&lt;/p>
&lt;p>Por otro lado, en los generadores de sitios estáticos (SSG) que adoptan la arquitectura Jamstack (JavaScript, APIs y Markup), todos los archivos HTML, CSS y JavaScript se generan por adelantado (durante el tiempo de compilación). Dado que el servidor web (o CDN) simplemente devuelve los archivos estáticos ya generados en respuesta a las solicitudes de los usuarios, se puede lograr una velocidad abrumadora y una seguridad robusta.&lt;/p>
&lt;h3 id="12-la-superioridad-de-hugo">1.2 La superioridad de Hugo
&lt;/h3>&lt;p>Existen varias opciones de SSG como Next.js, Gatsby, Jekyll y Astro, pero la mayor característica de Hugo es su &lt;strong>velocidad de compilación&lt;/strong>. Beneficiándose del procesamiento concurrente de Go, la compilación de un sitio de miles a decenas de miles de páginas se completa en solo unos segundos. Esto reduce drásticamente el tiempo de espera en el pipeline CI/CD y se traduce directamente en una mejora de la experiencia del desarrollador (DX: Developer Experience).&lt;/p>
&lt;hr>
&lt;h2 id="2-comparación-de-arquitecturas-de-servicios-de-alojamiento">2. Comparación de arquitecturas de servicios de alojamiento
&lt;/h2>&lt;p>El siguiente desafío es dónde alojar los archivos estáticos generados con Hugo. Las opciones representativas incluyen Cloudflare Pages, GitHub Pages y Netlify, pero la arquitectura de red detrás de cada una es diferente.&lt;/p>
&lt;h3 id="21-cdn-y-edge-computing">2.1 CDN y Edge Computing
&lt;/h3>&lt;p>Todas estas plataformas utilizan CDNs (Redes de Entrega de Contenido) distribuidas globalmente para entregar contenido. Sin embargo, el factor diferenciador es si el &amp;ldquo;edge computing&amp;rdquo; (computación en el borde) puede ejecutar el enrutamiento de solicitudes y la reescritura de encabezados en el PoP (Point of Presence) más cercano al usuario, y no solo almacenar en caché archivos estáticos.&lt;/p>
&lt;pre class="mermaid">
graph TD
A[&amp;#34;Usuario (Tokio)&amp;#34;] --&amp;gt;|Baja Latencia| B[&amp;#34;Nodo Edge (NRT)&amp;#34;]
C[&amp;#34;Usuario (Nueva York)&amp;#34;] --&amp;gt;|Baja Latencia| D[&amp;#34;Nodo Edge (EWR)&amp;#34;]
E[&amp;#34;Usuario (Londres)&amp;#34;] --&amp;gt;|Baja Latencia| F[&amp;#34;Nodo Edge (LHR)&amp;#34;]
B --&amp;gt; G[&amp;#34;Almacenamiento de Origen / Almacén de Objetos&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 es un servicio que permite publicar archivos HTML, CSS y JavaScript directamente desde un repositorio de GitHub. Detrás utiliza un CDN como Fastly y ofrece un rendimiento suficiente. Sin embargo, las capacidades como infraestructura pura son un poco modestas, con restricciones en la personalización de encabezados (ej. configuración de &lt;code>Cache-Control&lt;/code> y encabezados de seguridad) y la dependencia de meta refresh de HTML o plugins de Jekyll para la configuración de redirecciones.&lt;/p>
&lt;h3 id="23-cloudflare-pages">2.3 Cloudflare Pages
&lt;/h3>&lt;p>Cloudflare Pages es un servicio de alojamiento de sitios estáticos construido sobre la red Anycast a nivel mundial de la que Cloudflare se enorgullece (desplegada en más de 275 ciudades).
Permite un ajuste de rendimiento abrumador, incluyendo soporte estándar para HTTP/3 (QUIC), optimización de imágenes y la integración de funciones edge (Cloudflare Workers). Además, una gran ventaja es que no hay cargos por ancho de banda, por lo que se puede operar de forma gratuita sin importar cuánto aumente el tráfico.&lt;/p>
&lt;h3 id="24-netlify">2.4 Netlify
&lt;/h3>&lt;p>Netlify es un pionero de Jamstack y proporciona un DX todo en uno que integra funciones de formularios, autenticación (Identity), funciones serverless, etc. Sin embargo, una vez que se supera el ancho de banda del nivel gratuito (100 GB por mes), se incurren en altos cargos por uso, por lo que se requiere cuidado con la gestión de costos en blogs que utilizan muchas imágenes o videos.&lt;/p>
&lt;hr>
&lt;h2 id="3-cálculo-teórico-del-rendimiento-y-la-latencia-modelo-matemático-con-latex">3. Cálculo teórico del rendimiento y la latencia (Modelo matemático con LaTeX)
&lt;/h2>&lt;p>Al evaluar el rendimiento web, la reducción de la latencia (Latency) es el indicador más importante. Modelemos cuánta latencia se reduce al usar una CDN (edge) en comparación con acceder directamente al servidor de origen.&lt;/p>
&lt;p>Supongamos que la probabilidad de que la solicitud de un usuario acierte en la caché es el &amp;ldquo;Ratio de aciertos de caché (Cache Hit Ratio)&amp;rdquo; y la denotamos como $C$. Donde $0 \le C \le 1$.
Dejamos que la latencia hasta el servidor de origen sea $L_{origin}$, y la latencia hasta el nodo edge más cercano sea $L_{edge}$.&lt;/p>
&lt;p>La nueva latencia promedio $L_{new}$ se calcula como el siguiente valor esperado:&lt;/p>
$$ L_{new} = C \times L_{edge} + (1 - C) \times (L_{edge} + L_{origin}) $$&lt;p>Simplificando esta fórmula obtenemos lo siguiente:&lt;/p>
$$ L_{new} = L_{edge} + (1 - C) \times L_{origin} $$&lt;p>Por ejemplo, si un usuario en Tokio accede a un servidor de origen ubicado en la costa este de los EE. UU. (Nueva York), considerando la distancia física de la fibra óptica y el retraso de procesamiento en los enrutadores, $L_{origin}$ será de aproximadamente 200 ms. Por otro lado, si se utiliza una CDN como Cloudflare, el usuario puede conectarse al nodo edge en Tokio, por lo que $L_{edge}$ se reducirá a unos 10 ms.&lt;/p>
&lt;p>Asumiendo que el ratio de aciertos de caché $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>De esta manera, la introducción de una CDN hace posible reducir drásticamente (alrededor del 90%) la latencia promedio de 210 ms a 20 ms.&lt;/p>
&lt;hr>
&lt;h2 id="4-construcción-del-pipeline-cicd-utilizando-github-actions">4. Construcción del pipeline CI/CD utilizando GitHub Actions
&lt;/h2>&lt;p>Para automatizar el proceso de actualización del blog de Hugo, construiremos un pipeline CI/CD utilizando GitHub Actions. Con esto, simplemente escribiendo artículos en Markdown localmente y ejecutando &lt;code>git push&lt;/code>, la compilación se ejecutará automáticamente y se desplegará en Cloudflare Pages o GitHub Pages.&lt;/p>
&lt;p>El siguiente diagrama de secuencia muestra el flujo general desde que se hace push a un artículo hasta que se entrega al usuario.&lt;/p>
&lt;pre class="mermaid">
sequenceDiagram
participant U as &amp;#34;Usuario (Autor)&amp;#34;
participant G as &amp;#34;Repositorio de 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;Visitante&amp;#34;
U-&amp;gt;&amp;gt;G: &amp;#34;git push origin main&amp;#34;
G-&amp;gt;&amp;gt;A: &amp;#34;Desencadenar Evento Push&amp;#34;
A-&amp;gt;&amp;gt;A: &amp;#34;Checkout y Configurar Hugo&amp;#34;
A-&amp;gt;&amp;gt;A: &amp;#34;hugo --minify (Compilación)&amp;#34;
A-&amp;gt;&amp;gt;C: &amp;#34;Desplegar en Cloudflare Pages (Carga Directa)&amp;#34;
C--&amp;gt;&amp;gt;A: &amp;#34;URL de Despliegue (Éxito)&amp;#34;
V-&amp;gt;&amp;gt;C: &amp;#34;Solicitar Página Web&amp;#34;
C--&amp;gt;&amp;gt;V: &amp;#34;Devolver HTML en Caché (Edge)&amp;#34;
&lt;/pre>
&lt;h3 id="41-configuración-de-despliegue-para-cloudflare-pages-direct-upload">4.1 Configuración de despliegue para Cloudflare Pages (Direct Upload)
&lt;/h3>&lt;p>En Cloudflare Pages, hay un método para vincular un repositorio de GitHub y construir en la infraestructura de Cloudflare, y un método para &amp;ldquo;Direct Upload&amp;rdquo; (cargar directamente) archivos estáticos compilados con GitHub Actions. Si deseas gestionar las versiones de Hugo más estrictamente y vincularlas con otros trabajos (pruebas y optimización de imágenes), se recomienda el método de compilar en GitHub Actions y hacer un Direct Upload.&lt;/p>
&lt;p>A continuación se muestra un ejemplo práctico de &lt;code>.github/workflows/deploy.yml&lt;/code> para desplegar en 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>En este pipeline, HTML/CSS/JS se minimizan mediante la opción &lt;code>--minify&lt;/code>, y los archivos innecesarios se eliminan mediante &lt;code>--gc&lt;/code>. Estos son los conceptos básicos de la optimización del rendimiento.&lt;/p>
&lt;hr>
&lt;h2 id="5-profundizando-en-la-configuración-dns-dominios-personalizados-y-registros-cname--alias">5. Profundizando en la configuración DNS: Dominios personalizados y registros CNAME / ALIAS
&lt;/h2>&lt;p>Cuando se utiliza un dominio personalizado (ej: &lt;code>kenji.blog&lt;/code>), es esencial una configuración adecuada del DNS (Sistema de Nombres de Dominio).&lt;/p>
&lt;h3 id="51-restricciones-de-registros-cname-y-zone-apex">5.1 Restricciones de registros CNAME y Zone Apex
&lt;/h3>&lt;p>Normalmente, al dirigir un subdominio (ej: &lt;code>www.kenji.blog&lt;/code>) a un servicio externo, se utiliza un registro &lt;code>CNAME&lt;/code>. Sin embargo, debido a las especificaciones DNS (RFC 1034), no se puede configurar un registro &lt;code>CNAME&lt;/code> en el dominio raíz (también llamado Zone Apex o dominio desnudo. Ej: &lt;code>kenji.blog&lt;/code>). Esto se debe a la regla de que registros como SOA (Start of Authority), NS (Name Server) y MX (Mail Exchange) deben existir en el Zone Apex, y un CNAME no puede coexistir con otros registros de recursos.&lt;/p>
&lt;h3 id="52-soluciones-alias--aname--cname-flattening">5.2 Soluciones: ALIAS / ANAME / CNAME Flattening
&lt;/h3>&lt;p>Para resolver este problema, los proveedores de DNS modernos ofrecen sus propias extensiones.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Registros ALIAS / ANAME&lt;/strong>: Resuelven dinámicamente nombres en el lado del servidor DNS y devuelven el registro A final (dirección IP) al cliente. Amazon Route 53 y otros lo admiten.&lt;/li>
&lt;li>&lt;strong>CNAME Flattening&lt;/strong>: Una función proporcionada por Cloudflare. Mientras se comporta como si un CNAME estuviera configurado en el Zone Apex, el servidor DNS autoritativo de Cloudflare devuelve de manera transparente al cliente el grupo de direcciones IP (registros A y AAAA) resueltos automáticamente.&lt;/li>
&lt;/ul>
&lt;p>Al usar Cloudflare Pages, delegar los servidores de nombres de dominio a Cloudflare y utilizar este &amp;ldquo;CNAME Flattening&amp;rdquo; es la configuración más eficiente y de mayor rendimiento.&lt;/p>
&lt;hr>
&lt;h2 id="6-estrategias-de-caché-y-control-de-encabezados-http">6. Estrategias de caché y control de encabezados HTTP
&lt;/h2>&lt;p>Otra clave para acelerar sitios estáticos es la &amp;ldquo;estrategia de caché&amp;rdquo;. En Cloudflare Pages, se pueden controlar en detalle los encabezados de respuesta HTTP utilizando un archivo generado (el archivo &lt;code>_headers&lt;/code>).&lt;/p>
&lt;h3 id="61-edge-cache-vs-browser-cache">6.1 Edge Cache vs Browser Cache
&lt;/h3>&lt;p>La caché se divide a grandes rasgos en dos tipos: la &amp;ldquo;Edge Cache&amp;rdquo; que se retiene en el lado del CDN, y la &amp;ldquo;Browser Cache&amp;rdquo; que se guarda en el navegador del usuario.&lt;/p>
&lt;p>Lo ideal es permitir que los archivos estáticos (imágenes, CSS, JS, etc., aquellos con hashes en sus nombres de archivo) se almacenen en la caché del navegador durante un largo período de tiempo. Por otro lado, para que los archivos HTML reflejen las actualizaciones de inmediato, la configuración común es acortar (o deshabilitar) la caché del navegador y manejarla en la caché del edge.&lt;/p>
&lt;p>Ejemplo de configuración de &lt;code>_headers&lt;/code> en 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"># Los archivos HTML no se almacenan en la caché del navegador y se validan cada vez
&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"># Los archivos de recursos (CSS/JS/imágenes) se almacenan en la caché del navegador por 1 año
&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-fórmula-para-reducir-los-costos-de-ancho-de-banda">6.2 Fórmula para reducir los costos de ancho de banda
&lt;/h3>&lt;p>Al configurar los encabezados de caché adecuados, la cantidad de datos transferidos desde el servidor (edge) se puede reducir drásticamente. El costo mensual del ancho de banda $Cost$ se representa mediante el siguiente modelo, basado en la cantidad de transferencia de cada recurso $B_i$, el ratio de aciertos de caché $C_i$ y el precio unitario del ancho de banda $R$.&lt;/p>
$$ Cost = \sum_{i=1}^{n} \left( B_i \times (1 - C_i) \times R \right) $$&lt;p>Dado que la transferencia de salida es gratuita en Cloudflare ($R = 0$), el costo monetario directo se convierte en $0$. Sin embargo, cuando se usa junto con otra infraestructura como GitHub Pages, o cuando se usa AWS S3 como backend, maximizar este ratio de aciertos de caché $C_i$ es clave para reducir los costos de infraestructura.&lt;/p>
&lt;hr>
&lt;h2 id="7-análisis-de-acceso-equilibrando-privacidad-y-rendimiento">7. Análisis de acceso equilibrando privacidad y rendimiento
&lt;/h2>&lt;p>Al gestionar un blog, el análisis de acceso (Web Analytics) para saber cuántos usuarios lo visitan es indispensable. Google Analytics (GA4) ha sido el estándar de facto durante mucho tiempo, pero la situación está cambiando con las recientes tendencias de protección de la privacidad (GDPR, CCPA) y la abolición de las cookies de terceros.&lt;/p>
&lt;h3 id="71-impacto-en-el-rendimiento-web">7.1 Impacto en el rendimiento web
&lt;/h3>&lt;p>Cuando se introduce Google Analytics (específicamente &lt;code>gtag.js&lt;/code> o Google Tag Manager), se cargan y ejecutan muchos scripts externos, lo que afecta negativamente al rendimiento (especialmente al TTFB y al tiempo de bloqueo del hilo principal).&lt;/p>
&lt;p>Desglosemos los tiempos de carga del sitio de la siguiente manera:&lt;/p>
&lt;pre class="mermaid">
pie title Desglose de los tiempos de carga típicos del sitio
&amp;#34;TTFB (Tiempo hasta el Primer Byte)&amp;#34; : 15
&amp;#34;Descarga de Contenido (HTML/CSS)&amp;#34; : 20
&amp;#34;Análisis y Renderizado del DOM&amp;#34; : 45
&amp;#34;Analítica y JS de terceros&amp;#34; : 20
&lt;/pre>
&lt;p>No es raro que las herramientas de análisis JS de terceros representen alrededor del 20% al 30% del tiempo de carga total.&lt;/p>
&lt;h3 id="72-introducción-a-cloudflare-web-analytics">7.2 Introducción a Cloudflare Web Analytics
&lt;/h3>&lt;p>Por lo tanto, la atención se centra en los análisis de acceso que priorizan la privacidad y que no utilizan cookies (Cookieless), como Cloudflare Web Analytics y Plausible Analytics.&lt;/p>
&lt;p>Cloudflare Web Analytics funciona simplemente incrustando un fragmento de JavaScript muy ligero y no emite cookies, por lo que no es necesario instalar un molesto banner de consentimiento de cookies (Cookie Consent Banner).&lt;/p>
&lt;p>Su implementación en Hugo también es muy sencilla. Simplemente añade el fragmento proporcionado en &lt;code>layouts/partials/head.html&lt;/code> o &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>Al agregar el atributo &lt;code>defer&lt;/code>, el script se puede cargar de forma asíncrona sin bloquear el análisis de HTML y ejecutarse después de que se construya el DOM. Esto minimiza el impacto en la velocidad de visualización inicial (LCP: Largest Contentful Paint y FCP: First Contentful Paint).&lt;/p>
&lt;hr>
&lt;h2 id="8-conclusión-y-mejores-prácticas">8. Conclusión y Mejores Prácticas
&lt;/h2>&lt;p>En la operación de un sitio estático usando Hugo, adoptar plataformas de alojamiento modernas como Cloudflare Pages o GitHub Pages tiene beneficios abrumadores en términos de rentabilidad, velocidad de visualización y seguridad.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Compilación ultrarrápida&lt;/strong>: Aprovechar la velocidad de Hugo para minimizar el tiempo de ejecución del pipeline CI/CD (GitHub Actions).&lt;/li>
&lt;li>&lt;strong>Entrega en el edge&lt;/strong>: Utilizar la red edge de Cloudflare para entregar contenido a usuarios de todo el mundo con latencia de milisegundos.&lt;/li>
&lt;li>&lt;strong>Configuración adecuada de DNS&lt;/strong>: Aprovechar CNAME Flattening para operar el Zone Apex (dominio personalizado) de manera segura y rápida.&lt;/li>
&lt;li>&lt;strong>Optimización de la estrategia de caché&lt;/strong>: Usar &lt;code>_headers&lt;/code> para separar adecuadamente la caché del navegador y la caché del edge para cada tipo de recurso.&lt;/li>
&lt;li>&lt;strong>Analíticas ligeras&lt;/strong>: Introducir Cloudflare Web Analytics, etc., que no comprometen el rendimiento al tiempo que respetan la privacidad.&lt;/li>
&lt;/ol>
&lt;p>Al combinar estos elementos, es posible construir un sistema de blog escalable y robusto que puede soportar grandes volúmenes de tráfico de millones de visitas mensuales de forma gratuita. Si estás considerando lanzar un blog técnico, un sitio corporativo o un portafolio, definitivamente prueba esta configuración de Jamstack + Hugo + Cloudflare Pages.&lt;/p></description></item><item><title>Estrategia para reescribir artículos técnicos pasados utilizando Google Search Console</title><link>http://kenji.blog/es/p/google-search-console-rewrite-strategy/</link><pubDate>Sat, 12 Sep 2026 12:00:00 +0900</pubDate><guid>http://kenji.blog/es/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 Estrategia para reescribir artículos técnicos pasados utilizando Google Search Console" />&lt;h2 id="1-introducción-la-importancia-de-reescribir-en-blogs-técnicos-y-el-enfoque-basado-en-datos">1. Introducción: La importancia de reescribir en blogs técnicos y el enfoque basado en datos
&lt;/h2>&lt;p>Al gestionar un blog técnico o medios propios para desarrolladores, &amp;ldquo;reescribir artículos pasados&amp;rdquo; es tan o más importante que la escritura continua de nuevos artículos. Especialmente en temas de TI y tecnología, la información se vuelve obsoleta rápidamente; no es raro que los fragmentos de código o las especificaciones de API escritos hace unos años estén ahora obsoletos (Deprecated). Sin embargo, simplemente actualizar ciegamente los artículos pasados no maximizará el tráfico (visitas) desde los motores de búsqueda.&lt;/p>
&lt;p>Por lo tanto, en este artículo explicaremos una estrategia avanzada para identificar qué artículos técnicos se deben reescribir y mejorar drásticamente las clasificaciones de búsqueda y el porcentaje de clics (CTR) utilizando datos de &lt;strong>Google Search Console (GSC)&lt;/strong> y &lt;strong>Google Analytics 4 (GA4)&lt;/strong>, con un enfoque matemático y basado en datos.&lt;/p>
&lt;p>Específicamente, cubriremos de manera exhaustiva todo, desde cómo integrar datos de GSC y GA4 usando Python o BigQuery para descubrir &amp;ldquo;artículos con pérdida de oportunidades&amp;rdquo; que tienen un CTR bajo en relación con el número de impresiones, hasta el uso del análisis TF-IDF de PNL (Procesamiento del Lenguaje Natural) para identificar palabras clave faltantes en los encabezados H2 y H3 y llenar eficientemente los vacíos de contenido.&lt;/p>
&lt;hr>
&lt;h2 id="2-análisis-de-brechas-entre-el-ctr-esperado-y-el-ctr-real-introducción-al-modelo-matemático">2. Análisis de brechas entre el CTR esperado y el CTR real (Introducción al modelo matemático)
&lt;/h2>&lt;p>Uno de los indicadores más fundamentales en SEO es el &amp;ldquo;porcentaje de clics (CTR) frente a la clasificación de búsqueda&amp;rdquo;. Generalmente, si la posición de búsqueda es el primer lugar, el CTR es de alrededor del 25-30%, en el segundo lugar es de aproximadamente el 15%, y disminuye drásticamente a partir de ahí. Esta relación entre la clasificación y el CTR se puede modelar como una distribución que sigue una ley de potencias (Power Law).&lt;/p>
&lt;p>Se sabe que el porcentaje de clics esperado $CTR(r)$ para una clasificación $r$ se puede aproximar mediante la siguiente fórmula.&lt;/p>
$$
CTR(r) = a \cdot r^{-b}
$$&lt;p>Aquí, $a$ representa el CTR esperado cuando está en el primer lugar (por ejemplo, $0.30$ para 30%) y $b$ representa el parámetro de decaimiento (generalmente entre $1.0$ y $1.5$).&lt;/p>
&lt;p>El enfoque más efectivo al seleccionar artículos para reescribir es &lt;strong>encontrar artículos (palabras clave) donde el &amp;ldquo;CTR real&amp;rdquo; esté significativamente por debajo de este &amp;ldquo;CTR esperado&amp;rdquo;&lt;/strong>. Por ejemplo, si la posición de búsqueda es el 3er lugar (CTR esperado de aproximadamente 10%) pero el CTR real es solo del 2%, se puede determinar que es muy probable que haya una discrepancia entre la intención de búsqueda y el título/descripción, o que los factores de la competencia, como los fragmentos enriquecidos (rich snippets), estén robando los clics.&lt;/p>
&lt;p>El siguiente gráfico es una imagen que muestra la discrepancia entre el CTR esperado y el CTR real en cierto blog técnico.&lt;/p>
&lt;pre class="mermaid">
xychart-beta
title CTR Esperado vs CTR Real por Posición
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>(* La gráfica de líneas muestra el CTR esperado y la gráfica de barras muestra el CTR real. Se puede confirmar que está significativamente por debajo en el 4º y 8º lugar.)&lt;/p>
&lt;hr>
&lt;h2 id="3-extracción-automática-de-datos-de-rendimiento-de-búsqueda-utilizando-la-api-de-gsc-python">3. Extracción automática de datos de rendimiento de búsqueda utilizando la API de GSC (Python)
&lt;/h2>&lt;p>Si bien es posible descargar y analizar CSV desde la interfaz de usuario web de GSC, para blogs a gran escala o análisis continuos, lo mejor es construir un sistema que extraiga datos automáticamente en Python utilizando la API de GSC.&lt;/p>
&lt;p>A continuación se muestra un fragmento de Python usando &lt;code>google-api-python-client&lt;/code> para obtener datos de rendimiento por página y consulta (clics, impresiones, CTR, posición promedio) durante un período específico.&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"># Cargar credenciales y construir el cliente 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"># Configuración del payload de la solicitud API (especificando página y consulta como dimensiones)&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"># Ejecutar la 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"># Extraer datos de la respuesta y convertirlos a un DataFrame de Pandas&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"># Ejemplo de ejecución&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>Con este script, se pueden obtener datos detallados vinculando la URL de la página y las consultas de búsqueda como un DataFrame. Esto hace posible comprender de manera integral con qué palabras clave se muestran artículos específicos.&lt;/p>
&lt;hr>
&lt;h2 id="4-filtrado-de-palabras-clave-técnicas-mediante-expresiones-regulares-regex">4. Filtrado de palabras clave técnicas mediante expresiones regulares (Regex)
&lt;/h2>&lt;p>Una característica muy poderosa al analizar blogs técnicos es el &lt;strong>filtro de expresiones regulares (Regex)&lt;/strong> de GSC.
Por ejemplo, si escribe una amplia gama de artículos, desde frontend hasta backend e infraestructura, es posible que desee extraer solo &amp;ldquo;artículos de tutoriales o errores sobre Python o Pandas&amp;rdquo; y priorizar su reescritura.&lt;/p>
&lt;p>El uso de filtros de expresiones regulares personalizados en GSC le permite refinar las consultas con condiciones complejas.&lt;/p>
&lt;p>&lt;strong>Ejemplos de filtrado de palabras clave técnicas:&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>Investigación de errores relacionados con Python: &lt;code>^(python|pandas|numpy|matplotlib).* (error|exception|bug|error|no funciona)&lt;/code>&lt;/li>
&lt;li>Construcción de infraestructura relacionada con AWS: &lt;code>(aws|amazon web services|ec2|s3|lambda).* (construir|configurar|tutorial|tutorial|cómo hacer)&lt;/code>&lt;/li>
&lt;li>Actualizaciones de versión de una librería específica: &lt;code>(react|vue|angular) (v17|v18|v3) (migration|migración|transición)&lt;/code>&lt;/li>
&lt;/ul>
&lt;p>Al incorporar esto a una solicitud de la API de GSC, utilice &lt;code>dimensionFilterGroups&lt;/code> para aplicar condiciones de expresiones regulares. Al dominar este filtrado, se pueden identificar y extraer exactamente las palabras clave de alto valor orientadas a resolver problemas que los desarrolladores &amp;ldquo;están buscando en este momento por estar atascados&amp;rdquo;.&lt;/p>
&lt;hr>
&lt;h2 id="5-integración-de-datos-de-ga4-y-gsc-mediante-bigquerypandas">5. Integración de datos de GA4 y GSC mediante BigQuery/Pandas
&lt;/h2>&lt;p>Solo con los datos de GSC, únicamente conocemos la &amp;ldquo;clasificación de búsqueda y el porcentaje de clics&amp;rdquo;. Para saber &amp;ldquo;cuánto tiempo se quedó un usuario que llegó a ese artículo y si se convirtió (por ejemplo, al hacer la transición a un repositorio de GitHub o suscribirse al boletín de noticias)&amp;rdquo;, es necesario integrar (JOIN) con los datos de &lt;strong>Google Analytics 4 (GA4)&lt;/strong>.&lt;/p>
&lt;p>Si almacena los datos de exportación de GA4 y los datos de exportación masiva de GSC en BigQuery, puede combinar ambos con una consulta SQL como la siguiente y extraer &amp;ldquo;artículos con muchas impresiones y clasificaciones de búsqueda decentes, pero con una alta tasa de rebote o un tiempo de interacción corto&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;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>Usando estos resultados, puede clasificar los artículos objetivo a reescribir con una matriz como esta:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Alta impresión, bajo CTR, alta participación (Engagement)&lt;/strong>:
Artículos con los que los lectores están satisfechos si tan solo hicieran clic en los resultados de búsqueda. La principal prioridad debe ser &lt;strong>corregir el título y la metadescripción&lt;/strong>.&lt;/li>
&lt;li>&lt;strong>Alto CTR, baja participación (Engagement)&lt;/strong>:
Artículos en los que se hace clic, pero el contenido decepciona y los lectores abandonan la página. Requiere una reescritura importante del cuerpo principal, como &lt;strong>mejorar la introducción, actualizar con el código más reciente o aumentar la exhaustividad de la información (agregar H2/H3)&lt;/strong>.&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="6-análisis-de-brechas-de-contenido-mediante-pnl-y-tf-idf">6. Análisis de brechas de contenido mediante PNL y TF-IDF
&lt;/h2>&lt;p>Una vez que se han identificado los artículos a reescribir, el siguiente paso es analizar &amp;ldquo;qué títulos específicos (H2/H3) o palabras clave deben agregarse&amp;rdquo;. En lugar de confiar en la intuición aquí también, utilizaremos &lt;strong>TF-IDF (Frecuencia de término – frecuencia inversa de documento) en el Procesamiento del Lenguaje Natural (PNL)&lt;/strong>.&lt;/p>
&lt;p>TF-IDF es una estadística para evaluar qué tan importante es una palabra dentro de ese documento.&lt;/p>
$$
TF\text{-}IDF(t, d) = tf(t, d) \times \log\left(\frac{N}{df(t)}\right)
$$&lt;p>Donde:&lt;/p>
&lt;ul>
&lt;li>$tf(t, d)$ es la frecuencia de aparición de la palabra $t$ en el documento $d$&lt;/li>
&lt;li>$N$ es el número total de documentos&lt;/li>
&lt;li>$df(t)$ es el número de documentos en los que aparece la palabra $t$&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>Enfoque:&lt;/strong>&lt;/p>
&lt;ol>
&lt;li>Obtener los datos de texto de los 10 artículos principales (sitios de la competencia) para la palabra clave objetivo usando scraping o similares.&lt;/li>
&lt;li>Preparar los datos de texto del artículo objetivo de su propio sitio.&lt;/li>
&lt;li>Usar &lt;code>TfidfVectorizer&lt;/code> de &lt;code>scikit-learn&lt;/code> en Python para extraer palabras clave (palabras características) que aparecen consistentemente con puntajes altos en los principales artículos competidores, pero que no existen o tienen un puntaje significativamente menor en el artículo de su propio sitio.&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 = [Texto del propio sitio, Texto del competidor 1, Texto del competidor 2, ...]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Aquí se asume una lista de textos ya segmentados mediante análisis morfológico (MeCab, etc.) para japonés&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"># Calcular la puntuación TF-IDF media de los artículos competidores (índice 1 en adelante)&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"># Obtener la puntuación TF-IDF del artículo propio (índice 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"># Calcular la brecha de las palabras que son importantes en la competencia pero faltan (o son pocas) en el sitio propio&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"># Extraer las palabras principales con la brecha más grande&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"># Ejemplo: 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>A través de este análisis, puede descubrir cuantitativamente &lt;strong>omisiones temáticas (brechas de contenido)&lt;/strong> como: &amp;ldquo;En realidad, los principales artículos mencionan &amp;lsquo;cómo implementar en contenedores Docker&amp;rsquo; o &amp;lsquo;cómo construir canalizaciones CI/CD&amp;rsquo;, pero mi artículo no lo aborda&amp;rdquo;.&lt;/p>
&lt;p>Las palabras clave importantes descubiertas no solo deben dispersarse en el cuerpo principal, sino que al agregarlas como secciones significativas como &lt;strong>títulos H2 o H3 (etiquetas de encabezado)&lt;/strong> y escribir explicaciones técnicas detalladas y fragmentos de código para ellas, puede mejorar drásticamente su calificación en Google.&lt;/p>
&lt;hr>
&lt;h2 id="7-flujo-de-datos-y-ciclo-de-mejora-continua">7. Flujo de datos y ciclo de mejora continua
&lt;/h2>&lt;p>El proceso explicado hasta ahora no es algo que se haga una vez y se acabe, sino que la clave del éxito en SEO es canalizarlo y ejecutarlo de forma continua. A continuación, se muestra la arquitectura general y el flujo operativo en un diagrama de flujo de Mermaid.&lt;/p>
&lt;pre class="mermaid">
flowchart TD
A[&amp;#34;Datos de API de GSC (Impresiones, Clics, Posiciones)&amp;#34;] --&amp;gt; C[&amp;#34;BigQuery / Almacén de Datos&amp;#34;]
B[&amp;#34;Datos de Exportación de GA4 (Vistas de Página, Tiempo de Participación)&amp;#34;] --&amp;gt; C
C --&amp;gt; D[&amp;#34;Unión de Datos y Análisis en Python / Pandas&amp;#34;]
D --&amp;gt; E[&amp;#34;Identificar Artículos con Altas Impresiones / Bajo CTR&amp;#34;]
E --&amp;gt; F[&amp;#34;Scraping de Competencia PNL y Extracción de Palabras Clave TF-IDF&amp;#34;]
F --&amp;gt; G[&amp;#34;Optimizar Etiquetas H2/H3 y Reescribir Contenido&amp;#34;]
G --&amp;gt; H[&amp;#34;Publicar Artículo Actualizado&amp;#34;]
H --&amp;gt; I[&amp;#34;Monitorear Cambios en CTR (Esperado vs Real)&amp;#34;]
I --&amp;gt; |&amp;#34;Bucle de Retroalimentación&amp;#34;| A
&lt;/pre>
&lt;p>De esta manera, mediante la sistematización de la serie de pasos desde la recopilación de datos de GSC y GA4, la selección de objetivos a través del análisis, la optimización de contenido mediante PNL y la supervisión de resultados, los medios de un blog se convierten en un activo que sigue creciendo automáticamente.&lt;/p>
&lt;hr>
&lt;h2 id="8-conclusión-y-perspectivas-a-futuro">8. Conclusión y perspectivas a futuro
&lt;/h2>&lt;p>Reescribir artículos técnicos utilizando Google Search Console no se trata simplemente de editar el texto. Es una ingeniería avanzada para presentar la solución óptima utilizando datos y modelos matemáticos a la caja negra que es el algoritmo del motor de búsqueda.&lt;/p>
&lt;p>Se resumen a continuación los métodos explicados en este artículo:&lt;/p>
&lt;ol>
&lt;li>Calcular la discrepancia entre el &lt;strong>CTR esperado y el CTR real&lt;/strong> para identificar los artículos donde la corrección tendrá un gran impacto.&lt;/li>
&lt;li>Extraer automáticamente los datos de rendimiento mediante la &lt;strong>API de GSC y Python&lt;/strong>.&lt;/li>
&lt;li>Unir los datos con el engagement de GA4 en &lt;strong>BigQuery&lt;/strong> y revisar el cuerpo del texto de los artículos con altas tasas de rebote.&lt;/li>
&lt;li>Mediante el &lt;strong>análisis PNL usando TF-IDF&lt;/strong>, descubrir brechas de contenido con respecto a los competidores y optimizar los encabezados (H2/H3).&lt;/li>
&lt;/ol>
&lt;p>Las tendencias tecnológicas cambian constantemente. Para responder con precisión a los errores y problemas que tienen los lectores en este momento, considere incorporar estrategias de reescritura basadas en datos en sus operaciones diarias.&lt;/p></description></item><item><title>Estrategias de SEO para blogs de Hugo: Configuración del Frontmatter para aumentar drásticamente el tráfico</title><link>http://kenji.blog/es/p/hugo-blog-seo-frontmatter-tips/</link><pubDate>Sat, 12 Sep 2026 12:00:00 +0900</pubDate><guid>http://kenji.blog/es/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 Estrategias de SEO para blogs de Hugo: Configuración del Frontmatter para aumentar drásticamente el tráfico" />&lt;p>Hugo es uno de los generadores de sitios estáticos (SSG) más rápidos del mundo, escrito en el lenguaje Go. Su abrumadora velocidad de construcción y flexible sistema de plantillas han ganado un inmenso apoyo de muchos ingenieros y blogueros. Sin embargo, el simple hecho de que un sitio se genere y muestre rápidamente no significa que sea altamente valorado por los motores de búsqueda (como Google o Bing) y que los artículos lleguen a los usuarios.&lt;/p>
&lt;p>Para mejorar el posicionamiento en búsquedas, aumentar el poder de difusión en redes sociales y, como resultado, aumentar drásticamente el tráfico al blog, es esencial contar con estrategias detalladas de SEO (Optimización para Motores de Búsqueda). El núcleo del SEO en Hugo es la colaboración entre el &lt;strong>frontmatter&lt;/strong>, que se escribe al principio de cada artículo en markdown, y las &lt;strong>plantillas (Layouts)&lt;/strong>, que lo interpretan para desplegar los metadatos dentro de la etiqueta &lt;code>&amp;lt;head&amp;gt;&lt;/code> del HTML.&lt;/p>
&lt;p>En este artículo, explicaremos exhaustivamente en un volumen abrumador de más de 10,000 caracteres, cómo aprovechar al máximo las características de Hugo e implementar estrategias avanzadas de SEO, desde la configuración del frontmatter, pasando por diversas metaetiquetas, OGP (Open Graph Protocol), Twitter Cards, hasta la salida de datos estructurados utilizando JSON-LD.&lt;/p>
&lt;hr>
&lt;h2 id="1-contexto-matemático-del-seo-y-el-tráfico">1. Contexto matemático del SEO y el tráfico
&lt;/h2>&lt;p>Antes de entrar en la implementación específica, comprendamos matemáticamente por qué los metadatos detallados de SEO son importantes. El tráfico de búsqueda $T$ que puede obtener un sitio web está determinado por el volumen de búsqueda de las palabras clave objetivo y el porcentaje de clics (CTR) basado en el ranking de búsqueda.&lt;/p>
&lt;p>Esto se puede expresar mediante la siguiente fórmula matemática:&lt;/p>
$$ T = \sum_{i=1}^{n} V_i \times CTR(R_i) $$&lt;ul>
&lt;li>$V_i$ : Volumen de búsqueda mensual de la palabra clave $i$&lt;/li>
&lt;li>$R_i$ : Posición en el ranking de búsqueda para la palabra clave $i$&lt;/li>
&lt;li>$CTR(R_i)$ : Porcentaje de clics en la posición $R_i$&lt;/li>
&lt;/ul>
&lt;p>De estos, el ranking de búsqueda $R_i$ depende de muchos factores como la calidad del contenido y los enlaces entrantes (PageRank), pero el algoritmo inicial de PageRank de Google se modela de la siguiente manera:&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 página $u$&lt;/li>
&lt;li>$d$ : Factor de amortiguación (normalmente 0.85)&lt;/li>
&lt;li>$B(u)$ : Conjunto de páginas que enlazan a la página $u$&lt;/li>
&lt;li>$L(v)$ : Número de enlaces salientes de la página $v$&lt;/li>
&lt;/ul>
&lt;p>Lo importante aquí es, &lt;strong>además de los esfuerzos para mejorar el ranking de búsqueda $R_i$, cómo maximizar el porcentaje de clics $CTR(R_i)$&lt;/strong>. Al optimizar el título y el fragmento (description) que se muestran en los resultados de búsqueda (SERPs), y la imagen destacada (OGP) cuando se comparte en redes sociales, es posible aumentar intencionalmente el $CTR(R_i)$. La configuración de SEO del frontmatter está directamente relacionada con la maximización de este $CTR$.&lt;/p>
&lt;hr>
&lt;h2 id="2-proceso-de-construcción-de-hugo-y-el-papel-del-frontmatter">2. Proceso de construcción de Hugo y el papel del Frontmatter
&lt;/h2>&lt;p>Hugo lee el frontmatter (YAML/TOML/JSON) en los archivos markdown y lo pasa al motor de plantillas como variables de página. Primero entendamos este flujo de información de forma visual.&lt;/p>
&lt;pre class="mermaid">
flowchart TD
A[&amp;#34;Archivo Markdown&amp;#34;] --&amp;gt; B[&amp;#34;Análisis del Frontmatter&amp;#34;]
A --&amp;gt; C[&amp;#34;Análisis del Contenido&amp;#34;]
B --&amp;gt; D[&amp;#34;Variables de Página de Hugo (.Title, .Params)&amp;#34;]
C --&amp;gt; D
E[&amp;#34;layouts/partials/head.html&amp;#34;] --&amp;gt; F[&amp;#34;Motor de Plantillas de Go&amp;#34;]
D --&amp;gt; F
F --&amp;gt; G[&amp;#34;Etiqueta &amp;lt;head&amp;gt; HTML Final&amp;#34;]
G --&amp;gt; H[&amp;#34;Googlebot / Rastreadores&amp;#34;]
G --&amp;gt; I[&amp;#34;Scrapers de Redes Sociales (OGP)&amp;#34;]
&lt;/pre>
&lt;p>De esta manera, los valores configurados en el frontmatter se pasan a &lt;code>head.html&lt;/code> como variables como &lt;code>.Title&lt;/code> o &lt;code>.Params.description&lt;/code>, y se emiten como metadatos HTML finales. Por lo tanto, el éxito del SEO consta de dos pasos: &amp;ldquo;definir la información adecuada en el frontmatter&amp;rdquo; y &amp;ldquo;convertirla correctamente a HTML en la plantilla&amp;rdquo;.&lt;/p>
&lt;hr>
&lt;h2 id="3-configuración-básica-de-metadatos-title-description-canonical-url">3. Configuración básica de metadatos: Title, Description, Canonical URL
&lt;/h2>&lt;p>Las etiquetas más básicas para que los motores de búsqueda entiendan el contenido de la página son &lt;code>&amp;lt;title&amp;gt;&lt;/code> y &lt;code>&amp;lt;meta name=&amp;quot;description&amp;quot;&amp;gt;&lt;/code>. Además, &lt;code>&amp;lt;link rel=&amp;quot;canonical&amp;quot;&amp;gt;&lt;/code> es esencial para evitar penalizaciones por contenido duplicado.&lt;/p>
&lt;h3 id="31-ejemplo-de-configuración-del-frontmatter">3.1. Ejemplo de configuración del frontmatter
&lt;/h3>&lt;p>En el frontmatter del artículo, preparamos campos especializados para SEO.&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: &amp;#39;Estrategias de SEO para blogs de Hugo&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Configuración del Frontmatter para aumentar drásticamente el tráfico&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">seo_title: &amp;#39;Guía Completa de SEO en Hugo: Aumenta tu tráfico con el Frontmatter&amp;#39; # Opcional&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Para motores de búsqueda&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="s1">&amp;#39;Técnicas avanzadas de SEO utilizando el frontmatter de Hugo. Explicamos detalladamente cómo configurar OGP, JSON-LD y metadatos.&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">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 canónica explícita&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-implementación-de-layoutspartialsheadhtml">3.2. Implementación de &lt;code>layouts/partials/head.html&lt;/code>
&lt;/h3>&lt;p>Creamos una plantilla HTML para emitir estas variables correctamente.&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;!-- Optimización del título --&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;!-- Optimización de la descripción --&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 Canónica (Normalización) --&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;!-- Control de robots (como la configuración noindex) --&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>Al usar &lt;code>.Summary&lt;/code> de Hugo como respaldo (fallback), se puede extraer automáticamente la oración inicial del artículo incluso si &lt;code>description&lt;/code> no está configurado.&lt;/p>
&lt;hr>
&lt;h2 id="4-ogp-y-twitter-cards-maximizando-el-ctr-en-redes-sociales">4. OGP y Twitter Cards: Maximizando el CTR en redes sociales
&lt;/h2>&lt;p>Para que tu artículo se muestre en un formato de tarjeta atractivo cuando se comparta en redes sociales como Twitter (X) o Facebook, la configuración del protocolo Open Graph (OGP) y Twitter Cards es esencial. Esto también se genera dinámicamente desde el frontmatter.&lt;/p>
&lt;h3 id="41-el-problema-de-las-plantillas-integradas">4.1. El problema de las plantillas integradas
&lt;/h3>&lt;p>Hugo tiene una plantilla incorporada útil llamada &lt;code>{{ template &amp;quot;_internal/opengraph.html&amp;quot; . }}&lt;/code>, pero carece de personalización y en algunos casos no se adapta al entorno japonés o requisitos específicos. Por lo tanto, se recomienda encarecidamente implementar etiquetas OGP propias dentro de &lt;code>head.html&lt;/code>.&lt;/p>
&lt;h3 id="42-especificando-imágenes-en-el-frontmatter">4.2. Especificando imágenes en el 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"># Para especificar múltiples imágenes o rutas absolutas&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-código-de-implementación-personalizada-para-ogp-y-twitter-cards">4.3. Código de implementación personalizada para OGP y 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;!-- Resolución de la imagen 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>Al pasar por la función &lt;code>absURL&lt;/code>, las URL de las imágenes especificadas como rutas relativas se convierten en rutas absolutas. Dado que las rutas absolutas son obligatorias en OGP, este proceso es extremadamente importante.&lt;/p>
&lt;hr>
&lt;h2 id="5-implementación-de-datos-estructurados-json-ld">5. Implementación de datos estructurados (JSON-LD)
&lt;/h2>&lt;p>En el SEO actual, &lt;strong>JSON-LD (JavaScript Object Notation for Linked Data)&lt;/strong> se ha convertido en la tecnología principal para transmitir con precisión la estructura semántica de una página a los motores de búsqueda. Al configurar esto, es más probable que se muestren fragmentos enriquecidos (rich snippets como valoraciones con estrellas, nombre del autor, fecha de publicación, etc.) en los resultados de búsqueda.&lt;/p>
&lt;h3 id="51-estructura-de-json-ld">5.1. Estructura de JSON-LD
&lt;/h3>&lt;p>Para artículos de blog, se implementan principalmente dos esquemas: el esquema &lt;code>Article&lt;/code> (Artículo) y el esquema &lt;code>BreadcrumbList&lt;/code> (Ruta de exploración o Migas de pan).&lt;/p>
&lt;pre class="mermaid">
flowchart TD
A[&amp;#34;Definiciones de Schema.org&amp;#34;] --&amp;gt; B[&amp;#34;Esquema Article&amp;#34;]
A --&amp;gt; C[&amp;#34;Esquema 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;ListItem 1&amp;#34;]
C --&amp;gt; J[&amp;#34;ListItem 2&amp;#34;]
I --&amp;gt; K[&amp;#34;position: 1&amp;#34;]
I --&amp;gt; L[&amp;#34;name: Home&amp;#34;]
J --&amp;gt; M[&amp;#34;position: 2&amp;#34;]
J --&amp;gt; N[&amp;#34;name: Categoría / Blog&amp;#34;]
&lt;/pre>
&lt;h3 id="52-generación-de-json-ld-en-plantillas-de-hugo">5.2. Generación de JSON-LD en plantillas de Hugo
&lt;/h3>&lt;p>Utilizamos variables del frontmatter como &lt;code>.Date&lt;/code> y &lt;code>.Lastmod&lt;/code> para generar JSON-LD dinámicamente. Lo escribimos en &lt;code>head.html&lt;/code> usando la etiqueta &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;!-- Esquema 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>El punto clave al expandir cadenas dentro de JSON-LD es usar &lt;code>htmlEscape&lt;/code> (o &lt;code>jsonify&lt;/code>) para evitar que se rompan las comillas dobles. Esto previene errores de sintaxis JSON sin importar qué símbolos se usen en el frontmatter.&lt;/p>
&lt;hr>
&lt;h2 id="6-técnicas-avanzadas-de-uso-del-frontmatter">6. Técnicas avanzadas de uso del Frontmatter
&lt;/h2>&lt;p>Además de los metadatos básicos de SEO, el frontmatter de Hugo cuenta con características para lograr estrategias de SEO aún más avanzadas.&lt;/p>
&lt;h3 id="61-redireccionamiento-mediante-alias-aliases">6.1. Redireccionamiento mediante Alias (Aliases)
&lt;/h3>&lt;p>Si migras a Hugo desde un servicio de blog anterior, o si cambias la estructura de los enlaces permanentes (permalinks), necesitas redirigir el tráfico de las URL antiguas a las nuevas. Con el campo &lt;code>aliases&lt;/code> de Hugo, puedes generar automáticamente páginas de actualización HTTP-Equiv (meta redirecciones) para URL antiguas.&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="s1">&amp;#39;Nuevo título del artículo&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">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-fecha-de-caducidad-y-programación-de-artículos">6.2. Fecha de caducidad y programación de artículos
&lt;/h3>&lt;p>Para artículos de campañas por tiempo limitado o información que pierde valor al envejecer, puedes configurar la &lt;code>expiryDate&lt;/code> para excluirlos de los resultados de construcción después de una fecha y hora específicas, evitando que se muestren en el sitio (devolviendo un error 404). Esto evita que el contenido antiguo y de baja calidad permanezca en el índice y reduzca la calificación general del sitio.&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="s1">&amp;#39;Técnicas de SEO exclusivas para 2026&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">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-rendimiento-del-sitio-y-core-web-vitals">7. Rendimiento del sitio y Core Web Vitals
&lt;/h2>&lt;p>En SEO, &lt;strong>la velocidad de carga de la página&lt;/strong> es tan importante como la optimización de las etiquetas. Google ha incorporado los Core Web Vitals (LCP, FID/INP, CLS) como factores de clasificación.&lt;/p>
&lt;p>Hugo, al ser un sitio estático, tiene un excelente TTFB (Time to First Byte) por defecto, pero la optimización de imágenes es esencial en blogs que hacen un uso intensivo de ellas. Al combinar las potentes funciones de procesamiento de imágenes de Hugo (Image Processing) con el frontmatter, puedes automatizar el redimensionamiento y la conversión a formatos de próxima generación (como WebP) durante la construcción (build).&lt;/p>
&lt;p>Por ejemplo, puedes crear un shortcode que genere automáticamente imágenes WebP en el lado de la plantilla a partir de la ruta de la imagen especificada en el frontmatter. Esto puede mejorar drásticamente el rendimiento SEO.&lt;/p>
&lt;hr>
&lt;h2 id="8-resumen">8. Resumen
&lt;/h2>&lt;p>En la gestión de blogs con Hugo, el frontmatter no es solo &amp;ldquo;una lista de valores de configuración&amp;rdquo;, sino un &amp;ldquo;panel de control&amp;rdquo; para comunicarse con los motores de búsqueda y las redes sociales.&lt;/p>
&lt;p>Al implementar completamente los siguientes puntos explicados en este artículo, la base SEO de tu blog será sólida:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Generación dinámica de metadatos básicos&lt;/strong>: Salida confiable de Title, Description y Canonical.&lt;/li>
&lt;li>&lt;strong>Optimización para compartir en redes sociales&lt;/strong>: Mejora del CTR mediante la implementación personalizada de OGP y Twitter Cards.&lt;/li>
&lt;li>&lt;strong>Soporte completo de datos estructurados&lt;/strong>: Soporte para resultados enriquecidos (Rich Results) con JSON-LD (Article, Breadcrumb).&lt;/li>
&lt;li>&lt;strong>Gestión avanzada de tráfico&lt;/strong>: Control de robots con metaetiquetas y redirecciones usando Aliases.&lt;/li>
&lt;/ol>
&lt;p>Aunque los algoritmos de los motores de búsqueda evolucionan diariamente, el principio fundamental del SEO de proporcionar señales para que los motores de búsqueda &amp;ldquo;comprendan correctamente el contenido de la página&amp;rdquo; permanece inalterable. Al dominar el flexible motor de plantillas y el frontmatter de Hugo, continúa enviando esas señales con la más alta calidad y aumenta drásticamente el tráfico de tu blog.&lt;/p></description></item><item><title>Qué deben hacer los ingenieros para aumentar el tráfico mensual en su blog técnico</title><link>http://kenji.blog/es/p/tech-blog-growth-strategies-for-engineers/</link><pubDate>Sat, 12 Sep 2026 12:00:00 +0900</pubDate><guid>http://kenji.blog/es/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 Qué deben hacer los ingenieros para aumentar el tráfico mensual en su blog técnico" />&lt;h2 id="introducción-growth-hacking-para-blogs-técnicos-que-solo-los-ingenieros-pueden-hacer">Introducción: Growth hacking para blogs técnicos que solo los ingenieros pueden hacer
&lt;/h2>&lt;p>Muchos ingenieros de software abren blogs técnicos, pero no hay muchos casos en los que logren atraer una cierta cantidad de tráfico y mantenerlo/expandirlo a largo plazo. Escribir artículos técnicos de alta calidad es un requisito previo, pero la era de &amp;ldquo;si escribes buenos artículos, serán leídos naturalmente&amp;rdquo; ya ha terminado. Los algoritmos de los motores de búsqueda actuales se han vuelto complejos y, además, el flujo de información en las redes sociales es más rápido que nunca.&lt;/p>
&lt;p>Sin embargo, los ingenieros tienen fortalezas que otras profesiones no tienen. Estas radican en su capacidad para &amp;ldquo;comprender la arquitectura de los sistemas, combinar herramientas para automatizar y analizar datos mediante programación&amp;rdquo;. En este artículo, no nos limitaremos a simples técnicas de escritura, sino que trataremos el blog técnico como un &amp;ldquo;producto&amp;rdquo;, y explicaremos de manera extremadamente detallada y práctica las estrategias para aumentar drásticamente el tráfico mensual utilizando el poder de la ingeniería.&lt;/p>
&lt;hr>
&lt;h2 id="1-arquitectura-seo-de-blogs-técnicos-para-ingenieros">1. Arquitectura SEO de blogs técnicos para ingenieros
&lt;/h2>&lt;p>El sistema fundamental del blog (como los generadores de sitios estáticos) y la estructura HTML son los elementos más importantes para que los motores de búsqueda interpreten correctamente el contenido.&lt;/p>
&lt;h3 id="11-optimización-de-los-core-web-vitals">1.1 Optimización de los Core Web Vitals
&lt;/h3>&lt;p>Google ha adoptado la experiencia de la página como factor de clasificación, y en especial los &lt;strong>Core Web Vitals (LCP, FID/INP, CLS)&lt;/strong> no pueden ignorarse, incluso en un blog técnico.
En los blogs técnicos, se utilizan en gran medida bloques masivos de código fuente, fórmulas matemáticas (MathJax / KaTeX) y diagramas. Estos factores retrasan la renderización de la página.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>LCP (Largest Contentful Paint)&lt;/strong>: Velocidad de carga del contenido principal de la primera vista. Use WebP o AVIF para la imagen destacada y precárguela asignando el atributo &lt;code>fetchpriority=&amp;quot;high&amp;quot;&lt;/code>. Además, cargue de forma asíncrona CSS o JS masivos para resaltar la sintaxis, o diséñelos para que se carguen solo en las páginas necesarias.&lt;/li>
&lt;li>&lt;strong>CLS (Cumulative Layout Shift)&lt;/strong>: Desplazamiento del diseño durante la carga del artículo. Al asegurar con anticipación el área de visualización de fórmulas matemáticas o imágenes con atributos CSS como &lt;code>aspect-ratio&lt;/code>, evitará saltos bruscos cuando el DOM se inserte más tarde.&lt;/li>
&lt;li>&lt;strong>INP (Interaction to Next Paint)&lt;/strong>: Capacidad de respuesta a la interacción del usuario. Es esencial no ejecutar JavaScript pesado (por ejemplo, búsquedas dinámicas de texto completo en el lado del cliente o la ejecución de analizadores masivos de Markdown) en el hilo principal; trasládelo a un Web Worker o genérelo como HTML estático (SSG) durante la compilación.&lt;/li>
&lt;/ul>
&lt;h3 id="12-implementación-de-datos-estructurados-json-ld">1.2 Implementación de datos estructurados (JSON-LD)
&lt;/h3>&lt;p>Para informar explícitamente a los motores de búsqueda que la página es un &amp;ldquo;artículo&amp;rdquo; y &amp;ldquo;quién&amp;rdquo; es el autor, implemente datos estructurados en formato JSON-LD. Al usar esquemas como &lt;code>TechArticle&lt;/code> o &lt;code>SoftwareSourceCode&lt;/code>, es más probable que aparezca en los resultados enriquecidos de Google, lo que mejorará su CTR (Click-Through Rate).&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;Qué deben hacer los ingenieros para aumentar el tráfico mensual en su blog técnico&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-semántico-y-optimización-de-la-estructura-del-documento">1.3 HTML semántico y optimización de la estructura del documento
&lt;/h3>&lt;p>El anidamiento adecuado de los encabezados (&lt;code>h1&lt;/code> a &lt;code>h6&lt;/code>) es fundamental, pero en un blog técnico se requiere el uso preciso de etiquetas semánticas de HTML5 como &lt;code>article&lt;/code>, &lt;code>section&lt;/code>, &lt;code>aside&lt;/code> y &lt;code>nav&lt;/code>. Además, al utilizar correctamente &lt;code>&amp;lt;code&amp;gt;&lt;/code> y &lt;code>&amp;lt;pre&amp;gt;&lt;/code> para el código fuente, &lt;code>&amp;lt;kbd&amp;gt;&lt;/code> para la entrada del teclado, y &lt;code>&amp;lt;var&amp;gt;&lt;/code> para variables, podrá proporcionar un HTML legible por máquinas. Esta es también una medida muy eficaz para la indexación de contenido por IA (recopilación de datos de entrenamiento LLM o sistemas RAG).&lt;/p>
&lt;hr>
&lt;h2 id="2-la-psicología-de-la-intención-de-búsqueda-search-intent-y-estrategias-de-palabras-clave">2. La psicología de la intención de búsqueda (Search Intent) y estrategias de palabras clave
&lt;/h2>&lt;p>Para maximizar el flujo desde los motores de búsqueda (tráfico orgánico), es necesario interpretar con precisión la intención de búsqueda, es decir, &amp;ldquo;por qué el usuario buscó esa palabra clave&amp;rdquo;. La intención de búsqueda en temas técnicos se puede clasificar principalmente en dos categorías.&lt;/p>
&lt;h3 id="21-tipo-resolución-de-errores-y-tipo-aprendizaje-sistemático--revisión">2.1 &amp;ldquo;Tipo resolución de errores&amp;rdquo; y &amp;ldquo;Tipo aprendizaje sistemático / revisión&amp;rdquo;
&lt;/h3>&lt;ol>
&lt;li>
&lt;p>&lt;strong>Tipo resolución de errores (Troubleshooting Intent)&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>Ejemplos de palabras clave de búsqueda: &lt;code>Solución Docker &amp;quot;no space left on device&amp;quot;&lt;/code>, &lt;code>Causa Python IndexError list index out of range&lt;/code>&lt;/li>
&lt;li>Psicología: Están bloqueados por un error durante el desarrollo y buscan comandos o fragmentos de código que actúen como un remedio inmediato.&lt;/li>
&lt;li>Estrategia: Presente la &amp;ldquo;conclusión (códigos o comandos para resolverlo)&amp;rdquo; al comienzo del artículo (primera vista). El trasfondo y la explicación detallada de los mecanismos se colocarán detrás de esto, satisfaciendo primero el deseo del usuario de &amp;ldquo;arreglarlo ahora mismo&amp;rdquo;. Esto puede reducir la tasa de rebote (bounce rate).&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Tipo aprendizaje sistemático / revisión (Learning &amp;amp; Review Intent)&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>Ejemplos de palabras clave de búsqueda: &lt;code>Comparación React vs Vue 2026&lt;/code>, &lt;code>Introducción al procesamiento asíncrono en Rust&lt;/code>, &lt;code>Diseño de arquitectura de red GCP&lt;/code>&lt;/li>
&lt;li>Psicología: Quieren seleccionar un nuevo conjunto de tecnologías o profundizar su comprensión desde lo básico, y están preparados para tomarse el tiempo de leer.&lt;/li>
&lt;li>Estrategia: Enriquezca la tabla de contenidos (TOC) y utilice abundantes diagramas de arquitectura o ilustraciones (Mermaid, etc.). Al comparar objetivamente las ventajas y desventajas e incluir casos de uso sobre cómo aplicarlo en el trabajo real, puede aumentar el tiempo de permanencia.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;h3 id="22-modelo-de-decaimiento-exponencial-del-tráfico-y-estrategia-de-cola-larga-long-tail">2.2 Modelo de decaimiento exponencial del tráfico y estrategia de cola larga (Long Tail)
&lt;/h3>&lt;p>El tráfico de los artículos técnicos tiende a formar picos (aumentos rápidos) al hacerse virales en redes sociales inmediatamente después de su publicación, y luego disminuir exponencialmente. Este tráfico $V(t)$ se puede aproximar con el siguiente modelo matemático.&lt;/p>
$$ V(t) = V_0 e^{-\lambda t} + C $$&lt;p>Donde:&lt;/p>
&lt;ul>
&lt;li>$V(t)$: Volumen de tráfico en el tiempo $t$&lt;/li>
&lt;li>$V_0$: Pico de tráfico inicial debido a la viralidad en redes sociales, etc., justo después de la publicación&lt;/li>
&lt;li>$\lambda$: Constante de decaimiento debido a la obsolescencia del contenido u olvido en las redes sociales (dependiente de la velocidad de los cambios en las tendencias tecnológicas)&lt;/li>
&lt;li>$C$: Flujo constante de búsqueda orgánica desde los motores de búsqueda (tráfico base)&lt;/li>
&lt;/ul>
&lt;p>La clave para aumentar el acceso a largo plazo es, más que apuntar a una viralidad temporal ($V_0$), &lt;strong>cómo maximizar el término constante $C$ (flujo sostenido desde los motores de búsqueda)&lt;/strong>. Al cubrir masivamente &amp;ldquo;palabras clave de cola larga&amp;rdquo; (long tail keywords) que no tienen competidores aunque su volumen de búsqueda sea bajo, como errores específicos de nicho o cómo conectar herramientas específicas entre sí, desarrollaremos la suma total de $C$ hasta que sea enorme.&lt;/p>
&lt;hr>
&lt;h2 id="3-análisis-de-contenido-basado-en-datos-utilizando-la-api-de-google-search-console">3. Análisis de contenido basado en datos utilizando la API de Google Search Console
&lt;/h2>&lt;p>Para construir una base de tráfico estable $C$, es necesario utilizar datos de Google Search Console (GSC) y analizar objetivamente &amp;ldquo;cómo está siendo evaluado por Google&amp;rdquo;. Sin embargo, hay límites al operar GSC haciendo clics en su interfaz web. Como ingenieros, automaticemos el análisis usando la API de GSC y Python.&lt;/p>
&lt;h3 id="31-enfoque-de-automatización-con-la-api-de-gsc-y-python">3.1 Enfoque de automatización con la API de GSC y Python
&lt;/h3>&lt;p>Crearemos un script que detecte automáticamente &amp;ldquo;artículos desperdiciados&amp;rdquo; donde el ranking de búsqueda de un artículo específico cae con el tiempo (Decaying Content), o donde las impresiones son altas pero el CTR (tasa de clics) es inusualmente bajo.
Para esto usaremos &lt;code>google-api-python-client&lt;/code> y &lt;code>pandas&lt;/code>.&lt;/p>
&lt;h3 id="32-código-de-implementación-en-python-extracción-automática-de-contenido-con-caída-de-ctr">3.2 Código de implementación en Python: Extracción automática de contenido con caída de CTR
&lt;/h3>&lt;p>El siguiente es un ejemplo de script que obtiene datos de rendimiento de búsqueda de los últimos 30 días a través de la API, y extrae &amp;ldquo;palabras clave y URLs de artículos con gran margen de mejora en el título o descripción&amp;rdquo; que tienen 1000 o más impresiones y un CTR menor al 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. Autenticación y construcción del servicio 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. Cálculo del período de la solicitud (últimos 30 días)&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. Ejecución de la solicitud a la 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. Procesamiento y filtrado de datos usando 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"># Condiciones de filtrado: 1000 o más impresiones y CTR menor al 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"># Ordenar por posición ascendente (priorizar aquellos con alta posición pero no cliqueados)&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;【Lista de recomendaciones para mejorar títulos/meta descripciones】&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"># Salida a CSV si es necesario, etc.&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;No se encontraron datos.&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>Al ejecutar este script periódicamente a través de un cron o un job de GitHub Actions, siempre podrá decidir basado en datos &amp;ldquo;qué título de artículo debe reescribirse&amp;rdquo;. En lugar de depender de la intuición, la mejora continua basada en datos (Mejora Continua de Contenido en lugar de CI/CD) es importante.&lt;/p>
&lt;hr>
&lt;h2 id="4-gestión-del-ciclo-de-vida-de-los-artículos-y-estrategias-de-reescritura">4. Gestión del ciclo de vida de los artículos y estrategias de reescritura
&lt;/h2>&lt;p>Un artículo técnico no termina cuando se publica. A medida que la tecnología evoluciona (actualizaciones de versiones de frameworks, obsolescencia de API, etc.), el contenido se vuelve anticuado rápidamente. Seguir proporcionando información desactualizada no solo daña la credibilidad de su blog, sino que también resulta en una calificación negativa desde el punto de vista del SEO.&lt;/p>
&lt;h3 id="41-gestión-del-ciclo-de-vida-del-contenido-diagrama-de-gantt">4.1 Gestión del ciclo de vida del contenido (Diagrama de Gantt)
&lt;/h3>&lt;p>A continuación se muestra el ciclo de vida de operación de contenido ideal utilizando un diagrama de Gantt de Mermaid.&lt;/p>
&lt;pre class="mermaid">
gantt
title Gestión del ciclo de vida del contenido basada en datos
dateFormat YYYY-MM-DD
axisFormat %m/%d
section &amp;#34;Fase 1: Planificación y escritura&amp;#34;
&amp;#34;Análisis de palabras clave y tendencias&amp;#34; :a1, 2026-09-01, 3d
&amp;#34;Borrador y verificación de código&amp;#34; :a2, after a1, 5d
&amp;#34;Revisión y corrección&amp;#34; :a3, after a2, 2d
section &amp;#34;Fase 2: Publicación y promoción&amp;#34;
&amp;#34;Despliegue a través del pipeline CI/CD&amp;#34; :p1, 2026-09-11, 1d
&amp;#34;Distribución automática en RR.SS. (X, LinkedIn, RSS)&amp;#34; :p2, 2026-09-11, 1d
&amp;#34;Efecto dominó en marcadores sociales, etc.&amp;#34; :p3, after p2, 3d
section &amp;#34;Fase 3: Observación y análisis&amp;#34;
&amp;#34;Período de acumulación de datos de GSC&amp;#34; :m1, 2026-09-14, 28d
&amp;#34;Evaluación de rendimiento con API de Python&amp;#34;:m2, after m1, 2d
section &amp;#34;Fase 4: Mejora (Reescritura)&amp;#34;
&amp;#34;Corrección de títulos de artículos con bajo CTR&amp;#34; :r1, after m2, 3d
&amp;#34;Actualización de código a la última versión&amp;#34;:r2, after r1, 4d
&lt;/pre>
&lt;p>Este tipo de enfoque, tratando la creación de artículos como un proyecto de desarrollo de software e incorporando la fase de operación y mantenimiento (reescritura) posterior al lanzamiento en su planificación, es el secreto para mantener y mejorar el tráfico.&lt;/p>
&lt;h3 id="42-modelo-matemático-del-retorno-de-inversión-roi-de-la-creación-de-contenido">4.2 Modelo matemático del retorno de inversión (ROI) de la creación de contenido
&lt;/h3>&lt;p>Dado que los ingenieros dedican su valioso tiempo a escribir artículos, deben ser conscientes de su retorno de inversión (ROI).
El ROI en un blog se puede formular de la siguiente manera.&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$: Vida útil del artículo (tiempo hasta la obsolescencia)&lt;/li>
&lt;li>$Rev_{ad}(t)$: Ingresos directos de publicidad, afiliaciones o patrocinios&lt;/li>
&lt;li>$Val_{brand}(t)$: Valor monetario equivalente al impacto positivo en su carrera por demostrar habilidades técnicas (aumento en ofertas de trabajo, solicitudes de conferencias, etc.)&lt;/li>
&lt;li>$Val_{skill}(t)$: Valor del incremento de sus propias habilidades a través del aprendizaje e investigación necesarios para escribir el artículo&lt;/li>
&lt;li>$Cost_{time}$: Tiempo dedicado a escribir el artículo, crear diagramas y verificar código (equivalente a su tarifa por hora)&lt;/li>
&lt;/ul>
&lt;p>Lo grandioso de los blogs técnicos es que, incluso si $Rev_{ad}$ es pequeño, $Val_{brand}$ y $Val_{skill}$ tienden a ser extremadamente grandes. En particular, las explicaciones técnicas de alta calidad se convierten directamente en su portafolio y tienen un inmenso poder en la búsqueda de empleo o trabajos secundarios.&lt;/p>
&lt;hr>
&lt;h2 id="5-distribución-mediante-github-actions-y-la-integración-de-herramientas-de-automatización-externas">5. Distribución mediante GitHub Actions y la integración de herramientas de automatización externas
&lt;/h2>&lt;p>Una vez creado el contenido, el desafío es cómo entregarlo eficientemente a su público objetivo (distribución). Publicar enlaces manualmente en cada red social cada vez es ineficiente y no es digno de un ingeniero.&lt;/p>
&lt;h3 id="51-arquitectura-de-automatización-de-intercambio-en-redes-sociales">5.1 Arquitectura de automatización de intercambio en redes sociales
&lt;/h3>&lt;p>Construiremos una arquitectura totalmente automatizada desde el momento en que se fusiona el archivo Markdown a la rama main del repositorio de GitHub, abarcando la compilación, despliegue y notificaciones en múltiples plataformas.&lt;/p>
&lt;pre class="mermaid">
flowchart TD
A[&amp;#34;Desarrollador (Git Push)&amp;#34;] --&amp;gt; B[&amp;#34;Repositorio de GitHub&amp;#34;]
B --&amp;gt;|Webhook| C[&amp;#34;GitHub Actions (CI/CD)&amp;#34;]
C --&amp;gt;|Build| D[&amp;#34;Generador de Sitios Estáticos (Hugo/Gatsby)&amp;#34;]
D --&amp;gt;|Deploy| E[&amp;#34;Alojamiento (Vercel / Cloudflare Pages)&amp;#34;]
D --&amp;gt;|Generate| F[&amp;#34;Feed RSS (index.xml)&amp;#34;]
F --&amp;gt;|Polled by| G[&amp;#34;Zapier / IFTTT / Make&amp;#34;]
G --&amp;gt;|API Call| H[&amp;#34;Publicación automática en X (Twitter)&amp;#34;]
G --&amp;gt;|API Call| I[&amp;#34;Publicación de artículo en LinkedIn&amp;#34;]
G --&amp;gt;|API Call| J[&amp;#34;Webhook de comunidad de Discord / Slack&amp;#34;]
C --&amp;gt;|Actions Script| K[&amp;#34;API Cross-Post de Qiita / Zenn&amp;#34;]
&lt;/pre>
&lt;h3 id="52-puntos-clave-en-la-construcción-de-pipelines-de-automatización">5.2 Puntos clave en la construcción de pipelines de automatización
&lt;/h3>&lt;ol>
&lt;li>
&lt;p>&lt;strong>Compilación y despliegue usando GitHub Actions&lt;/strong>
Si utiliza un generador de sitios estáticos, automatice la generación de HTML y el despliegue al destino de alojamiento (Vercel, Netlify, Cloudflare Pages, etc.) utilizando GitHub Actions. En este punto, también es eficaz integrar procesos de optimización de imágenes (como la conversión automática a WebP) en su pipeline de compilación como medida para los Core Web Vitals mencionados anteriormente.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Integración en redes sociales disparada por RSS utilizando Zapier/IFTTT&lt;/strong>
El generador de sitios genera el último feed RSS (XML) durante la compilación. Haga que una plataforma iPaaS como Zapier o Make (antes Integromat) lea esto para crear un flujo de trabajo: &amp;ldquo;Cuando se agregue un nuevo elemento al RSS, publicar el título y la URL en X (Twitter) y LinkedIn&amp;rdquo;. Esto permite notificaciones automáticas a sus seguidores en el momento en que publica un artículo.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Publicación cruzada (Cross-post) en plataformas técnicas como Qiita/Zenn (uso de etiquetas Canonical)&lt;/strong>
Mientras el poder de dominio de su propio blog corporativo o personal sea débil, es una buena estrategia aprovechar el poder de atracción de clientes de plataformas técnicas como Qiita o Zenn. Sin embargo, el simple copiar y pegar conlleva el riesgo de recibir una penalización de SEO por contenido duplicado.
Este problema se puede resolver estableciendo la &lt;strong>etiqueta Canonical&lt;/strong> en los metadatos de los artículos en Qiita o Zenn, apuntando a la URL del artículo original en su propio blog. Al crear un script que llame a las APIs de las distintas plataformas desde GitHub Actions para generar artículos automáticamente desde Markdown, podrá automatizar completamente la distribución multicanal.&lt;/p>
&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="conclusión-girar-el-ciclo-de-mejora-continua">Conclusión: Girar el ciclo de mejora continua
&lt;/h2>&lt;p>Para aumentar drásticamente el tráfico mensual de un blog técnico, además del acto de &amp;ldquo;escribir&amp;rdquo;, el enfoque de ingeniería presentado esta vez es indispensable.&lt;/p>
&lt;ol>
&lt;li>Construcción de una arquitectura de sitio y HTML robusta teniendo en cuenta el SEO&lt;/li>
&lt;li>Diseño de artículos que comprenda la intención de búsqueda del usuario (resolución de errores vs aprendizaje sistemático)&lt;/li>
&lt;li>Análisis de datos aprovechando la API de Google Search Console y Python&lt;/li>
&lt;li>Gestión del ciclo de vida del contenido y reescritura considerando el ROI&lt;/li>
&lt;li>Automatización total de la distribución mediante integración con CI/CD y Zapier&lt;/li>
&lt;/ol>
&lt;p>Si logra integrar todo esto como un sistema, su blog técnico se convertirá en el activo (asset) más poderoso para impulsar fuertemente su propia carrera. A los ingenieros que sufren por el estancamiento del tráfico, les instamos a que comiencen hoy el &amp;ldquo;growth hacking para su blog&amp;rdquo;. Las habilidades de programación y diseño de arquitectura que han cultivado en sus tareas de desarrollo serán, sin duda, su mejor arma en la gestión de su blog.&lt;/p></description></item></channel></rss>