htmlagilitypackを使用してWebページをダウンロードする際のHTTPプロトコル違反
-
09-10-2019 - |
質問
www.mediafire.comからダウンロードページを解析しようとしていますが、本当に頻繁に取得します System.Net.WebException
次のメッセージで、ページをにロードしようとするとき HtmlDocument
:
サーバーはプロトコル違反をコミットしました。セクション= restonseStatusline
これは私のコードです:
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 Agility Packに直接関係していませんが、基礎となる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
これを確認するために、完全な16進レポート付きのソケットトレースを追加できます。
<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の設定を追加した場合、これは良いことです)が、これらの場合には優雅に失敗します。
他のヒント
Alive PropertyをFalseに設定すると、この問題が修正されます。しかし、htmlagilitypackがこのプロパティを持っているかどうかはわかりません。したがって、WebClientを使用することはより良い選択肢です。
これは私のために働いた。 URLをWeb.Loadで直接ロードする代わりに、カスタムWebClientを使用して目的のURLのHTMLをダウンロードします。 httpwebrequest.keepalive = falseを作成するカスタムWebClient Override getWebRequestメソッド。次に、ダウンロードしたファイルを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;
}
}
}