Ver fuente generada (después de AJAX / JavaScript) en C #

¿Hay una manera de ver la fuente generada de una página web (el código después de que todas las llamadas AJAX y las manipulaciones de DOM de JavaScript hayan tenido lugar) desde una aplicación de C # sin abrir un navegador desde el código?

Viendo la página inicial usando unSolicitud web oWebClient el objeto funciona bien, pero si la página hace un uso extensivo de JavaScript para alterar el DOM en la carga de la página, entonces no proporcionan una imagen precisa de la página.

He intentado usarSelenio yWatin Los marcos de prueba de la interfaz de usuario funcionan perfectamente, suministrando la fuente generada tal como aparece una vez que se completan todas las manipulaciones de JavaScript. Desafortunadamente, lo hacen abriendo un navegador web real, que es muy lento. He implementado un servidor de selenio que descarga este trabajo a otra máquina, pero todavía hay un retraso sustancial.

¿Existe una biblioteca .Net que cargará y analizará una página (como un navegador) y escupirá el código generado? Claramente, Google y Yahoo no están abriendo los navegadores para cada página que quieren arañar (por supuesto que pueden tener más recursos que yo ...).

¿Existe tal biblioteca o estoy fuera de suerte a menos que esté dispuesto a analizar el código fuente de un navegador de código abierto?

SOLUCIÓN

Bueno, gracias a todos por su ayuda. Tengo una solución de trabajo que es 10 veces más rápida que Selenium. ¡Cortejar!

Gracias a estoantiguo artículo de beansoftware Pude usar el control System.Windows.Forms.WebBrowser para descargar la página y analizarla, luego darles la fuente generada. A pesar de que el control está en Windows.Forms, aún puedes ejecutarlo desde Asp.Net (que es lo que estoy haciendo), solo recuerda agregar System.Window.Forms a las referencias de tu proyecto.

Hay dos cosas notables sobre el código. Primero, el control WebBrowser se llama en un nuevo hilo. Esto se debe a que debe ejecutarse en unaapartamento de una sola rosca.

Segundo, la variable GeneratedSource se establece en dos lugares. Esto no se debe a una decisión de diseño inteligente :) Todavía estoy trabajando en ello y actualizaré esta respuesta cuando termine. wb_DocumentCompleted () se llama varias veces. Primero cuando se descarga el HTML inicial, y luego nuevamente cuando se completa la primera ronda de JavaScript. Desafortunadamente, el sitio que estoy raspando tiene 3 etapas de carga diferentes. 1) Cargar HTML inicial 2) Hacer la primera ronda de manipulación de DOM de JavaScript 3) hacer una pausa de medio segundo y luego hacer una segunda ronda de manipulación de JS DOM.

Por alguna razón, la segunda ronda no es causada por la función wb_DocumentCompleted (), pero siempre se detecta cuando wb.ReadyState == Complete. Entonces, ¿por qué no eliminarlo de wb_DocumentCompleted ()? Todavía no estoy seguro de por qué no está atrapado allí y ahí es donde el artículo del software de cuentas recomendó ponerlo. Voy a seguir investigándolo. Solo quería publicar este código para que cualquiera que esté interesado pueda usarlo. ¡Disfrutar!

using System.Threading;
using System.Windows.Forms;

public class WebProcessor
{
    private string GeneratedSource{ get; set; }
    private string URL { get; set; }

    public string GetGeneratedHTML(string url)
    {
        URL = url;

        Thread t = new Thread(new ThreadStart(WebBrowserThread));
        t.SetApartmentState(ApartmentState.STA);
        t.Start();
        t.Join();

        return GeneratedSource;
    }

    private void WebBrowserThread()
    {
        WebBrowser wb = new WebBrowser();
        wb.Navigate(URL);

        wb.DocumentCompleted += 
            new WebBrowserDocumentCompletedEventHandler(
                wb_DocumentCompleted);

        while (wb.ReadyState != WebBrowserReadyState.Complete)
            Application.DoEvents();

        //Added this line, because the final HTML takes a while to show up
        GeneratedSource= wb.Document.Body.InnerHtml;

        wb.Dispose();
    }

    private void wb_DocumentCompleted(object sender, 
        WebBrowserDocumentCompletedEventArgs e)
    {
        WebBrowser wb = (WebBrowser)sender;
        GeneratedSource= wb.Document.Body.InnerHtml;
    }
}

Respuestas a la pregunta(3)

Su respuesta a la pregunta