Подтвердить что ты не робот

Просмотр сгенерированного источника (после AJAX/JavaScript) в С#

Есть ли способ просмотреть сгенерированный источник веб-страницы (код после всех вызовов AJAX и манипуляций с DOM-документами JavaScript) из приложения С#, не открывая браузер из кода?

Просмотр начальной страницы с помощью WebRequest или WebClient объект работает нормально, но если на странице широко используется JavaScript для изменения DOM при загрузке страницы, то они не дают точного изображения страницы.

Я попытался использовать Selenium и Watin Framework UI, и они отлично работают, поставляя сгенерированный источник, поскольку он появляется после завершения всех операций JavaScript. К сожалению, они делают это, открывая фактический веб-браузер, который очень медленный. Я реализовал сервер selenium, который разгружает эту работу на другую машину, но есть существенная задержка.

Есть ли библиотека .Net, которая будет загружать и анализировать страницу (например, браузер) и выплевывать сгенерированный код? Очевидно, что Google и Yahoo не открывают браузеры для каждой страницы, которую они хотят использовать (конечно, у них может быть больше ресурсов, чем у меня...).

Есть ли такая библиотека или мне повезло, если я не хочу анализировать исходный код браузера с открытым исходным кодом?

Решение

Хорошо, спасибо вам всем за помощь. У меня есть рабочее решение, которое примерно в 10 раз быстрее, чем Selenium. Woo!

Благодаря этой старой статье из beansoftware я смог использовать элемент управления System.Windows.Forms.WebBrowser для загрузки страницы и ее анализа, затем дать em сгенерированный источник. Несмотря на то, что элемент управления находится в Windows.Forms, вы все равно можете запустить его из Asp.Net(это то, что я делаю), просто не забудьте добавить System.Window.Forms в ваши ссылки на проект.

В коде есть две заметные вещи. Во-первых, элемент управления WebBrowser вызывается в новом потоке. Это связано с тем, что он должен работать на однопоточной квартире.

Во-вторых, переменная GeneratedSource устанавливается в двух местах. Это не из-за разумного дизайнерского решения:) Я все еще работаю над этим и обновляю этот ответ, когда закончите. wb_DocumentCompleted() вызывается несколько раз. Сначала, когда загружается исходный HTML, затем снова, когда заканчивается первый раунд JavaScript. К сожалению, сайт, который я соскабливаю, имеет 3 разных этапа загрузки. 1) Загрузите исходный HTML 2) Сделайте первый раунд манипуляции с DOM JavaScript 3) приостановите на полсекунды, затем выполните второй раунд манипуляций с JS DOM.

По какой-то причине второй раунд не является причиной функции wb_DocumentCompleted(), но он всегда пойман, когда wb.ReadyState == Complete. Так почему бы не удалить его из wb_DocumentCompleted()? Я все еще не уверен, почему он не пойман там и что там, где рекомендована статья в beadsoftware. Я буду продолжать изучать его. Я просто хотел опубликовать этот код, чтобы любой, кто его заинтересовал, мог его использовать. Наслаждайтесь!

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

Ответ 1

возможно, используя экземпляр браузера (в вашем случае: т.е. управление). вы можете легко использовать в своем приложении и открыть страницу. затем элемент управления загрузит его и обработает любой javascript. как только это будет сделано, вы сможете получить доступ к элементу управления dom и получить "интерпретируемый" код.

Ответ 2

Лучший способ - PhantomJs. Это здорово. (образец этого статьи).

Мое решение выглядит так:

var page = require('webpage').create();

page.open("https://sample.com", function(){
    page.evaluate(function(){
        var i = 0,
        oJson = jsonData,
        sKey;
        localStorage.clear();

        for (; sKey = Object.keys(oJson)[i]; i++) {
            localStorage.setItem(sKey,oJson[sKey])
        }
    });

    page.open("https://sample.com", function(){
        setTimeout(function(){
         page.render("screenshoot.png") 
            // Where you want to save it    
           console.log(page.content); //page source
            // You can access its content using jQuery
            var fbcomments = page.evaluate(function(){
                return $("body").contents().find(".content") 
            }) 
            phantom.exit();
        },10000)
    });     
});

Ответ 3

Теоретически да, но в настоящее время нет.

Я не думаю, что сейчас есть продукт или проект OSS, который делает это. Такой продукт должен иметь собственный интерпретатор javascript и иметь возможность точно эмулировать среду выполнения и причуды каждого поддерживаемого браузера.

Учитывая, что вам нужно что-то, что точно эмулирует среду сервера + браузер, чтобы создать окончательный код страницы, в конечном счете, я думаю, что использование экземпляра браузера - лучший способ точно сгенерировать страницу в ее конечном состоянии, Это особенно верно, если учесть, что после загрузки страницы источники страниц могут со временем меняться в браузере с AJAX/javascript.