Comment faire des appels asynchrones en utilisant HtmlAgilityPack?

c# html-agility-pack

Question

J'essaie d'obtenir la table avec les correspondances id table-matches disponibles ici . Le problème est que la table est chargée avec ajax , je ne reçois donc pas le code html complet lorsque je télécharge la page:

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;
        }
    }
}

le html renvoyé ne contient aucune table, j'ai donc essayé de voir s'il y avait un problème de bibliothèque, en fait j'ai installé Chrome (plus précisément sur la console de développement F12), javascript désactivé et le même résultat sur le navigateur.

Fox a résolu ce problème, mais j’ai pensé utiliser un WebBrowser , en particulier:

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

mais je veux demander si je peux charger aussi le plein html faisant des appels asynchrones, quelqu'un a rencontré un problème similaire?

Pourriez-vous s'il vous plaît partager une solution? Merci.

Réponse acceptée

Le problème principal avec cette page est que le contenu à l'intérieur des correspondances de table-matches est chargé via ajax. Et ni HttpClient ni HtmlAgilityPack incapables d'attendre l'exécution de ajax. Par conséquent, vous avez besoin d'une approche différente.

Approche n ° 1 - Utilisez n’importe quel navigateur sans navigateur comme 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();
            }
        }
    }
}

Dans le but de la propreté, j'ai posté la sortie ici ici . Et une fois que vous obtenez du contenu HTML, vous pouvez l’ analyser avec HtmlAgilityPack .

Approche n ° 2 - Utiliser du Selenium WebDriver pur

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
    }
}

Approche n ° 3 - Simuler des requêtes ajax

Si vous analysez le chargement de la page à l'aide de Fiddler ou du profileur du navigateur (F12), vous pouvez voir que toutes les données arrivent avec ces deux demandes:

un violoniste demande le raclage de son port oddsportal Vous pouvez donc essayer de les exécuter directement à l’aide de HttpClient . Mais dans ce cas, vous devrez peut-être suivre les en-têtes d'autorisation et peut-être autre chose avec chaque demande HTTP.



Related

Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow