【问题标题】:On PhantomJS I can't include jQuery and without jQuery I can't post form data在 PhantomJS 上我不能包含 jQuery,没有 jQuery 我不能发布表单数据
【发布时间】:2013-04-06 04:50:53
【问题描述】:

我在 PhantomJS 中运行 jQuery 时遇到问题。我找到了this 答案,它谈到在评估函数内部没有可用的变量,但问题是关于节点模块,在我的示例中,我只在评估函数内部调用console.log。我已经把这个问题放在GitHub too

以前,对于某些页面,以下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 = 'ih5d4hf65465fd45h6@yahoo.com.br';
                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 = 'ih5d4hf65465fd45h6@yahoo.com.br';
                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();
});

【问题讨论】:

  • @b1f56gd4 非常感谢 b1f56gd4。问题是 phantmJs 默认情况下不会在评估块内执行 console.log,上面的页面显示了这个技巧。现在我可以看到很多“页面在运行不安全的内容”和“不安全的 JavaScript 尝试从具有 URL 域、协议和端口必须匹配的框架访问具有 URL 的框架。”。谢谢,现在我可以看到和调试了。
  • 我知道这个问题已经有一年了,但是对于那些通过谷歌搜索找到这个问题的人来说,在这种特殊情况下的问题是 https 页面中正在使用 http 资源。为了加载 jquery,你所要做的就是使用 https url。

标签: javascript phantomjs evaluate


【解决方案1】:

我知道这个问题大约一年前就已经有了答案,但答案并没有真正解决这个问题。错误原因如下:

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,此错误将消失。花了一段时间才弄清楚。

【讨论】:

  • 这帮助我摆脱了“运行不安全的内容”错误。谢谢大家!
【解决方案2】:

使用谷歌搜索的工作版本。

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');

【讨论】:

    【解决方案3】:

    尝试来自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(); 
     }
    

    【讨论】:

    • 非常感谢您的时间和帮助。我做了最小的更改以使其在真实站点上可执行,也许我打破了它,但是当我运行它不返回的代码时,停留几个小时并且不返回,只截取一个屏幕截图(第一个)。无论如何,非常感谢。
    【解决方案4】:

    有一个众所周知的错误,即 PhantomJS 无法加载 JQuery,将难以将一些表单数据发布到服务器,但您只能使用 querySelectorAll 选择元素,例如:how to scrape links with phantomjs

    【讨论】:

    • 感谢您提供此信息,在我的搜索中从未找到有关此错误的信息,永远不会想象 PhantomJS 无法加载 JQuery,因为它是一个通用的无头浏览器。考虑回到HtmlUnit
    • 这不是真的;根据github.com/ariya/phantomjs/blob/master/examples/…phantomjs.org/page-automation.html 的示例,PhantomJS 可以很好地加载 jQuery。有时page.includeJs(url_to_jquery, function() { ... } 对我不起作用,所以我改用page.injectJs("./jquery.min.js") :-)。
    • @elimisteve 如果我将页面自动化示例复制粘贴到文件中并运行$ phantomjs sample.phantomjs。我收到“不安全的 JavaScript 尝试访问带有 URL 的框架 about:blank from frame with URL”消息。感谢您对page.injectJs 的建议。
    【解决方案5】:

    @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++;
            }       
        }
    });
    

    【讨论】:

    • 非常感谢您的时间和帮助。我按原样运行您的代码,我没有更改任何内容,我所做的唯一一件事就是将 [jquery-1.6.1.min.js] 文件放在脚本的同一文件夹中。它运行正常并返回,它在第 1 步按预期截取雅虎主页搜索的屏幕截图,但不打印第 2 步预期的结果链接列表,在第 2 步,它再次截取雅虎主页搜索页面的截图,看起来不像在雅虎上发布搜索参数形式。无论如何,非常感谢
    猜你喜欢
    • 2023-03-20
    • 1970-01-01
    • 1970-01-01
    • 2016-03-21
    • 2016-02-10
    • 2019-11-29
    • 2011-05-28
    • 2016-04-24
    • 1970-01-01
    相关资源
    最近更新 更多