Навигация по ссылкам на хэшбэнг с помощью javascript (phantomjs) - PullRequest
9 голосов
/ 20 июня 2011

Я пытаюсь загрузить HTML-код веб-сайта, который почти полностью генерируется JavaScript. Итак, мне нужно смоделировать доступ через браузер, и я играл с PhantomJS . Проблема в том, что сайт использует URL-адреса hashbang, и я не могу заставить PhantomJS обработать hashbang - он просто продолжает вызывать домашнюю страницу.

Сайт - http://www.regulations.gov. По умолчанию вы попадаете на #! Home. Я попытался использовать следующий код (из здесь ), чтобы попытаться обработать различные hashbangs.

if (phantom.state.length === 0) {
     if (phantom.args.length === 0) {
        console.log('Usage: loadreg_1.js <some hash>');
        phantom.exit();
     }
     var address = 'http://www.regulations.gov/';
     console.log(address);
     phantom.state = Date.now().toString();
     phantom.open(address);

} else {
     var hash = phantom.args[0];
     document.location = hash;
     console.log(document.location.hash);
     var elapsed = Date.now() - new Date().setTime(phantom.state);
     if (phantom.loadStatus === 'success') {
             if (!first_time) {
                     var first_time = true;
                     if (!document.addEventListener) {
                             console.log('Not SUPPORTED!');
                     }
                     phantom.render('result.png');
                     var markup = document.documentElement.innerHTML;
                     console.log(markup);
                     phantom.exit();
             }
     } else {
             console.log('FAIL to load the address');
             phantom.exit();
     }
}

Этот код производит правильный хэш-бэнг (например, я могу установить хэш '#! Contactus'), но он не генерирует динамически никакой другой HTML-код - просто страница по умолчанию. Тем не менее, он правильно выводит, когда я звоню document.location.hash.

Я также пытался установить начальный адрес для hashbang, но затем скрипт просто зависает и ничего не делает. Например, если я установил URL-адрес на http://www.regulations.gov/#!searchResults;rpp=10;po=0, сценарий просто зависает после печати адреса на терминал, и ничего не происходит.

1 Ответ

5 голосов
/ 24 июня 2011

Проблема в том, что содержимое страницы загружается асинхронно, но вы ожидаете, что оно станет доступным, как только страница будет загружена.

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

Хитрость в том, чтобы выяснить, что искатьдля - вам нужно что-то, что не будет присутствовать на странице, пока желаемый контент не будет загружен.В этом случае самый простой вариант, который я нашел для страниц верхнего уровня, - это вручную ввести теги H1, которые вы ожидаете увидеть на каждой странице, и ввести их в хэш:

var titleMap = {
    '#!contactUs': 'Contact Us',
    '#!aboutUs': 'About Us'
    // etc for the other pages
};

Затем в блоке успеха,Вы можете установить повторяющееся время ожидания для поиска нужного заголовка в теге h1.Когда он появляется, вы знаете, что можете отобразить страницу:

if (phantom.loadStatus === 'success') {
    // set a recurring timeout for 300 milliseconds
    var timeoutId = window.setInterval(function () {
        // check for title element you expect to see
        var h1s = document.querySelectorAll('h1');
        if (h1s) {
            // h1s is a node list, not an array, hence the
            // weird syntax here
            Array.prototype.forEach.call(h1s, function(h1) {
                if (h1.textContent.trim() === titleMap[hash]) {
                    // we found it!
                    console.log('Found H1: ' + h1.textContent.trim());
                    phantom.render('result.png');
                    console.log("Rendered image.");
                    // stop the cycle
                    window.clearInterval(timeoutId);
                    phantom.exit();
                }
            });
            console.log('Found H1 tags, but not ' + titleMap[hash]);
        }
        console.log('No H1 tags found.');
    }, 300);
}

Приведенный выше код работает для меня.Но это не сработает, если вам нужно будет обработать результаты поиска - вам нужно будет найти элемент или фрагмент текста, который вы можете искать, не зная заголовка заранее.

Редактировать : Кроме того, похоже, что новейшая версия PhantomJS теперь вызывает событие onResourceReceived при получении новых данных.Я не рассматривал это, но вы можете привязать слушателя к этому событию, чтобы достичь того же эффекта.

...