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.
Le principal problème avec cette page est que le contenu à l'intérieur des correspondances de table-matches
est chargé via ajax. Et ni HttpClient
ni HtmlAgilityPack
ne HtmlAgilityPack
pas attendre que ajax soit exécuté. Par conséquent, vous avez besoin d'une approche différente.
Approche n ° 1 - Utilisez n'importe quel navigateur sans tête 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 un souci de propreté, j'ai publié la sortie ici ici . Et une fois que vous obtenez du contenu html, vous pouvez l' analyser avec HtmlAgilityPack .
Approche n ° 2 - Utilisez Pure Selenium WebDriver . Peut être lancé en mode sans tête .
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 les demandes ajax
Si vous analysez le chargement de la page à l'aide de Fiddler ou du profileur de navigateur (F12), vous pouvez voir que toutes les données viennent avec ces deux demandes:
Vous pouvez donc essayer de les exécuter directement en utilisant 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.