В PhantomJS я не могу включить jQuery, а без jQuery я не могу отправлять данные формы

У меня проблемы с запуском jQuery в PhantomJS. Я нашел этот ответ, в котором говорится о том, что нет переменная доступна внутри функции оценки, но вопрос касается модуля узла, и в моем примере я вызываю только console.log внутри функции оценки. Я также разместил этот вопрос на GitHub.

Ранее для некоторых страниц следующий код evaluate не выполнялся. Теперь, когда @b1f56gd4 оказал некоторую помощь, теперь он печатает сообщения; Я не могу его выполнить, но теперь я вижу это:

Страница https://login.yahoo.com/ содержала небезопасное содержимое с http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js.

Я не могу загрузить jQuery из другого домена, и параметры --local-to-remote-url-access=true или --web-security=false не имеют значения.

Я попробую загрузить jQuery локально. Вот код:

console.log('Loading a web page');
var url = 'https://login.yahoo.com/'; 
var page = require('webpage').create();
console.log('Setting error handling');
page.onConsoleMessage = function (msg) {
    console.log(msg);
};
page.onError = function (msg, trace) {
    console.log(msg);
    trace.forEach(function(item) {
        console.log('  ', item.file, ':', item.line);
    })
    phantom.exit();
}
console.log('Error handling is set');
console.log('Opening page');
page.open(url, function (status) {
    if (status != 'success') {
        console.log('F-' + status);
    } else {
        console.log('S-' + status); 
        //-------------------------------------------------     
        var jsLoc = '';
        jsLoc = 'jquery.min.js'; // to load local
        //jsLoc = 'http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js'; // to load remote
        var func = function(pg){
            console.log('Function called');
            console.log('Page evaluating');
            console.log(pg);
            pg.evaluate(function() {
                console.log('Page evaluate started');               
                //---
                var loginVar = '[email protected]';
                var pwdVar = 'itsmypass_445f4hd564hd56f46s'; 
                //---
                $("#login_form #username").value = loginVar;
                $("#login_form #passwd").value = pwdVar;
                //---
            });
            console.log('Rendering');
            pg.render('ystsA.png');
            console.log('Rendered');
        }
        if (typeof jQuery == 'undefined') {  
            console.log('JQuery Loading');  // <<<<==== Execute only until here
            console.log('Source:['+jsLoc+']');
            var rs = page.includeJs(jsLoc, function()  // <<<<===== Fail here, jsLoc was changed to load locally and after tried remotely, i tried use page.injectJs but fail too
            { 
                console.log('JQuery Loaded');  // <<<< ===== Never reach here, no matter if loading local or remote script in include above
                func(page); 
            });
            page.render('ystsB.png');
        } else {
            console.log('JQuery Already Loaded');
            func(page);
            page.render('ystsC.png');
        }
        //-------------------------------------------------
    }
    phantom.exit();
});

Прочитав ответ @ g4d564w56, я сделал все без JQuery, затем я могу заполнить текстовое поле, но не могу нажать кнопку, чтобы опубликовать сообщение в форме входа.
См. Новый код:

console.log('Loading a web page');
var url = 'https://login.yahoo.com/'; 
var page = require('webpage').create();
console.log('Setting error handling');
page.onConsoleMessage = function (msg) {
    console.log(msg);
};
page.onError = function (msg, trace) {
    console.log(msg);
    trace.forEach(function(item) {
        console.log('  ', item.file, ':', item.line);
    })
    phantom.exit();
}
console.log('Error handling is set');
console.log('Opening page');
page.open(url, function (status) {
    if (status != 'success') {
        console.log('F-' + status);
    } else {
        console.log('S-' + status); 
        //-------------------------------------------------     
        var jsLoc = '';
        jsLoc = 'jquery.min.js'; // to load local
        //jsLoc = 'http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js'; // to load remote      
        var act01 = function(pg){
            console.log('Function called');
            console.log('Page evaluating');
            console.log(pg);
            pg.evaluate(function() {
                var getElmById = function(id){
                    return document.getElementById(id);
                }           
                console.log('Page evaluate started');               
               //---
                var loginVar = '[email protected]';
                var pwdVar = 'itsmypass_445f4hd564hd56f46s'; 
                //---
                getElmById("username").value = loginVar;
                getElmById("passwd").value = pwdVar;
                getElmById("login_form").submit(); /// <<<<==== now its dont work !!!
                //---
            });
            console.log('Rendering');
            pg.render('ystsA.png');
            console.log('Rendered');
        }
        act01(page);
        //-------------------------------------------------
    }
    phantom.exit();
});

