.NET Selenium图片下载遇403禁止错误,求自动下载解决方案
解决Selenium下载图片触发403 Forbidden的方案
方案1:复用浏览器Cookie到请求头
网站反爬策略通常会验证请求是否携带当前会话的Cookie,你当前用WebClient单独发起请求,未带上Selenium浏览器中的会话Cookie,这是触发403的核心原因之一。可以从ChromeDriver中提取Cookie,添加到WebClient的请求头里:
修改代码中的WebClient配置部分:
using WebClient webClient = new(); // 直接复用浏览器的User-Agent,避免手动填写不一致 string userAgent = driver.ExecuteScript("return navigator.userAgent").ToString(); webClient.Headers.Add("User-Agent", userAgent); Uri uri = new(url); string referer = $"{uri.Scheme}://{uri.Host}/"; webClient.Headers.Add("Referer", referer); // 提取浏览器Cookie并添加到请求头 var cookies = driver.Manage().Cookies.AllCookies; string cookieHeader = string.Join(";", cookies.Select(c => $"{c.Name}={c.Value}")); webClient.Headers.Add(HttpRequestHeader.Cookie, cookieHeader); // 保留其他必要头信息 webClient.Headers.Add("Sec-Ch-Ua", "Not_A Brand\";v=\"8\", \"Chromium\";v=\"120\", \"Google Chrome\";v=\"120"); webClient.Headers.Add("Sec-Ch-Ua-Mobile", "?0"); webClient.Headers.Add("Sec-Ch-Ua-Platform", "\"Windows\"");
方案2:通过JavaScript将图片转为Base64保存
绕开单独的HTTP请求,直接在浏览器上下文里获取图片的Base64编码,再写入本地文件,完全模拟浏览器环境:
修改循环内的下载逻辑:
for (int i = 0; i < imageElements.Count; i++) { string fileName = $"{Guid.NewGuid()}_{i + 1}.jpg"; string filePath = Path.Combine(downloadFolder, fileName); try { var imageElement = imageElements[i]; string imageUrl = imageElement.GetAttribute("src"); // 执行JS获取图片Base64编码 string base64Image = (string)driver.ExecuteScript(@" function getBase64(img) { const canvas = document.createElement('canvas'); canvas.width = img.naturalWidth; canvas.height = img.naturalHeight; const ctx = canvas.getContext('2d'); ctx.drawImage(img, 0, 0); return canvas.toDataURL('image/jpeg', 0.9); } return getBase64(arguments[0]); ", imageElement); // 去除Base64前缀并解码保存 string base64Data = base64Image.Split(',').Last(); byte[] imageBytes = Convert.FromBase64String(base64Data); await File.WriteAllBytesAsync(filePath, imageBytes); Console.WriteLine($"{fileName} 下载完成"); } catch (Exception ex) { Console.WriteLine($"{fileName} => 错误: {ex.Message}"); } }
如果遇到跨域阻止Canvas绘制的问题,给Chrome添加跨域参数:
var options = new ChromeOptions(); options.AddArgument("--disable-web-security"); options.AddArgument("--allow-running-insecure-content"); options.AddArgument("--disable-features=CrossSiteDocumentBlockingIfIsolating");
方案3:配置Chrome自动下载,触发浏览器原生下载
通过Chrome的下载设置,让Selenium直接触发浏览器的下载行为,完全模拟手动操作:
首先配置Chrome的下载路径和自动下载规则:
var options = new ChromeOptions(); var downloadPrefs = new Dictionary<string, object> { ["download.default_directory"] = downloadFolder, ["download.prompt_for_download"] = false, ["download.directory_upgrade"] = true, ["safebrowsing.enabled"] = true }; options.AddUserProfilePreference("download", downloadPrefs);
然后修改下载逻辑,用JS创建a标签触发下载:
for (int i = 0; i < imageElements.Count; i++) { string fileName = $"{Guid.NewGuid()}_{i + 1}.jpg"; try { var imageElement = imageElements[i]; string imageUrl = imageElement.GetAttribute("src"); // 执行JS触发浏览器原生下载 driver.ExecuteScript(@" const a = document.createElement('a'); a.href = arguments[0]; a.download = arguments[1]; document.body.appendChild(a); a.click(); document.body.removeChild(a); ", imageUrl, fileName); // 等待下载完成(可根据图片大小调整等待时间) Thread.Sleep(1500); Console.WriteLine($"{fileName} 下载完成"); } catch (Exception ex) { Console.WriteLine($"{fileName} => 错误: {ex.Message}"); } }
额外建议
- 替换过时的
WebClient为HttpClient,后者更稳定且支持现代HTTP特性; - 可通过Chrome开发者工具的Network面板,复制浏览器请求的完整头信息,确保代码中的请求头与浏览器完全一致;
- 添加随机延迟,避免短时间内高频请求触发反爬机制。
内容的提问来源于stack exchange,提问作者Sakin WarTera
相关产品推荐
相关产品推荐

