Вывод HTML из PhantomJS и Google Chrome / Firefox отличается

Я долгое время отлаживал это, и это меня полностью сбило с толку. Мне нужно сохранить рекламу на моем компьютере для рабочего проекта. Вот пример рекламы, которую я получил от CNN.com:

http://ads.cnn.com/html.ng/site=cnn&cnn_pagetype=main&cnn_position=300x250_rgt&cnn_rollup=homepage&page.allowcompete=no¶ms.styles=fs&Params.User.UserID=5372450203c5be0a3c695e599b05d821&transactionID=13999976982075532128681984&tile=2897967999935&domId=6f4501668a5e9d58&kxid=&kxseg=»отн=

Когда я перехожу по этой ссылке в Google Chrome и Firefox, я вижу рекламу (если ссылка перестает работать, просто перейдите на CNN.com и возьмите URL-адрес iframe для одного из объявлений). Я разработал сценарий PhantomJS, который сохранит снимок экрана и HTML любой страницы. Он работает на любом веб-сайте, но, похоже, не работает с такой рекламой. Снимок экрана пустой, а HTML-код содержит пиксель отслеживания (прозрачный GIF размером 1 x 1, используемый для отслеживания рекламы). Я думал, что это даст мне то, что я вижу в своем обычном браузере.

Единственное, о чем я могу думать, это то, что вызовы AJAX каким-то образом портят PhantomJS, поэтому я жестко запрограммировал задержку, но получил те же результаты.

Вот самый простой фрагмент тестового кода, который воспроизводит мою проблему:

var fs = require('fs');
var page = require('webpage').create();
var url = phantom.args[0];

page.open(url, function (status) {
    if (status !== 'success') {
        console.log('Unable to load the address!');
        phantom.exit();
    }
    else {
        // Output Results Immediately
        var html = page.evaluate(function () {
            return document.getElementsByTagName('html')[0].innerHTML;
        });
        fs.write("HtmlBeforeTimeout.htm", html, 'w');
        page.render('RenderBeforeTimeout.png');

        // Output Results After Delay (for AJAX)
        window.setTimeout(function () {
            var html = page.evaluate(function () {
                return document.getElementsByTagName('html')[0].innerHTML;
            });
            fs.write("HtmlAfterTimeout.htm", html, 'w');
            page.render('RenderAfterTimeout.png');
            phantom.exit();
        }, 9000); // 9 Second Delay 
    }
});

Вы можете запустить этот код с помощью этой команды в своем терминале:

phantomjs getHtml.js 'http://www.google.com/'

Вышеупомянутая команда работает хорошо. Когда вы заменяете URL-адрес Google на URL-адрес объявления (например, в верхней части этого сообщения), это дает мне неожиданные результаты, которые я объяснил.

Большое спасибо за Вашу помощь! Это мой первый вопрос, который я когда-либо задавал здесь, потому что я почти всегда могу найти ответ, выполнив поиск по переполнению стека. Однако этот меня полностью поставил в тупик! :)

РЕДАКТИРОВАТЬ: я запускаю PhantomJS 1.9.7 на Ubuntu 14.04 (Trusty Tahr)

РЕДАКТИРОВАТЬ: Хорошо, я работаю над этим некоторое время, и я думаю, что это как-то связано с файлами cookie. Если я очищаю всю историю и просматриваю ссылку в браузере, она также оказывается пустой. Если я затем обновлю страницу, все будет нормально. Он также отображается нормально, если я открываю его в новой вкладке. Единственный раз, когда этого не происходит, - это когда я пытаюсь просмотреть его сразу после очистки файлов cookie.

РЕДАКТИРОВАТЬ: я дважды пытался загрузить ссылку в PhantomJS, не выходя (вручную запрашивая ее дважды в моем сценарии перед вызовом phantom.exit ()). Не работает. В документации PhantomJS сказано, что по умолчанию cookie-файл включен. Любые идеи? :)


person Jared Carter    schedule 13.05.2014    source источник
comment
Это настоящий тупик! Независимо от того, что я пытаюсь, я получаю только черное изображение 1x1. Интересно, связано ли это с тем, что некоторые объявления показываются во встроенном Flash-плеере? PhantomJS больше не поддерживает Flash, начиная с версии 1.5, что позволяет PhantomJS работать полностью без использования xvfb. Стоит попробовать SlimerJS, использующий движок Gecko, а не Webkit, который поддерживает Flash и имеет практически тот же API, что и PhantomJS.   -  person Cameron Tinker    schedule 15.05.2014


Ответы (1)


Вам следует попробовать использовать обратный вызов onLoadFinished вместо проверки статуса в page.open. Примерно так должно работать:

var fs = require('fs');
var page = require('webpage').create();
var url = phantom.args[0];

page.open(url);

page.onLoadFinished = function()
{
    // Output Results Immediately
    var html = page.evaluate(function () {
        return document.getElementsByTagName('html')[0].innerHTML;
    });
    fs.write("HtmlBeforeTimeout.htm", html, 'w');
    page.render('RenderBeforeTimeout.png');

    // Output Results After Delay (for AJAX)
    window.setTimeout(function () {
        var html = page.evaluate(function () {
            return document.getElementsByTagName('html')[0].innerHTML;
        });
        fs.write("HtmlAfterTimeout.htm", html, 'w');
        page.render('RenderAfterTimeout.png');
        phantom.exit();
    }, 9000); // 9 Second Delay 
};

У меня есть ответ, который просматривает все файлы в локальной папке и сохраняет изображения полученных страниц: Использование Phantom JS для преобразования всех файлов HTML в папке в PNG Тот же принцип применяется к удаленным страницам HTML.

Вот что я получил в результате:
До тайм-аута:
https://i.stack.imgur.com/GmsH9.jpg

После тайм-аута:
http://i.stack.imgur.com/mo6Ax.jpg < / а>

person Cameron Tinker    schedule 13.05.2014
comment
кажется разумным, тем более что все, что вы загружаете для начала, - это связка JS для рендеринга iframe позже, время здесь становится важным для того, что рендерится. - person dbrin; 13.05.2014
comment
Я просто перемещал исходный код OP в обратный вызов onLoadFinished. Задержка в 9 секунд такая же, как у OP. - person Cameron Tinker; 13.05.2014
comment
извините, комментарий был для OP. Я был с тобой согласен :) - person dbrin; 13.05.2014
comment
@dbrin Нет проблем! :) - person Cameron Tinker; 13.05.2014
comment
Спасибо за быстрый ответ! Я скопировал и вставил ваш код в новый файл и протестировал его. Результат был точно таким же, как у меня (он работал со ссылкой Google, но не работал с рекламой от CNN). У тебя есть другие идеи? :) - person Jared Carter; 13.05.2014
comment
Я добавил результат моего прогона. CNN довольно длинный, так что я извиняюсь за длинный пост, ха-ха. Я могу отредактировать ответ, указав ссылку на изображения, чтобы уменьшить размер ответа. - person Cameron Tinker; 13.05.2014
comment
Я здесь тоже ничего не вижу (видите, что я там делал?). Откуда вы взяли ссылку на рекламу? Я предполагаю, что вы не отправляете все необходимые HTTP-заголовки / данные POST на URL-адрес объявления. - person Cameron Tinker; 13.05.2014
comment
Ха-ха! Ссылка находится в iframe в правой части домашней страницы CNN.com (она не отображается на снимке экрана, но появляется, когда вы посещаете ее в браузере). В файле .htm, созданном PhantomJS, найдите Объявление и посмотрите на несколько строк над ним. Есть тег iframe со ссылкой в ​​атрибуте src. - person Jared Carter; 13.05.2014