person newway    schedule 06.04.2013    source источник
comment
Решение находится здесь: stackoverflow.com/questions/11121734/evaluate- не работает/   -  person    schedule 06.04.2013
comment
@ b1f56gd4 Большое спасибо, b1f56gd4. Проблема заключалась в том, что phantmJs по умолчанию не выполняли console.log внутри блока оценки, на странице выше показан трюк. Теперь я вижу, как страница запускает небезопасный контент и небезопасный JavaScript пытается получить доступ к фрейму с URL-адресом из фрейма с URL-адресом. Домены, протоколы и порты должны совпадать. Спасибо, теперь я могу видеть и отлаживать.   -  person newway    schedule 06.04.2013
comment
Я знаю, что этому вопросу уже год, но для тех, кто находит этот вопрос с помощью поиска в Google, проблема в этом конкретном случае заключается в том, что ресурс http используется на странице https. Чтобы загрузить jquery, все, что вам нужно сделать, это использовать URL-адрес https.   -  person derickito    schedule 16.05.2014


Ответы (5)


Я знаю, что на этот вопрос уже был ответ около года назад, но ответ на самом деле не касался проблемы. Причина ошибки ниже:

"Страница https://login.yahoo.com/ содержала небезопасный контент с http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js".

Является ли страница входа в систему https-страницей, и вы пытаетесь загрузить http-ресурс. Если вы измените URL-адрес на https://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js эта ошибка исчезнет. Потребовалось время, чтобы понять это.

person derickito    schedule 15.05.2014
comment
Это помогло мне избавиться от ошибки запуска небезопасного содержимого. Огромное спасибо! - person pauloz1890; 13.09.2014

Рабочая версия с использованием поиска Google.

var page, doSearch, displayResults;
page = require('webpage').create();

doSearch = function() {
    console.log('Searching...');
    page.evaluate(function() {
        $("input[name=q]").val('what is phantomjs');
        $("form").trigger('submit');
        return true;
    });
    page.render('phantomjs-searching.png');
};

displayResults = function() {
    console.log('Results...');
    page.evaluate(function() {
        $('h3 a').each(function(i) {
            console.log([i + 1, $(this).text(), ' // ' + $(this).attr('href')].join(': '));
        });
        return true;
    });
    page.render('phantomjs-results.png');
};

page.onLoadFinished = function(status) {
    if (status === 'success') {
        page.includeJs('http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js', function() {
            if (!phantom.state) {
                doSearch();
                phantom.state = 'results';
            } else {
                displayResults();
                phantom.exit();
            }
        });
    } else {
        console.log('Connection failed.');
        phantom.exit();
    }
};

page.onConsoleMessage = function(msg) {
    console.log(msg);
};

page.open('http://google.com');
person Gil Barbara    schedule 06.01.2014

Попробуйте следующий код из http://snippets.aktagon.com/snippets/534-How-to-scrape-web-pages-with-PhantomJS-and-jQuery. Он загружает локальную копию jQuery, но также может использовать экземпляр jQuery, загруженный запрошенной страницей.

var page = new WebPage(),
     url = 'http://localhost/a-search-form',
     stepIndex = 0;

 /**
  * From PhantomJS documentation:
  * This callback is invoked when there is a JavaScript console. The callback may accept up to three arguments: 
  * the string for the message, the line number, and the source identifier.
  */
 page.onConsoleMessage = function (msg, line, source) {
     console.log('console> ' + msg);
 };

 /**
  * From PhantomJS documentation:
  * This callback is invoked when there is a JavaScript alert. The only argument passed to the callback is the string for the message.
  */
 page.onAlert = function (msg) {
     console.log('alert!!> ' + msg);
 };

 // Callback is executed each time a page is loaded...
 page.open(url, function (status) {
   if (status === 'success') {
     // State is initially empty. State is persisted between page loads and can be used for identifying which page we're on.
     console.log('============================================');
     console.log('Step "' + stepIndex + '"');
     console.log('============================================');

     // Inject jQuery for scraping (you need to save jquery-1.6.1.min.js in the same folder as this file)
     page.injectJs('jquery-1.6.1.min.js');

     // Our "event loop"
     if(!phantom.state){
       initialize();
     } else {
       phantom.state();
     } 

     // Save screenshot for debugging purposes
     page.render("step" + stepIndex++ + ".png");
   }
 });

 // Step 1
 function initialize() {
   page.evaluate(function() {
     $('form#search input.query').val('Jebus saves');
     $('form#search').submit();
     console.log('Searching...');
   });
   // Phantom state doesn't change between page reloads
   // We use the state to store the search result handler, ie. the next step
   phantom.state = parseResults; 
 }

 // Step 2
 function parseResults() {
   page.evaluate(function() {
     $('#search-result a').each(function(index, link) {
       console.log($(link).attr('href'));
     })
     console.log('Parsed results');
   });
   // If there was a 3rd step we could point to another function
   // but we would have to reload the page for the callback to be called again
   phantom.exit(); 
 }
