7

在我的 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 文件位于同一目录中吗?

4

7 回答 7

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(...)调用方式的问题。我怀疑这是一个非阻塞调用,但根据本期作者的说法,这是一个阻塞调用。如果我不得不冒险猜测,也许渲染的行为是一个阻塞调用,但是执行渲染的代码可能会将数据移交给另一个线程,该线程处理将数据持久化到磁盘(所以这部分可能是非-阻塞呼叫)。不幸的是,当执行回到主脚本并执行时,这个调用可能仍在执行phantom.exit(),这意味着前面提到的异步代码永远没有机会完成它正在做的事情。

我能够在 PhantomJS 论坛上找到一篇与您所描述的内容有关的帖子。我看不到任何已提交的问题,因此,如果您愿意,可以继续发布一个。

于 2013-03-04T16:12:14.200 回答
8

我和这篇文章的作者有同样的问题,没有一个代码示例对我有用。让 Phantom.js 文档中的第二个示例不起作用,有点让人迷失方向。在 Snow Leopard 上使用 Home Brew 安装。

我找到了一个工作示例

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();
};
于 2013-03-12T23:03:33.303 回答
5

对于来这里寻找保存 PhantomJS 或 CasperJS 屏幕截图的目录的人来说,这只是一个快速帮助:默认情况下它在 scripts 目录中。但是,您确实有控制权。

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

page.render('screenshots/google.jpg'); // saves to scriptLocation/screenshots/
page.render('/opt/google.jpg'); // saves to /screenshots (in the root)

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

casper.capture('/opt/google.jpg',
        undefined,
        { // imgOptions
            format: 'jpg',
            quality: 25
        }); 

希望这可以为某人省去麻烦!

于 2015-10-05T09:04:24.047 回答
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。

但是,最初导致我进入该线程的原因是图像文件从未像原始问题一样在我的磁盘上创建。我认为这是某种安全问题,所以我登录到虚拟机并开始将所有内容放在同一个目录中。我正在使用批处理文件启动 phantomjs.exe,并将我的 .js 文件作为参数传入。将所有文件都放在我的 VM 上的同一目录中,效果很好。通过反复试验,我发现我的批处理文件必须与我的 .js 文件位于同一目录中。现在我的主机上也一切正常。

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

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

于 2016-07-27T20:16:22.747 回答
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);
于 2014-11-26T20:34:57.820 回答
0

从rasterize.js 示例中窃取,它比我接受的答案更可靠。

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.");
    }
});
于 2016-01-15T09:21:05.390 回答
0

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

我正在运行一个 phantomjs docker 映像,默认用户是“phantomjs”,而不是 root。因此,我试图写入一个我没有权限的位置(它是 docker 主机上的密码)......

> 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 命令即可解决此问题,然后我就可以google.png在 CWD 中找到它。

为了完整起见,最后的命令:

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

于 2017-04-28T20:54:51.250 回答