質問: 私の問題は、テーブルからdiv InnerTextを取得できないということです。私は正常に別の種類のデータを追加しましたが、テーブルからdivを読み込む方法がわかりません。 次の図ではdivを強調表示しています。この場合はInnerTextを取得する必要があります(番号3)。 最初の写真はここをクリック 私は次のパスを使用してこれを達成しようとしています: ``` "//div[@class='kal']//table//tr[2]/td[1]/div[@class='cipars']" ``` しかし、私は次のエラーが発生しています: エラーメッセージの画像はここをクリック コードの残りが正しく書かれていると仮定すると、誰かが正しい方向に私を向けることができますか?私はこれを理解しようとしていますが、結果は得られません。
回答: したがって、問題は、XPath内のポジションに依存していることです。ある種の`tr` **最初の** `td`がクラスと`div`を持つことを期待しているので、これはいくつかのケースではOKですが、ここにはありません。 Chromeのソースを見ると、これは必ずしもそうとは限りません。これは、カレンダーの「1」要素を「2」と「3」と比較することで確認できます。あなたは "1"要素がその周りにいくつかの要素を持っていることに気づくでしょう。他の要素はそうではありません。 元のXPathクエリは要素を返さないため、エラーが発生しています。 HtmlAgilityPackに与えるXPathクエリでDOM要素が生成されない場合は、nullが返されます。 さて、コード全体を表示していないので、このコードがどのように実行されているのか分かりません。しかし、私はあなたがすべてのカレンダーアイテムをループしようとしていると推測しています。いずれにしても、複数の方法がありますが、 `descendant` XPathセレクタを使用すると、一度にたくさんのロットを取得*でき*ます。 ``` //div[@class='kal']//table//descendant::div[@class='cipars'] ``` これにより、 *すべて*のカレンダー項目(つまり1〜30)が返され*ます* 。 ただし、特定の行のすべてのアイテムを取得するには、その`tr`をクエリにスティックするだけです。 ``` //div[@class='kal']//table//tr[3]/descendant::div[@class='cipars'] ``` これは、2から8(カレンダー項目の2番目の行)を返します。 特定のものをターゲットにするには、ウェブサイトのソースコードを前提にしなければなりません。すべての "cipars" `div`は、クラスの`datums` ....と`td`祖先があるように見えるので、あなたの質問から "3"の値を得る: ``` //div[@class='kal']//table//tr[3]//td[@class='datums'][2]/div[@class='cipars'] ``` うまくいけば、少なくともこの問題を示すには十分です。 **編集** XPathの問題がありますが、別の問題もあります。 サイトは非常に奇妙に作成されています。カレンダーは奇妙な方法で読み込まれます。そのURLにヒットすると、カレンダーは、XML Webサービス(PHPで書かれた)を呼び出すいくつかのJavaScriptによって作成され、カレンダーに使用される完全な`table`が計算されます。 これはJavascript(クライアントサイドコード)であるため、HtmlAgilityPackはそれを実行しません。したがって、HtmlAgilityPackはテーブルを「参照」しません。したがって、それに対する照会は「見つからない」(null)として戻ってくる。 これを回避する方法:1)スクリプトを呼び出すツールを使用します。これにより、ブラウザをロードすることを意味します。これに使用するための素晴らしいツールはSeleniumと呼ばれています。これはおそらくサイト全体で使用されるすべてのスクリプティングが実際に呼び出されることを意味するため、全体的に優れたソリューションになるでしょう。それでもXPathを使用することができるので、クエリは変更されません。 2番目の方法は、ページ*と同じ* Webサービスにリクエストを送信することです。これは、基本的に、ページが取得しているの*と同じ* HTMLを取得し、HtmlAgilityPackで*その* HTMLを使用する*こと*です。どうすればいいの? C#を使用してデータをWebサービスに簡単にPOSTできます。使用の容易さのために、私はこのSOの質問からコードを盗んだ。これで、ページのリクエストと同じリクエストを送信し、同じHTMLを返すことができます。 だから、いくつかのPOSTデータを送信するには、我々は.....のようなメソッドを生成する ``` public static string SendPost(string url, string postData) { string webpageContent = string.Empty; byte[] byteArray = Encoding.UTF8.GetBytes(postData); HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(url); webRequest.Method = "POST"; webRequest.ContentType = "application/x-www-form-urlencoded"; webRequest.ContentLength = byteArray.Length; using (Stream webpageStream = webRequest.GetRequestStream()) { webpageStream.Write(byteArray, 0, byteArray.Length); } using (HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse()) { using (StreamReader reader = new StreamReader(webResponse.GetResponseStream())) { webpageContent = reader.ReadToEnd(); } } return webpageContent; } ``` 私たちはそう呼ぶことができます: ``` string responseBody = SendPost("http://lekcijas.va.lv/lekcijas_request.php", "nodala=IT&kurss=1&gads=2013&menesis=9&c_dala="); ``` どうしたの?さて、私たちが呼んでいる`php`ファイルは、ページのWebサービスであり、POSTデータもあります。私はそれがサービスに送信するどのようなデータが分かった方法は、(Chromeのデベロッパーコンソールを使用して)Javascriptをデバッグすることです**が** 、あなたはそれがURLにあるほとんど同じことだ気づくことがあります。それは意図的なようだ。 返される`responseBody`は、カレンダーの`table` **物理HTML** *だけ*です。 今、私たちは何をしていますか?純粋なHTMLを受け入れることができるので、これをHtmlAgilityPackに読み込みます。 ``` var document = new HtmlDocument(); document.LoadHtml(webpageContent); ``` さて、私たちは元のXPathを次のように守っています: ``` var node = document.DocumentNode.SelectSingleNode("//div[@class='kal']//table//tr[3]//td[@class='datums'][2]/div[@class='cipars']"); ``` 今、私たちはうまくいけば "3"であるべきものを印刷します: ``` Console.WriteLine(node.InnerText); ``` ローカルで実行している私の出力は確かです: **3** 。 しかし、これはあなたが持っている問題を解決するでしょうが、私はサイトの残りの部分がこのようなものであると仮定しています。これが当てはまる場合は、上記の手法を使用して回避することができますが、Seleniumのようなツールがこのような理由で作成されました。