person lmeurs    schedule 11.06.2013
comment
Большое спасибо за ваше время и помощь. Я сделал минимальные изменения, чтобы сделать его исполняемым на реальном сайте, может быть, я сломал это, но когда я запускаю код, он не возвращается, остается часами и не возвращается, делается только один скриншот (первый). в любом случае большое спасибо. - person newway; 07.07.2013

Существует хорошо известная ошибка, заключающаяся в том, что PhantomJS не может загрузить JQuery, будет сложно отправить некоторые данные формы на сервер, но вы можете выбирать элементы только с помощью querySelectorAll, как в этом примере: как очищать ссылки с помощью phantomjs

person g4d564w56    schedule 11.04.2013
comment
Спасибо за эту информацию, в моих поисках я никогда не находил эту информацию об этой ошибке, никогда не предполагайте, что PhantomJS не может загрузить JQuery, потому что это обычный безголовый браузер. Думаю вернуться к HtmlUnit - person newway; 11.04.2013
comment
@elimisteve Если я скопирую и вставлю образец автоматизации страницы в файл и запущу $ phantomjs sample.phantomjs. Я получаю небезопасную попытку JavaScript получить доступ к фрейму с URL-адресом about:blank из фрейма с сообщением URL. Спасибо за ваше предложение о page.injectJs. - person Tobias; 30.01.2015

Ответ @lmeurs очень хорош, но не функционален.
Я использовал ответ, чтобы создать для вас что-то функциональное :) .

var page = new WebPage();
var url = 'http://br.search.yahoo.com';
var stepIndex = 0;

page.onConsoleMessage = function (msg, line, source) { console.log('console> ' + msg); };

page.onAlert = function (msg) { console.log('alert!!> ' + msg); };

function takeShot(){
    console.log("TakingShot"); 
    page.render("step" + stepIndex + ".png");
    console.log("ShotTake");     
}

function step0() {
    console.log("step 00 enter");
    page.evaluate(function() {
        $("form [type='text']").val('its now sunday searching it');
        $("form [type='submit']").submit();     
    });
    console.log("step 00 exit");
}

function step1() {
    console.log("step 01 enter");
    page.evaluate(function() {
        $('#search-result a').each(function(index, link) {
            console.log($(link).attr('href'));
        })
    });
    console.log("step 01 exit");
    phantom.exit(); 
}

page.open(url, function (status) {
    console.log("[- STARTING -]");
    if (status === 'success') {
        var cmd = ""
        page.injectJs('jquery-1.6.1.min.js');
        while(true)
        {
            console.log("Step["+stepIndex+"] starting on ["+new Date()+"]");
            //cmd = "var x = step"+stepIndex+";"
            //console.log(cmd);
            //eval(cmd);
            switch(stepIndex){
                case 0:
                    step0();
                    break;
                case 1:
                    step1();
                    break;                  
            }
            takeShot();
            stepIndex++;
        }       
    }
});
person h154sdfh656d4f    schedule 06.07.2013
comment
Большое спасибо за ваше время и помощь. Я запустил ваш код как есть, я ничего не менял, единственное, что я сделал, это поместил файл [jquery-1.6.1.min.js] в ту же папку вашего скрипта. Он работает нормально и возвращается, он делает снимок экрана домашнего поиска Yahoo, как и ожидалось на шаге 1, но не печатает список ссылок результата, ожидаемого от шага 2, на шаге 2 снова делает снимок экрана домашней страницы поиска Yahoo, похоже, не публикуя аргумент поиска на Yahoo форма. в любом случае большое спасибо - person newway; 07.07.2013