HttpWebRequest 返回“(403)禁止”错误

11

我编写了一个XML抓取器,用于从网站接收/解码XML文件。它大多数时候都工作正常,但总是返回错误:

"远程服务器返回错误:(403)禁止访问。"

针对这个网站:http://w1.weather.gov/xml/current_obs/KSRQ.xml

我的代码如下:

CookieContainer cookies = new CookieContainer();
HttpWebRequest webRequest = (HttpWebRequest)HttpWebRequest.Create(Path);
webRequest.Method = "GET";
webRequest.CookieContainer = cookies;
using (HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse())
{
    using (StreamReader streamReader = new StreamReader(webResponse.GetResponseStream()))
    {
        string xml = streamReader.ReadToEnd();
        xmldoc.LoadXml(xml);
    }
}

而异常是在 GetResponse 方法中抛出的。我该如何找出发生了什么?


@MethodMan - 基于最后一行,我认为代码没有执行到那里。它在方法GetResponse()的第一个using块中失败。 - Igor
请求 xml,扩展名为 xml,获取 HTML,你会喜欢它的。政府。 - user1228
@Igor 不,这并不是预期的结果。我也感到困惑。但是我可以在Chrome浏览器的调试控制台中获取真实的XML文件。 - ncite
@Will:实际上它返回的是XML。该XML包含一个样式表指令,由浏览器自动读取和处理。当OP在代码中发出请求时,它将返回纯XML。我认为这是一种非常友好的Web方式 :o) - Mike Goodwin
1
@MikeGoodwin ... ... ... 嗯,但是还是这样。 - user1228
显示剩余2条评论
4个回答

22

可能是您的请求缺少服务器所需的标头。我在浏览器中请求了页面,使用 Fiddler 记录了准确的请求,然后删除了 User-Agent 标头并重新发出请求。这导致了403响应。

通常情况下,服务器会尝试防止脚本对其站点进行编写,就像您正在执行的操作一样;)

在这种情况下,403响应中的服务器标头为“AkamaiGHost”,这表明是来自Akamai某种云安全解决方案的边缘节点。也许是触发403的WAF规则阻止了机器人。

似乎将任何值添加到 User-Agent 标头都可以为此网站工作。例如,我将其设置为“绝不是屏幕刮板”,这似乎运行良好。

通常,当您遇到此类问题时,查看实际的 HTTP 请求和响应通常很有帮助,可以使用浏览器工具或 Fiddler 等代理来查看。正如 Scott Hanselman 所说

互联网不是黑匣子

http://www.hanselman.com/blog/TheInternetIsNotABlackBoxLookInside.aspx


1
我同意,这可能是罪魁祸首。@ncite - 请参考我昨天写的之前的SO答案如何在C#中不进行任何身份验证消耗WebAp2,它有完全相同的问题,并通过添加用户代理标头得到了解决。 - Igor
谢谢!Mike Goodwin和@Igor。 - ncite
它可以是除了“User-Agent”之外的其他东西,我只是遇到了一个问题,结果发现缺少了“X-Requested-With”头。 - DavidP

16

显然,该URL在浏览器中可以使用。但是从代码中无法使用。似乎服务器基于用户代理接受/拒绝请求,可能是为了尝试防止网络爬虫。

为了通过验证,只需将UserAgent属性设置为服务器能够识别的内容,例如:

webRequest.UserAgent = @"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36";

看起来似乎有效。


2
在我的情况中,服务器不喜欢的不是UserAgent头部,而是Accept头部。
request.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8";

你可以使用浏览器的开发工具中的网络选项卡来查看正确的头信息。

1

您的请求是否通过代理服务器进行?如果是,请在GetResponse()调用之前添加以下行。

webRequest.Proxy.Credentials = System.Net.CredentialCache.DefaultCredentials;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接