使用C# HttpClient爬取NGO Darpan数据遇403 Forbidden错误求助
解决HttpClient请求ngodarpan.gov.in返回403 Forbidden的问题
我之前碰到过类似的网站反爬场景,你的问题核心在于没有维持请求上下文的一致性,而且缺少必要的浏览器请求头模拟,服务器直接识别出这是非浏览器发起的请求,所以返回了403。下面一步步帮你解决:
问题根源拆解
这个网站的反爬校验包含几个关键点:
- 请求必须携带和获取csrf_token时一致的Cookie(服务器会验证Cookie与表单里的csrf值是否匹配)
- 需要模拟浏览器的核心请求头(比如User-Agent、Referer),否则会被判定为程序爬虫
- 不能每次请求都新建HttpClient实例,否则Cookie容器会被重置,导致上下文断裂
你的代码里用了全新的HttpClient,也没设置任何请求头,自然过不了服务器的校验。
修正后的实现步骤
- 复用同一个HttpClient实例:HttpClient会自动维护Cookie容器,这样获取csrf_token时服务器设置的Cookie会被保留到后续请求中
- 添加浏览器请求头:至少要设置User-Agent和Referer,让请求看起来和正常浏览器访问一致
- 正确获取并传递csrf_token:先调用
get_csrf接口拿到有效csrf值,再将其传入show_ngo_info接口,同时确保Cookie同步
修改后的测试代码
private async Task FetchNgoDetailsAsync() { // 复用同一个HttpClient,自动管理Cookie上下文 using var client = new HttpClient(); // 模拟Chrome浏览器的请求头,可根据实际浏览器调整 client.DefaultRequestHeaders.UserAgent.ParseAdd("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36"); // 设置Referer为列表页,模拟从列表页点击进入详情的流程 client.DefaultRequestHeaders.Referrer = new Uri("https://ngodarpan.gov.in/index.php/home/statewise_ngo/5972/33/1"); // 第一步:获取csrf_token及对应的Cookie var csrfResponse = await client.GetAsync("https://ngodarpan.gov.in/index.php/ajaxcontroller/get_csrf"); csrfResponse.EnsureSuccessStatusCode(); var csrfToken = (await csrfResponse.Content.ReadAsStringAsync()).Trim(); // 注意:如果返回的csrfToken包含多余字符(比如引号),需要额外处理 // 第二步:构造表单数据,传入NGO id和csrf参数 var formData = new List<KeyValuePair<string, string>> { new KeyValuePair<string, string>("id", "169486"), new KeyValuePair<string, string>("csrf_cookie_name", csrfToken) }; var content = new FormUrlEncodedContent(formData); // 第三步:发起POST请求获取NGO详情 var response = await client.PostAsync("https://ngodarpan.gov.in/index.php/ajaxcontroller/show_ngo_info", content); if (response.IsSuccessStatusCode) { var ngoDetails = await response.Content.ReadAsStringAsync(); // 这里可以解析返回的HTML/JSON数据 Console.WriteLine(ngoDetails); } else { Console.WriteLine($"请求失败:{response.StatusCode} - {response.ReasonPhrase}"); // 打印错误内容,查看服务器的具体提示 var errorContent = await response.Content.ReadAsStringAsync(); Console.WriteLine(errorContent); } }
额外提醒
- 如果还是返回403,可以复制浏览器的完整请求头(比如Accept、Accept-Language、Cache-Control等)添加到HttpClient中,完全模拟浏览器请求
- 不要短时间内频繁发起请求,建议添加1-2秒的延迟,避免IP被封禁
- 部分网站会检查请求顺序,确保先访问列表页再请求详情,你设置的Referer已经覆盖了这一点
内容的提问来源于stack exchange,提问作者Prasanna
相关产品推荐
相关产品推荐

