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

Принимая надежные скриншоты веб-сайтов? Phantomjs и Casperjs возвращают пустые снимки экрана на некоторых веб-сайтах

Откройте веб-страницу и сделайте снимок экрана.

Использование ТОЛЬКО phantomjs: (это простой script, на самом деле это пример script, используемый в их документах. http://phantomjs.org/screen-capture.html

var page = require('webpage').create();
page.open('http://github.com/', function() {
  page.render('github.png');
  phantom.exit();
});

Проблема в том, что для некоторых веб-сайтов (например, github) достаточно смешно, так или иначе обнаруживающих и не обслуживающих phantomjs, и ничего не отображается. Результат github.png - пустой белый файл png.

Замените github на "google.com", и вы получите хороший (правильный) снимок экрана, как это предусмотрено.

Сначала я подумал, что это проблема Phantomjs, поэтому я попытался запустить ее через Casperjs с помощью:

casper.start('http://www.github.com/', function() {
    this.captureSelector('github.png', 'body');
});

casper.run();

Но я получаю такое же поведение, как с Phantomjs.

Итак, я понял, что это скорее всего проблема с пользовательским агентом. Как и в: Гитуб вынюхивает Фантомы и решает не показывать страницу. Поэтому я установил пользовательский агент, как показано ниже, но это все еще не сработало.

var page = require('webpage').create();
page.settings.userAgent = 'Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2049.0 Safari/537.36';
page.open('http://github.com/', function() {
  page.render('github.png');
  phantom.exit();
});

Итак, я попытался разобрать страницу, и, видимо, некоторые сайты (опять же, как и github), похоже, ничего не посылают по проводам.

Используя casperjs, я попытался напечатать заголовок. И для google.com я вернулся Google, но для github.com я вернулся bupkis. Пример кода:

var casper = require('casper').create();

casper.start('http://github.com/', function() {
    this.echo(this.getTitle());
});

casper.run();  

То же, что и выше, также дает тот же результат в чисто фантомах.

Update:

Может ли это быть проблемой сроков? Является ли github просто супер медленным? Я сомневаюсь, но давайте все равно протестируем.

var page = require('webpage').create();
page.open('http://github.com', function (status) {
    /* irrelevant */
   window.setTimeout(function () {
            page.render('github.png');
            phantom.exit();
        }, 3000);
});

И результат по-прежнему бупкис. Так что нет, это не проблема времени.

  • Как некоторые сайты вроде gantub блокируют phantomjs?
  • Как мы можем надежно снимать скриншоты ВСЕХ веб-страниц? Требуется быть быстрым и безголовым.
4b9b3361

Ответ 1

После подпрыгивания этого в течение некоторого времени я смог сузить проблему. По-видимому, PhantomJS использует по умолчанию ssl sslv3, из-за чего github отказывается от соединения из-за плохого ssl handshake

phantomjs --debug=true github.js

Показывает вывод:

. . .
2014-10-22T19:48:31 [DEBUG] WebPage - updateLoadingProgress: 10 
2014-10-22T19:48:32 [DEBUG] Network - Resource request error: 6 ( "SSL handshake failed" ) URL: "https://github.com/" 
2014-10-22T19:48:32 [DEBUG] WebPage - updateLoadingProgress: 100 

Итак, из этого можно сделать вывод, что экран не был взят, потому что github отказывался от связи. Отлично, что имеет смысл. Поэтому давайте установить флаг SSL в --ssl-protocol=any и также игнорировать ssl-ошибки с помощью --ignore-ssl-errors=true

phantomjs --ignore-ssl-errors=true --ssl-protocol=any --debug=true github.js

Большой успех! Снимок экрана теперь отображается и сохраняется должным образом, но отладчик показывает нам TypeError:

TypeError: 'undefined' is not a function (evaluating 'Array.prototype.forEach.call.bind(Array.prototype.forEach)')

  https://assets-cdn.github.com/assets/frameworks-dabc650f8a51dffd1d4376a3522cbda5536e4807e01d2a86ff7e60d8d6ee3029.js:29
  https://assets-cdn.github.com/assets/frameworks-dabc650f8a51dffd1d4376a3522cbda5536e4807e01d2a86ff7e60d8d6ee3029.js:29
2014-10-22T19:52:32 [DEBUG] WebPage - updateLoadingProgress: 72 
2014-10-22T19:52:32 [DEBUG] WebPage - updateLoadingProgress: 88 
ReferenceError: Can't find variable: $

  https://assets-cdn.github.com/assets/github-fa2f009761e3bc4750ed00845b9717b09646361cbbc3fa473ad64de9ca6ccf5b.js:1
  https://assets-cdn.github.com/assets/github-fa2f009761e3bc4750ed00845b9717b09646361cbbc3fa473ad64de9ca6ccf5b.js:1

Я проверил домашнюю страницу github вручную, чтобы увидеть, существует ли TypeError, и это НЕ.

Моя следующая догадка заключается в том, что активы не загружаются достаточно быстро.. Phantomjs быстрее, чем ускоряющая пуля!

Итак, попытайтесь искусственно замедлить его и посмотреть, можем ли мы избавиться от этого TypeError...

var page = require('webpage').create();
page.settings.userAgent = 'Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2049.0 Safari/537.36';
page.open('http://github.com', function (status) {
   window.setTimeout(function () {
            page.render('github.png');
            phantom.exit();
        }, 3000);
});

Это не сработало... После более пристального осмотра изображения - ясно, что некоторые элементы отсутствуют. Главным образом некоторые значки и логотип.

Успех? Частично потому, что мы сейчас, по крайней мере, снимаем экран раньше, мы ничего не получали.

Работа выполнена? Не совсем. Необходимо определить, что вызывает это TypeError, потому что это мешает некоторым активам загружать и искажать изображение.

Дополнительно

Попытка воссоздать с помощью CasperJS --debug очень уродлива и сложна в сравнении с PhantomJS:

casper.start();
casper.userAgent('Mozilla/5.0 (Macintosh; Intel Mac OS X)');
casper.thenOpen('https://www.github.com/', function() {
    this.captureSelector('github.png', 'body');
});

casper.run();

Приставки:

casperjs test --ssl-protocol=any --debug=true github.js

Далее на изображении отсутствуют одинаковые значки, но также визуально искажены. Поскольку CasperJs полагается на Phantomjs, я не вижу смысла использовать его для этой конкретной задачи.

Если вы хотите добавить к моему ответу, поделитесь своими результатами. Очень заинтересован в безупречном решении PhantomJS

Обновление # 1: Удаление TypeError

@ArtjomB указывает, что Phantomjs не поддерживает js bind в текущей версии этого обновления (1.9.7). По этой причине он объясняет: ArtjomB: PhantomJs Bind Issue Answer

TypeError: 'undefined' не является функцией, ссылающейся на bind, потому что PhantomJS 1.x не поддерживает его. PhantomJS 1.x использует старую вилку QtWebkit, который сопоставим с Chrome 13 или Safari 5. Новее PhantomJS 2 будет использовать более новый движок, который будет поддерживать привязку. На данный момент вам нужно добавить прокладку внутри страницы. inInitialized обработчик событий:

Хорошо, так что следующий код позаботится о нашем TypeError сверху. (Но не полностью функциональный, см. Ниже для деталей)

var page = require('webpage').create();
page.settings.userAgent = 'Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2049.0 Safari/537.36';
page.open('http://github.com', function (status) {
   window.setTimeout(function () {
            page.render('github.png');
            phantom.exit();
        }, 5000);
});
page.onInitialized = function(){
    page.evaluate(function(){
        var isFunction = function(o) {
          return typeof o == 'function';
        };

        var bind,
          slice = [].slice,
          proto = Function.prototype,
          featureMap;

        featureMap = {
          'function-bind': 'bind'
        };

        function has(feature) {
          var prop = featureMap[feature];
          return isFunction(proto[prop]);
        }

        // check for missing features
        if (!has('function-bind')) {
          // adapted from Mozilla Developer Network example at
          // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/bind
          bind = function bind(obj) {
            var args = slice.call(arguments, 1),
              self = this,
              nop = function() {
              },
              bound = function() {
                return self.apply(this instanceof nop ? this : (obj || {}), args.concat(slice.call(arguments)));
              };
            nop.prototype = this.prototype || {}; // Firefox cries sometimes if prototype is undefined
            bound.prototype = new nop();
            return bound;
          };
          proto.bind = bind;
        }
    });
}

Теперь приведенный выше код даст нам скриншот того же самого, что и мы до этого. И отладка не покажет TypeError, так что с поверхности все работает. Прогресс был достигнут.

К сожалению, все значки изображений [логотип и т.д.] по-прежнему не загружаются правильно. Мы видим, что какой-то значок 3W не уверен, откуда это.

Спасибо за помощь @ArtjomB

enter image description here