HtmlAgilityPackを使用して非同期呼び出しを行う方法

c# html-agility-pack

質問

私はここで利用可能なid table-matchesテーブルを取得しようとしています。問題は、テーブルがajaxを使用してロードされているため、ページをダウンロードするときに完全なhtmlコードが取得されないことです。

string url = "http://www.oddsportal.com/matches/soccer/20180701/";

using (HttpClient client = new HttpClient())
{
    using (HttpResponseMessage response = client.GetAsync(url).Result)
    {
        using (HttpContent content = response.Content)
        {
            string result = content.ReadAsStringAsync().Result;
        }
    }
}

返されるhtmlにはテーブルが含まれていないので、ライブラリの問題があるかどうかを確認しようとしましたが、 Chrome (特にDevコンソールF12で)javascriptをオフにしてブラウザで同じ結果を得ました。

Foxはこの問題を解決しましたが、特にWebBrowserを使用しています。

webBrowser.Navigate("oddsportal.com/matches/soccer/20140221/"); 
HtmlElementCollection elements = webBrowser.Document.GetElementsByTagName("table");

しかし、私は非同期呼び出しを行っている完全なhtmlかどうかを尋ねたい、誰かが同様の問題に遭遇しましたか?

あなたは解決策を共有できますか?ありがとう。

受け入れられた回答

このページの主な問題は、 table-matches内のコンテンツがajax経由で読み込まれることです。また、 HttpClientHtmlAgilityPackもajaxが実行されるのを待つことができません。したがって、あなたは別のアプローチが必要です。

アプローチ1 - PuppeteerSharpのようなヘッドレスブラウザを使用する

using PuppeteerSharp;
using System;
using System.Threading.Tasks;

namespace PuppeteerSharpDemo
{
    class Program
    {
        private static String url = "http://www.oddsportal.com/matches/soccer/20180701/";

        static void Main(string[] args)
        {
            var htmlAsTask = LoadAndWaitForSelector(url, "#table-matches .table-main");
            htmlAsTask.Wait();
            Console.WriteLine(htmlAsTask.Result);

            Console.ReadKey();
        }

        public static async Task<string> LoadAndWaitForSelector(String url, String selector)
        {
            var browser = await Puppeteer.LaunchAsync(new LaunchOptions
            {
                Headless = true,
                ExecutablePath = @"c:\Program Files (x86)\Google\Chrome\Application\chrome.exe"
            });
            using (Page page = await browser.NewPageAsync())
            {
                await page.GoToAsync(url);
                await page.WaitForSelectorAsync(selector);
                return await page.GetContentAsync();
            }
        }
    }
}

清潔さを目的としてここに出力を掲載しまし 。そして、あなたがhtmlAgilityPackでそれ解析することができるhtmlコンテンツを取得したら

アプローチ#2 - 純粋なSelenium WebDriverを使用する

using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using OpenQA.Selenium.Support.UI;
using System;

namespace SeleniumDemo
{
    class Program
    {
        private static IWebDriver webDriver;
        private static TimeSpan defaultWait = TimeSpan.FromSeconds(10);
        private static String targetUrl = "http://www.oddsportal.com/matches/soccer/20180701/";
        private static String driversDir = @"../../Drivers/";

        static void Main(string[] args)
        {
            webDriver = new ChromeDriver(driversDir);
            webDriver.Navigate().GoToUrl(targetUrl);
            IWebElement table = webDriver.FindElement(By.Id("table-matches"));
            var innerHtml = table.GetAttribute("innerHTML");
        }

        #region (!) I didn't even use this, but it can be useful (!)
        public static IWebElement FindElement(By by)
        {
            try
            {
                WaitForAjax();
                var wait = new WebDriverWait(webDriver, defaultWait);
                return wait.Until(driver => driver.FindElement(by));
            }
            catch
            {
                return null;
            }
        }

        public static void WaitForAjax()
        {
            var wait = new WebDriverWait(webDriver, defaultWait);
            wait.Until(d => (bool)(d as IJavaScriptExecutor).ExecuteScript("return jQuery.active == 0"));
        }
        #endregion
    }
}

アプローチ3 - ajaxリクエストをシミュレートする

Fiddlerまたはブラウザのプロファイラ(F12)を使用してページの読み込みを分析すると、すべてのデータに次の2つの要求があることがわかります。

フィドラーがオッズ・ポール・スクレイピングを要求するしたがって、 HttpClientを使用してそれらを直接実行しようとすることができます 。しかし、この場合、認証ヘッダーやHTTPリクエストごとに何か他のものを追跡する必要があるかもしれません。



ライセンスを受けた: CC-BY-SA with attribution
所属していない Stack Overflow
このKBは合法ですか? はい、理由を学ぶ
ライセンスを受けた: CC-BY-SA with attribution
所属していない Stack Overflow
このKBは合法ですか? はい、理由を学ぶ