来自phantom.js的截图在哪里保存?

时间:2013-03-04 15:53:52

标签: javascript phantomjs

在我的Mac上通过Homebrew安装后,开始使用Phantom.js。

我正在尝试通过https://github.com/ariya/phantomjs/wiki/Quick-Start

保存网站截图的示例
var page = require('webpage').create();
page.open('http://google.com', function () {
    page.render('google.png');
    phantom.exit();
});

但是我没有看到任何图像。它们是否与.js文件位于同一目录中?

7 个答案:

答案 0 :(得分:9)

PhantomJS通常会将图像渲染到与您正在运行的脚本相同的目录中。所以,是的,它应该与您使用PhantomJS运行的JavaScript文件位于同一目录中。

修改

看来这个特定的例子是有缺陷的。问题是page.render(...);需要一些时间来呈现页面,但是在完成渲染之前你正在调用phantom.exit()。通过这样做,我能够获得预期的输出:

var page = require('webpage').create();
page.open('http://google.com', function () {
    page.render('google.png');
    setTimeout(function() { phantom.exit(); }, 5000) // wait five seconds and then exit;
});

不幸的是,这并不理想,所以我能够想出一些更好的头发。我说一个“头发”,因为我基本上是轮询以查看页面何时完成渲染:

var done = false; //flag that tells us if we're done rendering

var page = require('webpage').create();
page.open('http://google.com', function (status) {
    //If the page loaded successfully...
    if(status === "success") {
        //Render the page
        page.render('google.png');
        console.log("Site rendered...");

        //Set the flag to true
        done = true;
    }
});

//Start polling every 100ms to see if we are done
var intervalId = setInterval(function() {
    if(done) {
        //If we are done, let's say so and exit.
        console.log("Done.");
        phantom.exit();
    } else {
        //If we're not done we're just going to say that we're polling
        console.log("Polling...");
    }
}, 100);

上面的代码有效,因为回调没有立即执行。因此,轮询代码将启动并开始轮询。然后,当执行回调时,我们检查以查看页面的状态(如果我们能够成功加载页面,我们只想渲染)。然后我们渲染页面并将我们的轮询代码正在检查的标志设置为true。因此,下次轮询代码运行时,标志为true,因此我们退出。

这看起来是PhantomJS运行webpage#render(...)调用的方式的问题。我怀疑它是一个非阻塞的呼叫,但据this issue中的作者说,这是一个阻塞呼叫。如果我不得不冒险猜测,也许渲染的行为是阻塞调用,但执行渲染的代码可能会将数据移交给另一个线程,该线程处理将数据持久保存到磁盘(因此这部分可能是非阻塞呼叫)。不幸的是,当执行回到主脚本并执行phantom.exit()时,这个调用可能仍在执行,这意味着前面提到的异步代码永远不会有机会完成它正在做的事情。

我能够在PhantomJS论坛上找到一篇与what you're describing交易的帖子。我看不到任何已提交的问题,所以如果您愿意,可以继续发布。

答案 1 :(得分:8)

我和这篇文章的作者有同样的问题,而且没有一个代码示例适合我。让Phantom.js文档中的第二个示例无法正常工作。在Snow Leopard上使用Home Brew安装。

我找到了working example

var page = require("webpage").create();
var homePage = "http://www.google.com/";
page.settings.javascriptEnabled = false;
page.settings.loadImages = false;
page.open(homePage);
page.onLoadFinished = function(status) {
  var url = page.url;
  console.log("Status:  " + status);
  console.log("Loaded:  " + url);
  page.render("google.png");
  phantom.exit();
};

答案 2 :(得分:5)

快速帮助那些来到这里寻找保存PhantomJS或CasperJS屏幕截图的目录的人:默认情况下它位于scripts目录中。但是,你确实有控制权。

如果你想控制它们的保存位置,你可以像这样改变文件名:

getView()

或者,如果您使用CasperJS,您可以使用:

public class ViewAdapter extends BaseAdapter {
    LayoutInflater minflater;


    @Override
    public int getCount() {
        return productsList.size();
    }

