Script Python pour convertir des posts Wordpress en Markdown

J’ai utilisé ce script pour convertir les anciens posts techoverflow.net basés sur Wordpress au format Markdown pour une utilisation avec Hugo. Il utilise les bibliothèques beautifulsoup4 et markdownify pour analyser le contenu HTML et le convertir en Markdown.

Partie 1 : Récupérer les catégories Wordpress

wp_to_md_part1.py
#!/usr/bin/env python3
from tqdm import tqdm
import requests
import json
import base64
import os

URL = "https://myblog.com"
USER = "uli"
PASSWORD = os.environ.get("WORDPRESS_API_PASSWORD")
if PASSWORD is None:
    raise ValueError("WORDPRESS_API_PASSWORD environment variable is not set")

# Calculer l'en-tête d'authentification basic
auth_header = b"Basic " + base64.b64encode(f"{USER}:{PASSWORD}".encode("utf-8"))

def page_numbers():
    """Générateur infini de numéros de page"""
    num = 1
    while True:
        yield num
        num += 1

categories = []
for page in tqdm(page_numbers()):
    # Récupérer les [pagesize=10] catégories suivantes
    categories_page = requests.get(f"{URL}/wp-json/wp/v2/categories", params={"page": page, "per_page": 100, "context": "edit"},
                             headers={"Authorization": auth_header}).json()
    # Vérifier le code d'erreur "dernière page"
    if not len(categories_page):
        break
    # Pas de code d'erreur -> ajouter les catégories
    categories += categories_page

with open("categories.json", "w") as outfile:
    json.dump(categories, outfile)

Partie 2 : Récupérer les posts WordPress

wp_to_md_part2.py
#!/usr/bin/env python3
from tqdm import tqdm
import requests
import json
import base64
import os

URL = "https://techoverflow.net"
USER = "uli"
PASSWORD = os.environ.get("WORDPRESS_API_PASSWORD")
if PASSWORD is None:
    raise ValueError("WORDPRESS_API_PASSWORD environment variable is not set")

# Calculer l'en-tête d'authentification basic
auth_header = b"Basic " + base64.b64encode(f"{USER}:{PASSWORD}".encode("utf-8"))

def page_numbers():
    """Générateur infini de numéros de page"""
    num = 1
    while True:
        yield num
        num += 1

posts = []
for page in tqdm(page_numbers()):
    # Récupérer les [pagesize=10] posts suivants
    posts_page = requests.get(f"{URL}/wp-json/wp/v2/posts", params={"page": page, "per_page": 100, "context": "edit"},
                             headers={"Authorization": auth_header}).json()
    # Vérifier le code d'erreur "dernière page"
    if isinstance(posts_page, dict) and posts_page["code"] == "rest_post_invalid_page_number": # Dernière page trouvée
        break
    # Pas de code d'erreur -> ajouter les posts
    posts += posts_page

with open("posts.json", "w") as outfile:
    json.dump(posts, outfile)

Partie 3 : Convertir les posts sauvegardés en Markdown

wp_to_md_part3.py
#!/usr/bin/env python3
import requests
import json
import re
import os
import os.path
import markdownify
from datetime import datetime

with open("posts.json") as infile:
    posts = json.load(infile)

with open("categories.json") as infile:
    categories = json.load(infile)

category_map = {category["id"]: category["name"] for category in categories}

def code_language_callback(elem):
    lang = elem.attrs.get("data-enlighter-language", "")
    filename = elem.attrs.get("data-filename", None)
    return lang

def export_post(the_post):
    title = the_post["title"]["raw"]
    escaped_title = title.replace("\\", "\\\\").replace('"', '\\"')

    slug = the_post["slug"]
    slug = re.sub(r"%[a-f0-9]{2}", "", the_post["slug"]) # Supprimer les caractères spéciaux échappés

    date_str = the_post["date"]
    date = datetime.fromisoformat(date_str)

    post_categories = [category_map[cat_id] for cat_id in the_post["categories"]]
    content = the_post["content"]["raw"]
    has_latex = "[latex]" in content

    wp_post_id = the_post["id"]

    author = the_post["author"]
    if author == 1:
        author = "Uli Köhler"
    if author == 2:
        author = "Yann Spöri"
    if author == 6:
        author = "Tobias Gutmann"
    if author == 4:
        author = "Joshua Simon"
    if isinstance(author, int):
        raise ValueError(f"Unknown author ID: {author}")

    # Construire les catégories
    category_header = None
    for category in post_categories:
        if category_header is None:
            category_header = "categories:\n"
        category_header += f"    - {category}\n"

    # Construire l'en-tête
    header = f"""---
title: "{escaped_title}"
date: {date_str}
slug: "{slug}"
author: {author}
katex: {has_latex}

wordpress_import:
    wp_post_id: {wp_post_id}

{category_header}
---\n\n"""
    # Filtrer le contenu
    filtered_content = content.replace("\r\n", "\n")
    filtered_content = markdownify.markdownify(filtered_content, code_language_callback=code_language_callback)

    # Exporter en Markdown
    filename = f"content/post/{date.year}/{date.month}/{slug}.md"
    os.makedirs(os.path.dirname(filename), exist_ok=True)
    print(f"Writing to {filename}")
    with open(filename, "w") as outfile:
        outfile.write(header + filtered_content)

    # Exporter le HTML brut pour le débogage
    raw_filename = f"../raw_content/post/{date.year}/{date.month}/{slug}.html"
    os.makedirs(os.path.dirname(raw_filename), exist_ok=True)
    with open(raw_filename, "w") as outfile:
        outfile.write(content)

for post in [post for post in posts]:
    export_post(post)

Check out similar posts by category: Python, Hugo