使用Playwright下载文件时如何获取下载进度的百分比?
Playwright C# 获取下载进度百分比解决方案
Playwright 官方原生API暂未直接提供下载进度的回调事件,你目前的写法直接调用await e.SaveAsAsync(path)只能等待下载完成,无法获取中间进度,可通过以下两种方案实现:
方案1:提取下载链接用HttpClient自主下载(最稳定)
思路:在Download事件中拿到下载地址,复用Playwright上下文的请求头、Cookie,用HttpClient发起下载,通过进度回调计算百分比
示例代码:
using System.Net.Http.Headers; using (var playWright = await Playwright.CreateAsync()) { string DownloadDirectory = @"你的本地保存目录"; BrowserTypeLaunchOptions browserLaunchOptions = new BrowserTypeLaunchOptions() { Headless = true}; var browser = await playWright.Chromium.LaunchAsync(browserLaunchOptions); var browserContextOptions = new BrowserNewContextOptions() { AcceptDownloads = true }; var context = await browser.NewContextAsync(browserContextOptions); var page = await context.NewPageAsync(); page.Download += async (object sender, IDownload e) => { var downloadUrl = e.Url; var savePath = Path.Combine(DownloadDirectory, e.SuggestedFilename); // 复用Playwright上下文的Cookie,避免权限校验失败 var cookies = await context.CookiesAsync(new List<string> { downloadUrl }); using var httpClient = new HttpClient(); foreach (var cookie in cookies) { httpClient.DefaultRequestHeaders.Add("Cookie", $"{cookie.Name}={cookie.Value}"); } // 发起请求获取响应头 using var response = await httpClient.GetAsync(downloadUrl, HttpCompletionOption.ResponseHeadersRead); response.EnsureSuccessStatusCode(); var totalBytes = response.Content.Headers.ContentLength ?? -1; var downloadedBytes = 0L; var buffer = new byte[8192]; await using var contentStream = await response.Content.ReadAsStreamAsync(); await using var fileStream = new FileStream(savePath, FileMode.Create, FileAccess.Write, FileShare.None, buffer.Length, true); int bytesRead; while ((bytesRead = await contentStream.ReadAsync(buffer)) > 0) { await fileStream.WriteAsync(buffer.AsMemory(0, bytesRead)); downloadedBytes += bytesRead; if (totalBytes > 0) { var progress = (double)downloadedBytes / totalBytes * 100; // 此处可替换为你自己的进度处理逻辑 Console.WriteLine($"下载进度:{progress:F2}%"); } } }; await page.GotoAsync("你的目标页面URL"); }
注意:如果下载链接是一次性的或者带动态签名,需要保证HttpClient请求在链接失效前发起。
方案2:监控本地文件大小变化计算进度
思路:在调用SaveAsAsync的同时,启动后台任务轮询已保存的文件大小,结合响应头返回的文件总大小计算进度
示例代码片段:
page.Download += async (object sender, IDownload e) => { var savePath = Path.Combine(DownloadDirectory, e.SuggestedFilename); // 先获取下载响应的总大小 var response = await e.ResponseAsync(); var totalBytes = response.Headers.TryGetValue("Content-Length", out var contentLength) ? long.Parse(contentLength) : -1; // 开后台任务轮询进度 _ = Task.Run(async () => { while (!e.FailureAsync().IsCompleted) { await Task.Delay(500); if (File.Exists(savePath)) { var fileInfo = new FileInfo(savePath); var downloadedBytes = fileInfo.Length; if (totalBytes > 0) { var progress = (double)downloadedBytes / totalBytes * 100; Console.WriteLine($"下载进度:{progress:F2}%"); } } } }); // 等待下载保存完成 await e.SaveAsAsync(savePath); Console.WriteLine("下载完成"); };
注意:这个方案依赖响应头返回正确的Content-Length,如果是分片下载或者服务端没有返回该字段,总大小获取会失败,进度计算将不准确。
内容的提问来源于stack exchange,提问作者Dorel
相关产品推荐
相关产品推荐

