使用PhantomJS截取多个HTML页面的屏幕截图

3
如大家在这个github问题中提到的那样,PhantomJS中的视口大小函数并不像很多人预期的那样表现。
我正在尝试为iPad拍摄Web应用程序的屏幕截图。该网站有一个position:fixed;页脚和页眉。当我拍摄屏幕截图时,我只想看到页面首次加载时可见的内容,因此我使用以下代码裁剪页面到所需的大小。
page.clipRect = { top: 0, left: 0, width: 1024, height: 768 };

因为该网站的头部和底部采用了position: fixed;属性,所以当页面内容需要滚动时,我截图时会缺失底部(它在页面底部)。
在回复中,有一种解决方案是将要截图的页面加载到一个对象中,并设置您想要的高度和宽度,然后截取对象的屏幕截图。
所有实现此功能的代码片段都假定您有一个要截图的单个URL。我想截取多个html文件的屏幕截图。我不太擅长JavaScript,而且我真的很难将这些解决方案合并到我的代码中。
这个解决方案可以将单个网页转换为使用json文件的多个不同尺寸的图像。
这个解决方案更符合我的需求,但同样只适用于单个网页。请注意,iframe不起作用,需要将iframe代码替换为具有加载要加载的html页面值的data属性的对象。
还有一个最终解决方案,比其他解决方案更完整,但同样只适用于单个URL。
过去我一直在使用以下代码,并且对于构建特定尺寸的Web应用程序,它运行得非常完美,但是这次构建的应用程序有所不同,这就是为什么屏幕截图出现问题的原因。
var system = require('system');
var dest = system.args[1];
var files = system.args[2].split(',');

function takeScreenshot(destName, index) {
    var page = require('webpage').create();

    // Open the target HTML file
    page.open(dest+'/'+destName+'/'+destName+'.html', function(status) {

        // Only capture 1024x768 area 
        page.clipRect = { top: 0, left: 0, width: 1024, height: 768 };

        // Save as PNG
        page.render(dest+'/'+destName+'/'+destName+'-full.png');

        // Send output to be caught by progress bar
        console.log('OK');

        // If the lop has finished exit, otherwise clean memory
        if(files.length == 0) {
        phantom.exit();
        } else {
            page.close();
            takeScreenshot(files.shift());
        }
    });

}

takeScreenshot(files.shift());

dest变量是截图的目标位置。

files是一个文件数组,我想要对它们进行截图。

1个回答

0

最终解决方案与您现有的代码结合起来应该很容易。思路是将实际代码移动到一个函数中,并在前一个URL完成后使用新的URL调用该函数。当您查看“最终解决方案”时,我们完成当前页面的位置用phantom.exit();表示。从那里,您可以触发进一步的截图。

这是完整的脚本,修改自DEfusion的版本:

var args = require('system').args,
    resourceWait  = 300,
    maxRenderWait = 10000,
    mode          = args[3] || 'iframe',
    dest          = args[1],
    files         = args[2].split(','),
    page          = require('webpage').create(),
    count         = 0,
    forcedRenderTimeout,
    renderTimeout;

page.viewportSize = { width: 1024, height : 768 };

function doRender() {
    page.render(filename);
    next();
}

page.onResourceRequested = function (req) {
    count += 1;
    clearTimeout(renderTimeout);
};

page.onResourceReceived = function (res) {
    if (!res.stage || res.stage === 'end') {
        count -= 1;
        if (count === 0) {
            clearTimeout(forcedRenderTimeout);
            renderTimeout = setTimeout(doRender, resourceWait);
        }
    }
};

page.onConsoleMessage = function (msg) {
    console.log("from page: " + msg);
};

function evaluateJsWithArgs(func) {
    var args = [].slice.call(arguments, 1);
    var fn = "function() { return (" + func.toString() + ").apply(this, " + JSON.stringify(args) + "); }";
    return page.evaluate(fn);
};

function next(error){
    if (!error) {
        if (files.length == 0){
            phantom.exit();
        } else {
            takeScreenshot(files.shift());
        }
    }
}

function takeScreenshot(file){
    var url = dest+'/'+file+'/'+file+'.html';
    filename = dest+'/'+file+'/'+file+'-full.png';
    if(mode == 'iframe') {
        // use iFrame
        page.open('about:blank', function (status) {
            if (status !== "success") {
                console.log('Unable to load url');
                next(true);
            } else {
                page.includeJs(
                    "https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js",
                    function() {
                        evaluateJsWithArgs(
                            function(url, w, h) {
                                $('body')
                                    .css({margin: 0, padding: 0})
                                    .append('<object data="' + url + '" width="'+ w + '" height="' + h + '" id="screen-frame" />');
                                $('#screen-frame')
                                    .width(w)
                                    .height(h);
                            },
                            url,
                            page.viewportSize.width,
                            page.viewportSize.height
                        );
                    }
                );

                forcedRenderTimeout = setTimeout(function () {
                    doRender();
                }, maxRenderWait);
            }
        });
    } else {
        // resize body
        page.open(url, function(status) {
            if (status !== "success") {
                console.log('Unable to load url');
                next(true);
            } else {
                page.includeJs(
                    "https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js",
                    function() {
                        evaluateJsWithArgs(
                            function(w,h) {
                               $('body, html').css({
                                    width: w + 'px',
                                    height: h + 'px',
                                    overflow: 'hidden'
                               });
                            },
                            page.viewportSize.width,
                            page.viewportSize.height
                        );

                        forcedRenderTimeout = setTimeout(function () {
                            doRender();
                        }, maxRenderWait);
                    }
                );
            }
        });
    }
}

takeScreenshot(files.shift());

啊,我真的很希望这个能够运行。但不幸的是它没有成功 :(. 因为我是将其作为grunt任务的一部分运行的,所以调试起来非常棘手,因为控制台日志会输出。请问您能否推荐任何在grunt之外运行它的方法吗?非常感谢你。 - Oliver Evans
你说它不工作,这句话并没有提供任何信息,请具体说明一下。我注意到 iframe 变量在处理本地文件时无法正常工作。至于 grunt,我没有相关经验,无法为你提供帮助。 - Artjom B.
抱歉,我知道这是一个糟糕的回应,但因为它在grunt后台运行,我无法将任何内容记录下来,所以我不知道还能说什么。因此,我已经将此脚本从grunt中取出,尝试直接使用phantomjs screenshot.js从终端运行它。我用grunt传递给screenshot.js文件的值替换了所有系统参数。当我运行此命令时,控制台会出现CoreText性能提示。在目标目录中创建了图像文件,但它们不包含任何截图,只是完全空白的图像。我会继续尝试调试。 - Oliver Evans
我创建了一个测试HTML页面,只是为了确保对象实际上会像预期的那样使页面出现。它确实如此。我已经记录了URL、文件名等变量,看起来都没问题。仍然困惑。 - Oliver Evans
我有一种感觉,这可能与页面位置与文件位置的参照有关。我正在以下文件位置执行此截图脚本:root/tools/screenshot.js。我要截图的页面位于root/dist/files.html。您知道文件位置是从哪里运行脚本(例如根目录)还是脚本所在的位置(root/tools/screenshot.js)的参考吗? - Oliver Evans

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接