Kabosu - Creando cosas

Logo de la página. Gato esférico con colores verdoso.

Generador estático del blog: cómo lo he hecho

Publicado: 2024-01-28 (actualizado 2024-10-04)

Etiquetas: Blog, Proyectos, Python


Editado el 2024-10-04 para corregir algunos errores ortográficos.

En este artículo quiero explicar cómo estoy generando el HTML de esta página utilizando Python. Yo escribo los artículos en ficheros de Markdown que luego se convierten en HTML para añadirse al blog. Al principio lo hacía a mano pero la semana pasada me hice un pequeño script de Python que lo hace por mí. Ese mismo script además crea el fichero XML del feed Atom.

Antes de empezar con la explicación, un aviso: si tu objetivo es escribir un blog no pierdas el tiempo programando tu propio generador y dedícate a escribir entradas del blog. Existen multitud de static site generators (SSGs) que puedes utilizar como por ejemplo Hugo.

Mi blog consta de una serie de ficheros .md (Markdown) que guardo en el directorio posts/. En estos momentos tiene estos ficheros:

0001-hello-world.md 
0002-presentacion.md
0003-markdown-a-html.md
0004-review-mythical-man-month.md
0005-feed-para-el-blog.md

He escrito un script de Python que recorre el directorio buscando ficheros .md y para cada uno genera el fichero HTML correspondiente. Para tener claro el orden de los artículos decidí asignarles un número. Tengo pensado escribir 9999 artículos en este blog.

Para la conversión a HTML utilizo el módulo commonmark que se puede instalar con pip. Este conversor no devuelve una página web completa sino solo párrafos así que he definido un plantilla para la cabecera (desde el <html> hasta que empieza el contenido) y el pie de página (desde que termina el texto del articulo hasta el </html>) que se copian delante y detrás del HTML generado por commonmark. Simplemente mirando el código fuente de esta página se ver perfectamente la cabecera, el contenido y el pie.

Nota: Desde que escribí este artículo usaba el módulo commonmark pero ese paquete ya no está mantenido y ahora se recomienda usar markdown-it-py.

import commonmark

def genArticle(content, filePath):
  md = commonmark.commonmark(content)

  fout = open(filePath, 'w')
  print(open('header.txt').read(), file=fout)
  print(md, file=fout)
  print(open('footer.txt').read(), file=fout)

  fout.close()

La función genArticle se llama una vez para cada fichero Markdown en el directorio posts/. El código es muy sencillo:

posts = list(os.listdir('posts'))
posts.sort()

for path in posts:
  filepath = 'posts/' + path
  content = open(filepath).read()
  articlePath = 'www/' + path[:-3] + '.html'
  genArticle(content, articlePath)

El código para generar el feed RSS es algo más complicado porque los feeds Atom requieren varios datos. Para generarlo estoy utilizando el módulo Python llamado feedgen.

Primero hay que crear el feed (yo lo llamo fg) y pasarle los datos básicos del blog:

from feedgen.feed import FeedGenerator

PAGE_TITLE = 'Kabosu - Creando cosas'
URL = 'https://kabosu.neocities.org/'


fg = FeedGenerator()
fg.id(URL)
fg.title(PAGE_TITLE)
fg.link(href=URL, rel='alternate')
fg.logo(URL + 'logo.svg')
fg.link(href=URL + 'feed.atom', rel='self')
fg.language('es')

Luego, para cada artículo hay que añadir una nueva entrada al feed. En el bucle anterior yo he añadido:

for path in posts:
  filepath = 'posts/' + path
  content = open(filepath).read()
  articlePath = 'www/' + path[:-3] + '.html'
  genArticle(content, articlePath)

  fe = fg.add_entry()
  fe.id(articlePath)
  title = getTitle(content)
  fe.title(title)
  fe.link(href=URL + articlePath)
  fe.content(content=content, type='html')

Las entradas tienen campos como

Hay otros que no he puesto para no complicar mucho el código pero seguramente también quieras añadir:

Tras el bucle que genera los HTML de los artículo y guarda la información para el feed simplemente hay que generar el fichero

fg.atom_file('www/feed.atom', pretty=True)

Todos los ficheros los genero en el directorio www/. Cuando termina de ejecutarse el script subo todo al hosting y ya tengo la web actualizada.

El código de este artículo muestra una versión simplificada de cómo genero el blog. He ido añadiendo otras cosas como etiquetas, artículos anterior y siguientes, etc que no aparecen aquí.


Artículo siguiente: Analizando ROMs de Game Boy: el famoso logo
Artículo anterior: Ya tengo feed RSS para el blog