Does anyone know on how to bulk upload to Confluence knowldgebase page?

Does anyone know of any options for " bulk-uploading" .csv (MS Excel) files to a Confluence page? I have a pile of manually written knowledge incidents at hand that need to be registered as a Knowledge base on Confluence.

I have created below a pair of form (.csv) and an uploading script from a local PC via API. However, I have not tested yet. Can anyone review it and give me advice?

image

import pandas as pd
import requests
from requests.auth import HTTPBasicAuth
from dotenv import load_dotenv
import os
import html
import csv

Load environment variables

load_dotenv()

CONFLUENCE_EMAIL = os.getenv(“CONFLUENCE_EMAIL”)
CONFLUENCE_API_TOKEN = os.getenv(“CONFLUENCE_API_TOKEN”)
CONFLUENCE_URL = os.getenv(“CONFLUENCE_URL”)

auth = HTTPBasicAuth(CONFLUENCE_EMAIL, CONFLUENCE_API_TOKEN)
headers = {“Content-Type”: “application/json”}

Load CSV input

df = pd.read_csv(“confluence_plaintext_input_en.csv”, encoding=“utf-8”)

Convert plain text to HTML

def convert_to_html(row):
html_parts =
if pd.notna(row[‘Heading1’]) and row[‘Heading1’].strip():
html_parts.append(f"

{html.escape(row[‘Heading1’])}

“)
if pd.notna(row[‘Body1’]) and row[‘Body1’].strip():
html_parts.append(f”

{html.escape(row[‘Body1’])}

“)
if pd.notna(row[‘Heading2’]) and row[‘Heading2’].strip():
html_parts.append(f”

{html.escape(row[‘Heading2’])}

“)
if pd.notna(row[‘Body2’]) and row[‘Body2’].strip():
html_parts.append(f”

{html.escape(row[‘Body2’])}

")
return “\n”.join(html_parts)

Track log entries

log_entries =

Process and post each row

for index, row in df.iterrows():
html_body = convert_to_html(row)

page_data = {
    "type": "page",
    "title": row['Title'],
    "space": {"key": row['SpaceKey']},
    "body": {
        "storage": {
            "value": html_body,
            "representation": "storage"
        }
    }
}

if pd.notna(row['ParentPageID']):
    page_data["ancestors"] = [{"id": int(row['ParentPageID'])}]

response = requests.post(
    f"{CONFLUENCE_URL}/rest/api/content",
    headers=headers,
    auth=auth,
    json=page_data
)

status = response.status_code
page_id = ""
url = ""
if status in [200, 201]:
    try:
        page_id = response.json().get("id")
        url = f"{CONFLUENCE_URL}/pages/{page_id}"
    except Exception:
        url = "Unknown (parse failed)"

log_entries.append({
    "Title": row['Title'],
    "Status": status,
    "URL": url
})

print(f"[{row['Title']}] Status: {status}")
if status not in [200, 201]:
    print("Error details:", response.text)

Write log to CSV

with open(“upload_log_en.csv”, mode=“w”, newline=“”, encoding=“utf-8-sig”) as logfile:
fieldnames = [“Title”, “Status”, “URL”]
writer = csv.DictWriter(logfile, fieldnames=fieldnames)
writer.writeheader()
writer.writerows(log_entries)

print(“\n[INFO] Upload log saved to upload_log_en.csv”)