Ich versuche, die Tabelle mit ID- table-matches
hier zu bekommen . Das Problem ist, dass die Tabelle mit ajax
geladen wird, so dass ich nicht den vollständigen html
Code bekomme, wenn ich die Seite herunterlade:
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;
}
}
}
das zurückgegebene html
enthält keine Tabelle, also habe ich versucht zu sehen, ob es ein Problem mit der Bibliothek gibt, tatsächlich habe ich in Chrome
(speziell auf der Dev-Konsole F12) Javascript deaktiviert und das gleiche Ergebnis im Browser.
Fox behebt dieses Problem, ich benutze einen WebBrowser
, insbesondere:
webBrowser.Navigate("oddsportal.com/matches/soccer/20140221/");
HtmlElementCollection elements = webBrowser.Document.GetElementsByTagName("table");
aber ich möchte fragen, ob ich auch die volle html
asynchronus Anrufe laden kann, hat jemand ein ähnliches Problem festgestellt?
Könnten Sie bitte eine Lösung teilen? Vielen Dank.
Das Hauptproblem bei dieser Seite ist, dass Inhalte in table-matches
über Ajax geladen werden. Und weder HttpClient
noch HtmlAgilityPack
nicht auf die Ausführung von HtmlAgilityPack
warten. Deshalb brauchen Sie einen anderen Ansatz.
Ansatz 1 - Verwenden Sie einen beliebigen Browser ohne Kopf wie 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();
}
}
}
}
Zweck der Sauberkeit habe ich hier Ausgabe geschrieben hier . Und sobald Sie HTML-Inhalte erhalten, können Sie diese mit HtmlAgilityPack analysieren .
Ansatz 2 - Verwenden Sie reinen Selenium WebDriver . Kann im kopflosen Modus gestartet werden .
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
}
}
Ansatz 3 - Simulieren Sie Ajax-Anforderungen
Wenn Sie das Laden der Seite mit Fiddler oder dem Browser-Profiler (F12) analysieren, können Sie feststellen, dass alle Daten mit diesen beiden Anforderungen einhergehen:
Sie können also versuchen, sie direkt mit HttpClient auszuführen. In diesem Fall müssen Sie jedoch möglicherweise die Autorisierungsheader und möglicherweise etwas anderes bei jeder HTTP-Anforderung nachverfolgen.