使用CSOM读取SharePoint站点页面并本地存储的问题求助
我看你当前的代码有几个小问题导致拿不到页面内容,咱们一步步来修正:
1. 精准定位页面库
页面库的BaseTemplate是119没错,但你加载Lists的方式有点重复且不够精准。可以直接通过标题获取页面库(默认英文环境叫"Site Pages",中文环境通常是"站点页面"):
// 获取站点页面库 List pagesLibrary = web.Lists.GetByTitle("Site Pages"); clientcontext.Load(pagesLibrary); clientcontext.ExecuteQuery();
2. 加载页面时必须指定内容字段
默认获取ListItem不会自动加载页面的核心内容字段,你需要明确指定要加载的字段——现代页面用CanvasContent1,经典发布页面用PublishingPageContent:
CamlQuery cq = CamlQuery.CreateAllItemsQuery(); ListItemCollection pageItems = pagesLibrary.GetItems(cq); // 加载页面标题、内容、发布状态等关键字段 clientcontext.Load(pageItems, items => items.Include( item => item["Title"], item => item["CanvasContent1"], // 现代页面内容字段 item => item["PublishingPageContent"], // 经典发布页面内容字段 item => item["Level"] // 用于判断是否已发布 )); clientcontext.ExecuteQuery();
3. 筛选已发布/未发布页面
如果需要区分已发布(已批准)和未发布(草稿)页面,可以在CAML查询中添加过滤条件:
// 筛选已发布页面:Level字段值为2代表已发布,1代表草稿 string camlXml = @" <View> <Query> <Where> <Eq> <FieldRef Name='Level' /> <Value Type='Integer'>2</Value> </Eq> </Where> </Query> </View>"; CamlQuery cq = new CamlQuery { ViewXml = camlXml };
4. 保存页面内容到本地
拿到页面内容后,就可以写入本地文件了,这里还做了重名处理避免覆盖:
// 创建本地存储目录 string localSaveDir = @"C:\LocalSharePointPages"; if (!Directory.Exists(localSaveDir)) { Directory.CreateDirectory(localSaveDir); } foreach (ListItem page in pageItems) { string pageTitle = page["Title"].ToString(); // 判断页面发布状态 bool isPublished = page["Level"] != null && (int)page["Level"] == 2; string statusSuffix = isPublished ? "_已发布" : "_草稿"; // 根据页面类型获取内容 string pageContent = string.Empty; if (page.FieldValues.ContainsKey("CanvasContent1")) { pageContent = page["CanvasContent1"].ToString(); } else if (page.FieldValues.ContainsKey("PublishingPageContent")) { pageContent = page["PublishingPageContent"].ToString(); } // 处理重名文件 string filePath = Path.Combine(localSaveDir, $"{pageTitle}{statusSuffix}.html"); int counter = 1; while (File.Exists(filePath)) { filePath = Path.Combine(localSaveDir, $"{pageTitle}{statusSuffix}_{counter}.html"); counter++; } File.WriteAllText(filePath, pageContent); Console.WriteLine($"已保存:{filePath}"); }
完整修正后的代码示例
using Microsoft.SharePoint.Client; using System.IO; using System.Security; class SharePointPageExporter { static void Main(string[] args) { string siteUrl = "https://你的租户.sharepoint.com/sites/你的站点"; string userId = "你的账号@租户.onmicrosoft.com"; string password = "你的密码"; SecureString securePass = new SecureString(); foreach (char c in password) { securePass.AppendChar(c); } using (ClientContext clientContext = new ClientContext(siteUrl)) { clientContext.Credentials = new SharePointOnlineCredentials(userId, securePass); Web web = clientContext.Web; clientContext.Load(web); clientContext.ExecuteQuery(); // 获取站点页面库(中文环境改为"站点页面") List pagesLibrary = web.Lists.GetByTitle("Site Pages"); clientContext.Load(pagesLibrary); clientContext.ExecuteQuery(); // 查询所有页面并加载必要字段 CamlQuery cq = CamlQuery.CreateAllItemsQuery(); ListItemCollection pageItems = pagesLibrary.GetItems(cq); clientContext.Load(pageItems, items => items.Include( item => item["Title"], item => item["CanvasContent1"], item => item["PublishingPageContent"], item => item["Level"] )); clientContext.ExecuteQuery(); // 本地存储目录 string localDir = @"C:\LocalSharePointPages"; if (!Directory.Exists(localDir)) { Directory.CreateDirectory(localDir); } foreach (ListItem page in pageItems) { string pageTitle = page["Title"].ToString(); bool isPublished = page["Level"] != null && (int)page["Level"] == 2; string statusSuffix = isPublished ? "_已发布" : "_草稿"; string pageContent = string.Empty; if (page.FieldValues.ContainsKey("CanvasContent1")) { pageContent = page["CanvasContent1"].ToString(); } else if (page.FieldValues.ContainsKey("PublishingPageContent")) { pageContent = page["PublishingPageContent"].ToString(); } // 避免文件名重复 string filePath = Path.Combine(localDir, $"{pageTitle}{statusSuffix}.html"); int counter = 1; while (File.Exists(filePath)) { filePath = Path.Combine(localDir, $"{pageTitle}{statusSuffix}_{counter}.html"); counter++; } File.WriteAllText(filePath, pageContent); Console.WriteLine($"保存成功:{filePath}"); } } } }
几个额外注意点:
- 确保你的账号有站点页面库的读取权限
- 中文环境下记得把
GetByTitle的参数改成"站点页面" - 现代页面和经典页面的内容字段不同,代码里已经做了兼容判断
内容的提问来源于stack exchange,提问作者MSJ
相关产品推荐
相关产品推荐

