使用htmlagilitypack下载网页时违反HTTP协议
-
09-10-2019 - |
题
我正在尝试从www.mediafire.com分析页面,但我真的经常得到一个 System.Net.WebException
在以下消息中,当我尝试将页面加载到一个 HtmlDocument
:
服务器违反了协议。部分= ResponseStatUsline
这是我的代码:
HtmlAgilityPack.HtmlWeb web = new HtmlAgilityPack.HtmlWeb();
HtmlAgilityPack.HtmlDocument doc = null;
string url = www.mediafire.com/?abcdefghijkl //There are many different links
try
{
doc = web.Load(url); //From 30 links, usually only 10 load properly
}
catch (WebException)
{
}
有什么想法为什么只有30个链接中只有10个工作(每次链接都会改变,因为我的程序是“搜索引擎”)以及如何解决问题?
当我将这些站点加载到浏览器中时,一切正常。
我尝试将以下行添加到我的app.config,但这也无济于事
<system.net>
<settings>
<httpWebRequest useUnsafeHeaderParsing="true" />
</settings>
</system.net>
解决方案
这与HTML敏捷性包直接相关,而与基础HTTP/套接字层有关。此错误意味着服务器没有向正确的HTTP状态行发送。
状态行在HTTP RFC中定义:此处可用: http://www.w3.org/protocols/rfc2616/rfc2616-sec6.html
我引用:
响应消息的第一行是状态线,由协议版本组成,然后是数字状态代码及其关联的文本短语,每个元素都由SP字符分开。除了最终CRLF序列中,不允许使用CR或LF。
Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF
您可以添加带有完整十六进制报告的套接字跟踪以检查以下内容:
<configuration>
<system.diagnostics>
<sources>
<source name="System.Net.Sockets" tracemode="includehex">
<listeners>
<add name="System.Net.Sockets" type="System.Diagnostics.TextWriterTraceListener" initializeData="SocketTrace.log" />
</listeners>
</source>
</sources>
<switches>
<add name="System.Net.Sockets" value="Verbose"/>
</switches>
<trace autoflush="true" />
</system.diagnostics>
</configuration>
这将在当前执行目录中创建一个socketTrace.log文件。看看那里,应看到违反协议的行为。您可以在这里发布,如果它不太大:-)
不幸的是,如果您不拥有服务器,那么您无法做到太多(如果您已经添加了UseunSafeheaderParsing设置,那很好),但在这些情况下会优雅地失败。
其他提示
将“活着的属性”设置为false将解决此问题。但是我不确定htmlagilitypack是否具有此属性。因此,使用WebClient将是更好的选择。
这对我有用。而不是使用Web.load直接加载URL,而是使用自定义WebClient下载所需URL的HTML。在您的自定义WebClient override getwebrequest中,使httpwebrequest.keepalive = false。现在,将下载的文件加载到Web.load()中。
MyWebClient client = new MyWebClient();
client.DownloadFile(searchURL, @"C:\\index.html");
var doc = web.Load("C:\\index.html");
覆盖getwebrequest
using System;
using System.Net;
namespace MyProject
{
internal class CustomWebClient : WebClient
{
protected override WebRequest GetWebRequest(Uri address)
{
WebRequest request = base.GetWebRequest(address);
if (request is HttpWebRequest)
{
(request as HttpWebRequest).KeepAlive = false;
}
return request;
}
}
}