【问题标题】:Pass arguments with page.evaluate使用 page.evaluate 传递参数
【发布时间】:2012-03-23 11:03:58
【问题描述】:

我正在使用 PhantomJS page.evaluate() 进行一些抓取。我的问题是我传递给 webkit 页面的代码是沙盒的,因此无法访问我的主幻像脚本的变量。这使得抓取代码很难通用。

page.open(url, function() {
  var foo = 42;

  page.evaluate(function() {
    // this code has no access to foo
    console.log(foo);
  });
}

如何将参数推送到页面中?

【问题讨论】:

标签: javascript phantomjs


【解决方案1】:

我遇到过这个问题。这可以通过一些技巧来完成,因为page.evaluate 也可以接受字符串。

有几种方法可以做到这一点,但我使用了一个名为 evaluate 的包装器,它接受附加参数以传递给必须在 webkit 端评估的函数。你可以这样使用它:

page.open(url, function() {
  var foo = 42;

  evaluate(page, function(foo) {
    // this code has now has access to foo
    console.log(foo);
  }, foo);
});

这里是evaluate() 函数:

/*
 * This function wraps WebPage.evaluate, and offers the possibility to pass
 * parameters into the webpage function. The PhantomJS issue is here:
 * 
 *   http://code.google.com/p/phantomjs/issues/detail?id=132
 * 
 * This is from comment #43.
 */
function evaluate(page, func) {
    var args = [].slice.call(arguments, 2);
    var fn = "function() { return (" + func.toString() + ").apply(this, " + JSON.stringify(args) + ");}";
    return page.evaluate(fn);
}

【讨论】:

  • 太棒了!这个源代码清楚地解释了它是如何工作的。
  • 要深入解释为什么会发生这种情况,请查看这个问题:stackoverflow.com/questions/12222856/…
  • 您的解决方案似乎不错,但是如果我想通过回调怎么办,可以吗?两天去垃圾。 JS 回调中是否有类似参数的全局对象?
【解决方案2】:

更改已推送,现在您可以将其用作

page.open(url, function() {
  var foo = 42;

  page.evaluate( function(foo) {
  // this code has now has access to foo
  console.log(foo);
  }, foo);
}

推送详情在这里:https://github.com/ariya/phantomjs/commit/81794f9096

【讨论】:

  • 这是最好的方法,以防您传递的对象不复杂,如函数等。
  • 你能提供一个传递多个参数的例子吗?
  • 对于那些想要传递多个参数的人,您是否尝试过使用数组作为单个参数?
【解决方案3】:

您可以将参数传递给函数作为 page.evaluate 的参数。

例子:

page.evaluate(function(arg1, arg2){
    console.log(arg1); //Will print "hi"
    console.log(arg2); //Will print "there"
}, "hi", "there");

【讨论】:

    【解决方案4】:

    有适用于 PhantomJS 0.9.2 和 0.2.0 的解决方案:

    page.evaluate(
        function (aa, bb) { document.title = aa + "/" + bb;}, //the function
        function (result) {}, // a callback when it's done
        "aaa", //attr 1
        "bbb"); //attr 2
    

    【讨论】:

    • 这可能不是直接针对 PhantomJS,而是 node.js 和 PhantomJS 之间的桥梁。这样的桥使用稍微不同的语法。
    • 如果您尝试将参数传递给phantomjs-nodejs bridge 中的沙盒评估方法,则此答案就是票证。文档仍然很新鲜。我几乎放弃了,直到我找到了这个答案。谢谢!
    【解决方案5】:

    另一种可能性:将变量与 url 一起传递。例如,传递对象 x

    // turn your object "x" into a JSON string
    var x_json = JSON.stringify(x);
    
    // add to existing url
    // you might want to check for existing "?" and add with "&"
    url += '?' + encodeURIComponent(x_json);
    
    page.open(url, function(status){
        page.evaluate(function(){
            // retrieve your var from document URL - if added with "&" this needs to change
            var x_json = decodeURIComponent(window.location.search.substring(1));
            // evil or not - eval is handy here
            var x = eval('(' + x_json + ')');       
        )}
    });
    

    【讨论】:

    • 无法在 PhantomJS 中工作,因为 page.evaluate() 已被沙盒化。
    【解决方案6】:

    这对我有用:

    page.evaluate("function() {document.body.innerHTML = '" + size + uid + "'}");
    

    表示将所有内容都作为字符串。反正后来它变成了一个字符串。检查库源。

    【讨论】:

      【解决方案7】:

      虽然您可以将参数传递给evaluate(function, arg1, arg2, ...),但这通常有点麻烦。尤其是在传入多个变量或更糟的函数时。

      要绕过这个障碍,可以改用injectJs(filename)

      page.open(url, function() {
          if ( webpage.injectJs('my_extra_functionality.js') ) {
              page.evaluate( function() {
                  // this code has access to foo and also myFunction();
                  console.log(foo);
                  console.log(myFunction());
              });
          }
          else {
              console.log("Failed to inject JS");
          }
      }
      

      其中my_extra_functionality.js是同一目录下的本地文件:

      var foo = 42;
      var myFunction = function(){
          return "Hello world!";
      }
      

      【讨论】:

      • 如果有人正在寻找 puppeteer 解决方案,您可以使用 await page.addScriptTag({path: "/path/to/file/with/extra/functionality"});
      【解决方案8】:

      你不能只将 args 绑定到函数吗??

      page.evaluate.bind(args)(callbackFn)
      

      【讨论】:

        猜你喜欢
        • 2018-03-20
        • 2015-04-15
        • 1970-01-01
        • 2020-10-23
        • 1970-01-01
        • 1970-01-01
        • 2018-04-02
        • 2012-05-24
        相关资源
        最近更新 更多