You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python调用Confluence API批量导出空间页面为PDF遇阻

解决Confluence页面PDF导出脚本失败问题及层级批量下载方案

一、修复单个页面PDF下载失败

你当前使用的pdfpageexport.action是Confluence的Web UI端点,并非官方REST API,直接GET请求通常返回导出页面的HTML而非PDF文件。改用官方REST API的导出端点,并调整请求配置即可解决:

修正后的单页面导出脚本

import requests
from requests.auth import HTTPBasicAuth

# 配置信息
base_url = "https://abc-services.atlassian.net"
username = "qwerty.abcd@xyz.com"
api_token = "YOUR_API_TOKEN"
page_id = "463***765"

# 官方REST API的PDF导出端点
export_url = f"{base_url}/rest/api/content/{page_id}/export/pdf"

# 请求头:指定接受PDF格式,关闭CSRF检查
headers = {
    "Accept": "application/pdf",
    "X-Atlassian-Token": "no-check"
}

# 发送请求,允许自动重定向(导出请求会临时跳转)
response = requests.get(
    export_url,
    auth=HTTPBasicAuth(username, api_token),
    headers=headers,
    allow_redirects=True
)

if response.status_code == 200:
    # 从响应头获取文件名(可选,也可自定义)
    filename = f"page_{page_id}.pdf"
    with open(filename, 'wb') as f:
        f.write(response.content)
    print(f"PDF已保存为: {filename}")
else:
    print(f"请求失败,状态码: {response.status_code}")
    print(response.text)

关键调整点

  • 使用官方REST API端点/rest/api/content/{page_id}/export/pdf,而非Web UI的action端点
  • 添加Accept: application/pdf头,明确告知服务器返回PDF格式
  • 开启allow_redirects=True,处理导出时的临时重定向

二、实现指定空间内页面层级批量导出PDF

要按层级下载所有页面,需要先递归获取空间内的页面树结构,再逐个导出:

完整批量导出脚本

import requests
from requests.auth import HTTPBasicAuth
import os

# 全局配置
base_url = "https://abc-services.atlassian.net"
space_key = "SPACE"
username = "qwerty.abcd@xyz.com"
api_token = "YOUR_API_TOKEN"
save_dir = "confluence_pdf_export"

# 创建保存目录
os.makedirs(save_dir, exist_ok=True)

def get_page_children(page_id):
    """递归获取页面的所有子页面"""
    url = f"{base_url}/rest/api/content/{page_id}/child/page"
    params = {"limit": 100}
    response = requests.get(
        url,
        auth=HTTPBasicAuth(username, api_token),
        params=params
    )
    response.raise_for_status()
    pages = response.json()["results"]
    
    # 递归获取子页面的子页面
    for page in pages:
        page["children"] = get_page_children(page["id"])
    return pages

def get_space_root_pages(space_key):
    """获取空间的所有根页面"""
    url = f"{base_url}/rest/api/content"
    params = {
        "spaceKey": space_key,
        "type": "page",
        "limit": 100,
        "expand": "ancestors"
    }
    response = requests.get(
        url,
        auth=HTTPBasicAuth(username, api_token),
        params=params
    )
    response.raise_for_status()
    # 筛选根页面(无父页面的页面)
    root_pages = [p for p in response.json()["results"] if len(p["ancestors"]) == 0]
    return root_pages

def export_page_to_pdf(page_id, page_title, parent_path=""):
    """导出单个页面为PDF,按层级保存"""
    export_url = f"{base_url}/rest/api/content/{page_id}/export/pdf"
    headers = {
        "Accept": "application/pdf",
        "X-Atlassian-Token": "no-check"
    }
    response = requests.get(
        export_url,
        auth=HTTPBasicAuth(username, api_token),
        headers=headers,
        allow_redirects=True
    )
    response.raise_for_status()
    
    # 处理标题中的非法字符
    safe_title = page_title.replace("/", "_").replace("\\", "_").replace(":", "_")
    # 构建保存路径
    full_path = os.path.join(save_dir, parent_path, f"{safe_title}.pdf")
    os.makedirs(os.path.dirname(full_path), exist_ok=True)
    
    with open(full_path, 'wb') as f:
        f.write(response.content)
    print(f"已导出: {full_path}")

def export_pages_recursively(pages, parent_path=""):
    """递归导出所有页面"""
    for page in pages:
        # 导出当前页面
        export_page_to_pdf(page["id"], page["title"], parent_path)
        # 导出子页面,子路径为当前页面标题
        child_path = os.path.join(parent_path, page["title"].replace("/", "_").replace("\\", "_").replace(":", "_"))
        export_pages_recursively(page["children"], child_path)

if __name__ == "__main__":
    # 获取空间根页面
    root_pages = get_space_root_pages(space_key)
    # 递归导出所有页面
    export_pages_recursively(root_pages)
    print("所有页面导出完成!")

脚本功能说明

  • 页面树获取:通过REST API获取空间根页面,并递归遍历所有子页面,保持层级结构
  • 层级保存:按页面的父级关系创建文件夹,PDF文件名使用页面标题(自动处理非法字符)
  • 错误处理:使用raise_for_status()捕获请求异常,确保导出过程可追溯

常见问题排查

  • 如果仍导出失败,检查API令牌是否有Confluence的内容导出权限
  • 若遇到403状态码,确认账号对目标空间有查看和导出权限
  • 大页面导出可能需要增加超时时间,可在requests.get()中添加timeout=30参数

内容的提问来源于stack exchange,提问作者sdave

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 23:53:18