C# で動的 Web スクレイパーを実装するためのロジック
-
22-09-2019 - |
質問
C#ウィンドウフォームでWebスクレイパーを開発しようとしています。私が達成しようとしていることは次のとおりです。
- ユーザーから URL を取得します。
- WINForms の IE UI コントロール (埋め込みブラウザ) に Web ページを読み込みます。
- ユーザーがテキスト (連続、小さい (50 文字を超えない)) を選択できるようにします。ロードされた Web ページから。
- ユーザーが場所を永続化したい場合 (HTML DOM の場所) ユーザーが次回の訪問時にその場所を使用してその場所にあるデータをフェッチできるように、データを DB に永続化する必要があります。
読み込まれた Web サイトが価格リスト サイトで、見積料金が変化し続けると仮定すると、次回は DOM 階層をたどることができるように DOM 階層を永続化することが考えられます。
すべての HTML 要素に id 属性があれば、これを行うことができます。ID が null の場合、これを達成することはできません。
誰かがこれに関する有効なアイデアを提案してもらえますか(可能であれば最小限のコードスニペット)。
いくつかのオンライン リソースを共有していただければ助かります。
ありがとう、
ビジェイ
解決
1 つのアプローチは、選択する要素に至るまでタグ/スタイル/ID のスタックを構築することです。
必要な要素から、最も近い id 要素まで移動します。こうすることで、上部のヘッダーなどの大部分が削除されます。次に、検索するシーケンスを構築します。
例:
<html>
<body>
<!-- lots of html -->
<div id="main">
<div>
<span>
<div class="pricearea">
<table> <!-- with price data -->
たとえば、次のシーケンスをデータベースに保存します。 [id=main],div,span,div,table 多分 div[クラス=価格エリア],テーブル.
スタイル/クラスを使用してパスを作成することもできます。タグ、タグの属性、またはその組み合わせを検索するかどうかは自由に選択できます。堅牢にするために、できる限り少ない要素で可能な限り正確なデータが必要です。
レイアウトがめったに変わらない場合、これにより毎回同じ場所に移動できます。
また、おそらく使用することをお勧めします HTML アジリティ パック IE 制御が遅いため、DOM 解析に同様のものを使用します。
画面スクレイピングは楽しいですが、すべてのページで 100% の結果を得るのは困難です。幸運を!
他のヒント
少しグーグルで調べたところ、非常に簡単な解決策を見つけました。以下にサンプル スニペットを添付します。
if (webBrowser.Document != null)
{
IHTMLDocument2 HtmlDoc = (IHTMLDocument2)webBrowser.Document.DomDocument;// loads the HTML DOM
IHTMLSelectionObject selection = HtmlDoc.selection;// Fetches the currently selected HTML Element.
IHTMLTxtRange range = (IHTMLTxtRange)selection.createRange();
IHTMLElement parentElement = range.parentElement();// Identifies the parent element
targetSourceIndex = parentElement.sourceIndex;
//dataLocation = range.parentElement().id;
MessageBox.Show(range.text);//range.parentElement().sourceIndex
}
私が使用したのは、 組み込み Web ブラウザ Winforms アプリケーションで、現在の Web ページの HTML DOM を読み込みます。
の IHTML要素 インスタンスは、各 HTML 要素に一意の ID を割り当てる「SourceIndex」という名前のプロパティを公開します。
この SourceIndex を DB に保存し、その場所にあるコンテンツをクエリできます。次のコードを使用します。
if (webBrowser.Document != null)
{
IHTMLDocument2 HtmlDoc = (IHTMLDocument2)webBrowser.Document.DomDocument;
IHTMLElement targetElement = null;
foreach (IHTMLElement domElement in HtmlDoc.all)
{
if (domElement.sourceIndex == int.Parse(node.InnerText))// fetching the persisted data from the XML file.
{
targetElement = domElement;
break;
}
}
MessageBox.Show(targetElement.innerText); //range.parentElement().sourceIndex
}