Exportando tu contenido desde Substack a Obsidian
Implementando una herramienta cli con Python
La línea de comandos es, por lejos, la interfaz de usuario más flexible y útil para un programador. Todo esto gracias al poder de composición que nos proporcionan herramientas como pipes, o la ejecución de scripts que podemos componer para automatizar nuestro trabajo.
Hace poco escribí un pequeño script para poder importar mis artículos en Substack a Obsidian.
Substack es esta plataforma de publicación de newsletters en la que lees mis artículos. Obsidian es el sistema que uso para mantener notas. Quizás algún día escriba algo sobre cómo tomar notas y usar lo que algunos llaman tu “segundo cerebro” (second-brain) y que yo llamo procrastinación avanzada 🤣.
La razón para hacer esto es que me ayuda a encontrar temas, evitar repetirme, listar las referencias que he hecho en mis artículos, etc.
La exportación desde Substack es muy sencilla, ellos te generan un archivo CSV y en una carpeta dejan el contenido con un archivo HTML por cada post. El problema es que Obsidian necesita el contenido en formato Markdown.
La versión inicial la escribí en Python. Para transformar de HTML a Mardown usé el paquete markdownify
que está basado en beautiful soup,
que se usa bastante para hacer web scraping. La transformación es bastante decente, y puedes extenderla para efectuar ciertos ajustes con algunos elementos. En mi caso cuando procesa el elemento img
aprovecho de descargar la imagen (Substack almacena todas las imágenes en sus CDN, así que es necesario descargarlas para poder preservarlas en tu propio almacenamiento).
Por último, y lo que encuentro más útil, usé click para manejar las opciones y argumentos del script.
El siguiente código, que es parte de mi script, define los parámetros para mi cli:
@click.command()
@click.argument("csv_file", default='posts.csv', type=click.Path(exists=True))
@click.argument("input_folder", default='posts', type=click.Path(exists=True, dir_okay=True))
@click.argument("output_folder", default='md_posts', type=click.Path(exists=False))
@click.option("-f", "--from-date", default='2022-12-18', type=str)
@click.option("-p", "--base-prefix", default='https://newsletter.lnds.net/p/', type=str)
def import_from_substack(csv_file, input_folder, output_folder, from_date, base_prefix):
...
if __name__ == '__main__':
import_from_substack()
Usando anotaciones en la función principal de tu script configuras tu cli.
¿Qué es una CLI?
Viene de Command Line Interface, y define la forma en que el usuario interactúa con tu script o programa que corre en la consola, o línea de comandos.
Por ejemplo, en mi script tengo una opción que permite definir a partir de que fecha quiero importar los artículos, que se usa así:
python substack_import --from-date 2024-11-01
Bibliotecas como click te permiten gestionar de forma sencilla los parámetros de tu programa, porque a veces realizar la interpretación de los argumentos de tu programa puede llegar a ser algo bastante complicado.
Si te interesa ver el código, o si esta herramienta te resulta útil, la puedes descargar desde este repositorio en GitHub: https://github.com/lnds/import-substacks.
Si conoces a alguien que le pueda interesar esta herramienta, te invito a compartirle este artículo:
Y si te gusta este tipo de contenido, te animo a suscribirte:
He visto varias herramientas usar click, y últimamente otras también usar typer (https://typer.tiangolo.com), que usa type hints en vez de decoradores. No conozco ninguna a fondo, pero supongo que al fin del día las dos soportan casos de uso similares, así que va a ser cosa de gustos cuál escoger.