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
相关产品推荐
相关产品推荐