    @Override
    public Object getItem(int position) {
        return productsList.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    public ViewAdapter() {
        minflater = LayoutInflater.from(getBaseContext());

    }

    @Override
    public View getView(final int position, View convertView, ViewGroup parent) {

        if (convertView == null) {
            convertView = minflater.inflate(R.layout.you, null);

        }

        final TextView text11 = (TextView) convertView.findViewById(R.id.text11);
        text11.setText(productsList.get(position).get_productname());
        final TextView text22 = (TextView) convertView.findViewById(R.id.text22);
        text22.setText(productsList.get(position).get_versionname());
        final TextView text33 = (TextView) convertView.findViewById(R.id.text33);
        text33.setText(productsList.get(position).get_date());
        final Button update = (Button) convertView.findViewById(R.id.update);

        update.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

           //     int a = dbhandler.checkDatabase(productsList.get(position).get_date());

                final Calendar cal = Calendar.getInstance();
                int day = cal.get(Calendar.DAY_OF_MONTH);
                int month = cal.get(Calendar.MONTH);
                int year = cal.get(Calendar.YEAR);
                StringBuffer buffer = new StringBuffer();
                buffer.append(day + "-" + (month + 1) + "-" + year);
                String date = DateFormat.getTimeInstance().format(new Date());
               String b = "Date: " + buffer + "\n" + "Time: " + "" + date + "\n";
                dbhandler = new mydbhandler(getBaseContext(), null,null,1);
                dbhandler.updateProduct(position,b);

                productsList.clear();
                productsList.addAll(dbhandler.getFavList());
                ((ViewAdapter)listview.getAdapter()).notifyDataSetChanged();


            }


        });


        return convertView;
    }
}

希望这可以帮助别人解决问题!

答案 3 :(得分:4)

我不确定某些内容是否已发生变化,但http://phantomjs.org/screen-capture.html上的示例对我来说效果很好:

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

我正在运行phantomjs-2.1.1-windows。

然而,导致我进入这个主题的原因是最初的图像文件永远不会像原始问题一样在我的磁盘上创建。我认为这是某种安全问题所以我登录到VM并通过将所有内容放在同一目录中来启动。我正在使用批处理文件启动phantomjs.exe,我的.js文件作为参数传入。将所有文件放在我的VM上的同一目录中,它运行良好。通过反复试验,我发现我的批处理文件必须与我的.js文件位于同一目录中。现在一切都在我的主机上。

总而言之......对我来说这可能是一个与安全相关的问题。无需添加任何类型的超时。

我对原始问题的回答是,如果您正确设置了所有内容,该文件将与phantomjs.exe运行的.js文件位于同一目录中。我尝试为图像文件指定一个完全限定的路径,但似乎没有用。

答案 4 :(得分:1)

根本原因是即使在onLoadFinished()事件期间,page.render()也可能无法呈现图像。在page.render()成功之前,您可能需要等待几秒钟。我发现在PhantomJS中渲染图像的唯一可靠方法是重复调用page.render(),直到方法返回true,表明它成功渲染了图像。

解决方案:

var page = require("webpage").create();
var homePage = "http://www.google.com/";

page.onLoadFinished = function(status) {
  var rendered, started = Date.now(), TIMEOUT = 30 * 1000; // 30 seconds
  while(!((rendered = page.render('google.png')) || Date.now() - started > TIMEOUT));
  if (!rendered) console.log("ERROR: Timed out waiting to render image.")
  phantom.exit();
};

page.open(homePage);

答案 5 :(得分:0)

rasterize.js example窃取,它比我接受的答案更可靠。

var page = require('webpage').create();

page.open('http://localhost/TestForTest/', function (status) {
    console.log("starting...");
    console.log("Status: " + status);

    if (status === "success") {
        window.setTimeout(function () {
            page.render('myExample.png');
            phantom.exit();
        }, 200);
    } else {
        console.log("failed for some reason.");
    }
});

答案 6 :(得分:0)

这里有很多好的建议。我想补充一点:

我正在运行一个phantomjs docker镜像,默认用户是“phantomjs”,而不是root。因此我试图写一个我没有获得许可的位置(它是docker主机上的pwd)......

> docker run -i -t -v $(pwd):/pwd --rm wernight/phantomjs touch /pwd/foo.txt
touch: cannot touch '/pwd/foo.txt': Permission denied

上面的代码都运行没有错误,但是如果他们没有写入目标的权限,那么他们会默默地忽略请求...

例如,采用@ vivin-paliath的代码(当前接受的答案):

var done = false; //flag that tells us if we're done rendering

var page = require('webpage').create();
page.open('http://google.com', function (status) {
    //If the page loaded successfully...
    if(status === "success") {
        //Render the page
        page.render('google.png');
        console.log("Site rendered...");

        //Set the flag to true
        done = true;
    }
});

//Start polling every 100ms to see if we are done
var intervalId = setInterval(function() {
    if(done) {
        //If we are done, let's say so and exit.
        console.log("Done.");
        phantom.exit();
    } else {
        //If we're not done we're just going to say that we're polling
        console.log("Polling...");
    }
}, 100);

以默认用户身份运行它:

docker run -i -t -v $(pwd):/pwd -w /pwd --rm wernight/phantomjs phantomjs google.js 
Polling...
Polling...
Polling...
Polling...
Polling...
Polling...
Polling...
Polling...
Polling...
Polling...
Polling...
Polling...
Site rendered...
Done.

但没有google.png且没有错误。只需将-u root添加到docker命令即可解决此问题,并在CWD中获取google.png

为了完整性,最后的命令:

  

docker run -u root -i -t -v $(pwd):/ pwd -w / pwd --rm   wernight / phantomjs phantomjs google.js