如何使用Python递归下载SharePoint指定PDF并回传原路径
问题需求
- SharePoint指定路径下每日自动生成若干名称不固定的子文件夹,每个子文件夹内存储1个PDF文件
- 递归遍历目标路径下所有子文件夹,跳过名称为
Archive和Completed的子文件夹 - 将其余子文件夹内的所有PDF文件下载到本地指定目录
- 本地完成PDF内容分析后,将处理后的文件回传上传到SharePoint对应的原始子文件夹
现有代码问题
- 未做文件格式筛选,会下载路径下所有类型文件,无法仅提取PDF格式文件
- 仅遍历了
Dis_Out根目录下的直属文件,没有递归遍历嵌套子文件夹,也未实现指定文件夹的跳过逻辑
实现思路
- 封装递归遍历函数,传入当前待遍历的SharePoint文件夹对象、本地对应存储路径、路径映射字典:遍历过程中遇到文件夹名属于跳过列表时直接终止该分支遍历,其余子文件夹继续递归深入
- 遍历当前文件夹下的文件时,判断文件后缀是否为
.pdf(做大小写兼容,匹配.PDF等大写后缀),仅对符合格式要求的文件执行下载操作 - 下载时本地保持和SharePoint端一致的目录结构,同时记录「本地文件路径-远端所属文件夹路径」的映射关系,避免不同子文件夹下同名PDF互相覆盖,也为后续回传提供路径依据
- 本地PDF处理完成后,遍历之前记录的路径映射,将每个处理后的文件上传到对应的SharePoint文件夹即可
参考实现代码
import os from office365.sharepoint.client_context import ClientContext from office365.runtime.auth.authentication_context import AuthenticationContext # 基础配置 可根据实际情况修改 ONEDRIVE_BASE_URL = 'https://abc.sharepoint.com/' ONEDRIVE_SITE = '/sites/glas' REMOTE_ROOT_FOLDER = '/sites/glas/Shared Documents/Targeting/Bot_testing/Dis_Out/' LOCAL_SAVE_ROOT = './sharepoint_pdfs' SKIP_FOLDER_NAMES = {'Archive', 'Completed'} USER_INFO = { 'username': '你的SharePoint账号', 'password': '你的SharePoint密码' } def init_sharepoint_context(): """初始化SharePoint连接上下文""" ctx_auth = AuthenticationContext(url=ONEDRIVE_BASE_URL) ctx_auth.acquire_token_for_user(USER_INFO['username'], USER_INFO['password']) return ClientContext(f"{ONEDRIVE_BASE_URL}{ONEDRIVE_SITE}", ctx_auth) def recursive_download_pdfs(current_remote_folder, local_current_path, file_path_mapper): """ 递归遍历远端文件夹 下载符合要求的PDF :param current_remote_folder: 当前遍历的远端文件夹对象 :param local_current_path: 当前文件夹对应的本地存储路径 :param file_path_mapper: 存储 本地文件路径:远端所属文件夹路径 的映射 用于后续回传 """ ctx = current_remote_folder.context # 加载当前文件夹下的子文件夹和文件列表 ctx.load(current_remote_folder.folders) ctx.load(current_remote_folder.files) ctx.execute_query() # 创建本地对应目录 os.makedirs(local_current_path, exist_ok=True) # 下载当前目录下所有PDF文件 for remote_file in current_remote_folder.files: file_name = remote_file.properties['Name'] # 筛选PDF文件 兼容大小写后缀 if file_name.lower().endswith('.pdf'): local_file_abs_path = os.path.join(local_current_path, file_name) print(f"下载文件: {file_name} -> 本地路径: {local_file_abs_path}") with open(local_file_abs_path, 'wb') as local_f: remote_file.download(local_f).execute_query() # 记录路径映射 file_path_mapper[local_file_abs_path] = current_remote_folder.serverRelativeUrl # 递归处理子文件夹 跳过指定名称的文件夹 for sub_folder in current_remote_folder.folders: sub_folder_name = sub_folder.properties['Name'] if sub_folder_name in SKIP_FOLDER_NAMES: print(f"跳过指定文件夹: {sub_folder_name}") continue local_sub_path = os.path.join(local_current_path, sub_folder_name) recursive_download_pdfs(sub_folder, local_sub_path, file_path_mapper) return file_path_mapper def upload_processed_file(local_file_path, target_remote_folder_url): """将处理后的本地文件上传到指定远端文件夹""" ctx = init_sharepoint_context() target_folder = ctx.web.get_folder_by_server_relative_url(target_remote_folder_url) file_name = os.path.basename(local_file_path) with open(local_file_path, 'rb') as f: target_folder.upload_file(file_name, f.read()).execute_query() print(f"回传文件完成: {file_name} -> 远端路径: {target_remote_folder_url}") if __name__ == '__main__': # 初始化连接 获取远端根目录 ctx = init_sharepoint_context() remote_root = ctx.web.get_folder_by_server_relative_url(REMOTE_ROOT_FOLDER) ctx.load(remote_root) ctx.execute_query() # 执行PDF下载 path_mapping = recursive_download_pdfs(remote_root, LOCAL_SAVE_ROOT, {}) # -------------------------- 在此处插入你的PDF处理逻辑 -------------------------- for local_pdf in path_mapping.keys(): print(f"正在处理本地PDF文件: {local_pdf}") # 替换为你自己的PDF内容分析、修改逻辑 直接操作本地文件即可 # process_pdf(local_pdf) # ----------------------------------------------------------------------------- # 处理完成后批量回传文件 for local_path, remote_folder_url in path_mapping.items(): upload_processed_file(local_path, remote_folder_url)
注意事项
- 代码默认在本地保留和SharePoint端完全一致的目录结构,避免不同子文件夹下同名PDF被覆盖
- 文件夹跳过逻辑默认大小写敏感,如果你的环境中存在小写命名的
archive/completed文件夹,可自行往SKIP_FOLDER_NAMES集合中添加对应值 - 如果你的SharePoint环境不支持账号密码认证,可替换为客户端凭证认证方式,核心的遍历、下载、上传逻辑无需修改
内容的提问来源于stack exchange,提问作者Kash23
相关产品推荐
相关产品推荐

