简体   繁体   中英

Get HtmlDocument after javascript manipulations

In C#, using the System.Windows.Forms.HtmlDocument class (or another class that allows DOM parsing), is it possible to wait until a webpage finishes its javascript manipulations of the HTML before retrieving that HTML? Certain sites add innerhtml to pages through javascript, but those changes do not show up when I parse the HtmlElements of the HtmlDocument.

One possibility would be to update the HtmlDocument of the page after a second. Does anybody know how to do this?

Someone revived this question by posting what I think is an incorrect answer. So, here are my thoughts to address it.

Non-deterministically, it's possible to get close to finding out if the page has finished its AJAX stuff. However, it completely depends on the logic of that particular page: some pages are perpetually dynamic.

To approach this, one can handle DocumentCompleted event first, then asynchronously poll the WebBrowser.IsBusy property and monitor the current HTML snapshot of the page for changes, like below.

The complete sample can be found here .

// get the root element
var documentElement = this.webBrowser.Document.GetElementsByTagName("html")[0];

// poll the current HTML for changes asynchronosly
var html = documentElement.OuterHtml;
while (true)
{
    // wait asynchronously, this will throw if cancellation requested
    await Task.Delay(500, token); 

    // continue polling if the WebBrowser is still busy
    if (this.webBrowser.IsBusy)
        continue; 

    var htmlNow = documentElement.OuterHtml;
    if (html == htmlNow)
        break; // no changes detected, end the poll loop

    html = htmlNow;
}

In general aswer is "no" - unless script on the page notifies your code in some way you have to simply wait some time and grab HTML. Waiting a second after document ready notification likley will cover most sites (ie jQuery's $(code) cases).

You need to give the application a second to process the Java. Simply halting the current thread will delay the java processing as well so your doc will still come up outdated.

WebBrowserDocumentCompletedEventArgs cachedLoadArgs;

private void TimerDone(object sender, EventArgs e)
{
    ((Timer)sender).Stop();
    respondToPageLoaded(cachedLoadArgs);
}

void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
    cachedLoadArgs = e;

    System.Windows.Forms.Timer timer = new Timer();

    int interval = 1000;

    timer.Interval = interval;
    timer.Tick += new EventHandler(TimerDone);
    timer.Start();
}

I made with WEbBrowser take a look at my class:

public class MYCLASSProduct: IProduct
{
    public string Name { get; set; }
    public double Price { get; set; }
    public string Url { get; set; }

    private WebBrowser _WebBrowser;
    private AutoResetEvent _lock;

    public void Load(string url)
    {
        _lock = new AutoResetEvent(false);
        this.Url = url;

        browserInitializeBecauseJavascriptLoadThePage();
    }

    private void browserInitializeBecauseJavascriptLoadThePage()
    {
        _WebBrowser = new WebBrowser();
        _WebBrowser.DocumentCompleted += webBrowser_DocumentCompleted;
        _WebBrowser.Dock = DockStyle.Fill;
        _WebBrowser.Name = "webBrowser";
        _WebBrowser.ScrollBarsEnabled = false;
        _WebBrowser.TabIndex = 0;
        _WebBrowser.Navigate(Url);

        Form form = new Form();
        form.Hide();
        form.Controls.Add(_WebBrowser);

        Application.Run(form);
        _lock.WaitOne();
    }

    private void webBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
    {
        HtmlAgilityPack.HtmlDocument hDocument = new HtmlAgilityPack.HtmlDocument();
        hDocument.LoadHtml(_WebBrowser.Document.Body.OuterHtml);
        this.Price = Convert.ToDouble(hDocument.DocumentNode.SelectNodes("//td[@class='ask']").FirstOrDefault().InnerText.Trim());
        _WebBrowser.FindForm().Close();
        _lock.Set();

    }

if your trying to do this in a console application, you need to put this tag above your main, because Windows needs to communicate with COM Components:

[STAThread]
    static void Main(string[] args)

I did not like this solution, But I think that is no one better!

使用“WebBrowser.Navigated”事件怎么样?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM