使用WebClient.DownloadFile()时返回403错误的技术求助
解决WebClient下载图片返回403错误的问题
问题根源分析
- 静态Cookie失效:你手动添加的
cf_chl_3是Cloudflare生成的临时验证Cookie,有效期极短,昨天能用今天失效完全是因为Cookie过期了,静态复制的Cookie无法长期复用。 - 请求头不匹配:你给GET请求添加了
Content-Type、Content-Length这类POST请求专属的头,服务器会判定请求不合法。 - 缺少Referer验证:目标服务器可能会检查图片请求的来源页面,没有Referer头会触发反爬拦截。
- WebClient的局限性:WebClient是较老旧的API,会话管理和请求控制不如HttpClient灵活。
解决方案1:使用HttpClient(推荐)
HttpClient支持自动会话保持,能动态获取并维护Cookie,请求控制更精细。
初始化带会话的HttpClient
var handler = new HttpClientHandler { CookieContainer = new CookieContainer(), UseCookies = true, // 自动处理压缩,匹配浏览器行为 AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate | DecompressionMethods.Brotli }; var httpClient = new HttpClient(handler) { BaseAddress = new Uri("https://thebarchive.com/") }; // 添加浏览器核心请求头,仅保留GET请求需要的 httpClient.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36"); httpClient.DefaultRequestHeaders.Add("Accept", "image/avif,image/webp,*/*;q=0.8"); httpClient.DefaultRequestHeaders.Add("Accept-Language", "en-US,en;q=0.5"); httpClient.DefaultRequestHeaders.Add("Upgrade-Insecure-Requests", "1");
完整下载逻辑
// 先访问线程页面,获取会话Cookie(关键步骤) var html = await httpClient.GetStringAsync(ThreadLink); var htmlDocument = new HtmlDocument(); htmlDocument.LoadHtml(html); var piclinks = htmlDocument.DocumentNode.Descendants("div") .Where(node => node.GetAttributeValue("class", "").Contains("thread_image_box")) .ToList(); foreach (var imagelink in piclinks) { string link = imagelink.InnerHtml; string linkfull = link.Substring(link.IndexOf("t/") + 2, link.IndexOf("target=") - 2 - (link.IndexOf("t/") + 2)); string downloadlink = $"https://thebarchive.com/b/full_image/{linkfull}"; try { // 创建GET请求并添加Referer头 var request = new HttpRequestMessage(HttpMethod.Get, downloadlink); request.Headers.Referrer = new Uri(ThreadLink); // 发送请求并保存文件 using (var response = await httpClient.SendAsync(request)) { response.EnsureSuccessStatusCode(); // 主动抛出非200状态码异常 using (var stream = await response.Content.ReadAsStreamAsync()) using (var fileStream = new FileStream(Path.Combine(folder, linkfull), FileMode.Create)) { await stream.CopyToAsync(fileStream); } } } catch (HttpRequestException ex) { Console.WriteLine($"下载失败,状态码:{ex.StatusCode}"); Console.WriteLine(ex.Message); } catch (Exception ex) { Console.WriteLine("无法加载文件,可能是视频或其他错误"); Console.WriteLine(ex.Message); } }
解决方案2:修正WebClient的请求配置
如果坚持使用WebClient,需要移除无效请求头并动态获取Cookie:
var wc = new WebClient(); // 仅保留GET请求需要的头 wc.Headers.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36"); wc.Headers.Add("Accept", "image/avif,image/webp,*/*"); wc.Headers.Add("Accept-Encoding", "gzip, deflate, br"); wc.Headers.Add("Referer", ThreadLink); // 必须添加Referer // 先访问线程页面,获取动态会话Cookie wc.DownloadString(ThreadLink); // 执行下载 try { wc.DownloadFile(downloadlink, Path.Combine(folder, linkfull)); } catch (Exception ex) { Console.WriteLine("无法加载文件,可能是视频或其他错误"); Console.WriteLine(ex); }
核心注意事项
- 绝对不要使用静态复制的Cloudflare Cookie,这类Cookie几分钟内就会过期,必须通过先访问目标页面的方式动态获取。
- GET请求不要添加POST专属的请求头(
Content-Type、Content-Length等),否则会触发服务器的非法请求拦截。 - 必须添加Referer头,证明图片请求来自合法的页面来源。
内容的提问来源于stack exchange,提问作者WebScrapNub
相关产品推荐
相关产品推荐

