Php 获取完成呈现和运行脚本的页面的当前样式(可能是内联的)的HTML

Php 获取完成呈现和运行脚本的页面的当前样式(可能是内联的)的HTML,php,html,css,Php,Html,Css,我需要使用一个服务器端应用程序来获取当前样式(可能是内联的)的HTML,该应用程序将只提供一个URL(没有cookie、帖子、不妨碍表单等额外信息),该页面已完成呈现和运行脚本 使用浏览器库将网桥/代理连接到临时运行的浏览器或独立实用程序是一种公认的解决方案(但是,所选的浏览器或浏览器库必须在所有主要平台上都可用,并且必须能够在不存在或安装OS GUI的情况下运行) 一个可选的要求是在之后删除所有脚本(已经有了独立的解决方案,在这里添加它,因为可能给定的答案将能够在渲染或类似的情况下删除脚本)

我需要使用一个服务器端应用程序来获取当前样式(可能是内联的)的HTML,该应用程序将只提供一个URL(没有cookie、帖子、不妨碍表单等额外信息),该页面已完成呈现和运行脚本

使用浏览器库将网桥/代理连接到临时运行的浏览器或独立实用程序是一种公认的解决方案(但是,所选的浏览器或浏览器库必须在所有主要平台上都可用,并且必须能够在不存在或安装OS GUI的情况下运行)

一个可选的要求是在之后删除所有脚本(已经有了独立的解决方案,在这里添加它,因为可能给定的答案将能够在渲染或类似的情况下删除脚本)

如何在当前HTML文档的单个.HTML文件中使用当前样式(可能是内联的)和当前图像(使用)获取HTML+CSS快照?

如果可以使用纯PHP实现,那将是一个加号(尽管我对此表示怀疑,但我还没有发现任何有趣的东西)

编辑:我知道如何加载HTTP资源并获取URL的HTML,这不是我想要的;)

编辑2 输入HTML的示例:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
    <head>
        <title></title>

        <meta http-equiv="Content-Type" content="text/html;charset=utf-8">

        <link rel="stylesheet" type="text/css" href="/css/example.css">
        <script type="text/javascript" src="/javascript/example.js"></script>

        <script type="text/javascript">
            window.addEventListener("load",
                function(event){
                    document.title="New title";

                    document.getElementById("pic_0").style.border="0px";
                }
            );
        </script>
        <style type="text/css">
            p{
                color: blue;
            }
        </style>
    </head>
    <body>
        <p>Hello world!</p>
        <p>
            <img 
                alt="" 
                style="border: 1px" 
                id="pic_0" 
                src="http://linuxgazette.net/144/misc/john/helloworld.png"
            >
        </p>
    </body>
</html>

window.addEventListener(“加载”,
功能(事件){
document.title=“新标题”;
document.getElementById(“pic_0”).style.border=“0px”;
}
);
p{
颜色:蓝色;
}
你好,世界

示例输出:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
    <head>
        <title>New title</title>

        <meta http-equiv="Content-Type" content="text/html;charset=utf-8">

        <style type="text/css">
            b{font-weight: bold}
        </style>

        <style type="text/css">
            p{
                color: blue;
            }
        </style>
    </head>
    <body>
        <p>Hello world!</p>
        <p>
            <img 
                alt="" 
                style="border: 0px" 
                id="pic_0" 
                src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoBAMAAAB+0KVeAAAAK3RFWHRDcmVhdGlvbiBUaW1lAFYgMzEgYXVnLiAyMDEyIDE3OjU4OjU1ICswMjAwWMdbPwAAAAd0SU1FB9wIHw8ABeoUyU4AAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAEZ0FNQQAAsY8L/GEFAAAABlBMVEX///8AAABVwtN+AAAAXklEQVR42uWQUQ6AMAhD6Q3a+19WqsawwMf+NLEfy3iDlC7idTGQp/YglFAsUMqSwjlQOhN3mIMTHDq70SeEWBbt0EG8POWkDySvmCh/SssvNfwIfb+hFmgjFKPf6gDQBAQ368m09AAAAABJRU5ErkJggg=="
            >
        </p>
    </body>
</html>

新标题
b{字体大小:粗体}
p{
颜色:蓝色;
}
你好,世界

请注意
标记是如何更改的,
边框:1px
是如何变成
边框:0px
,图像URL是如何转换为

例如,使用Google Chrome inspector检查文档时,可以观察到其中一些转换(内联CSS和
标记)

编辑3:用页面上的资源(样式和图像)替换外部资源并删除javascript是一个简单的部分。最困难的部分是在运行javascript之后计算CSS样式

编辑4也许这可以使用注入的javascript来完成(但仍然需要浏览器控制)?

是一个带有javascript API的无头(无GUI)WebKit。 正如我在问题中所要求的,它在所有主要平台上运行

它可以运行Javascript脚本来控制无GUI的web浏览器。它有一个强大的API,还有很多很多的例子

在过去2-3天的空闲时间里,我为我的问题编写了解决方案,它完美地涵盖了所有需求。我还没有找到一个网页,它不会工作

用法,命令行:

phantomjs save_as_html.js http://stackoverflow.com/q/12215844/584490 saved.html

Javascript允许在加载所有其他内容后运行
n
秒,即使是完全由Javascript生成的网页,它也应该可以工作

注:

  • 在可能的情况下,XHR加载资源优于HTML5的画布渲染,因为减少了文件大小并防止了质量损失(重用原始文件比任何事情都好)

  • 背景图像
    ,在所有DOM节点上使用getComputedStyle()读取

  • 标记和事件处理程序属性将被删除

  • 带有
    rel=“alternative”
    的标记也会被删除(也许它们不应该被删除,而是被固定到一个绝对URL中,如果是相对的)

  • 当前未处理,其src属性设置为
    关于:空白

请注意,所有跨站点脚本安全限制均已解除,以便可以加载所有资源。确保在使用Facebook帐户的某些机密凭据时,您不会试图保存恶意网页:)

另存为\u html.js
内容:

//http://stackoverflow.com/a/12256190/584490
var page=require('webpage')。create();
page.onConsoleMessage=函数(msg){console.log(msg);};
var系统=要求(“系统”);
变量地址、输出、大小;
if(系统参数长度!=3)
{
log('用法:将_另存为_html.js URL文件名');
幻影。出口(1);
}
其他的
{
地址=system.args[1];
输出=系统参数[2];
page.viewportSize={
宽度:1680,
身高:1050,
};
//安全错误:DOM异常18:试图突破用户代理的安全策略。
//启用跨站点脚本:
page.settings.xsauditingEnabled=false;
page.settings.localToRemoteUrlAccessEnabled=true;
page.settings.webSecurityEnabled=false;
page.settings.userAgent=“Mozilla/5.0(Windows NT 6.1;WOW64)AppleWebKit/537.1(KHTML,如Gecko)Chrome/22.0.1207.1 Safari/537.1”;
page.settings.ignoreSslErrors=true;
第页打开(地址、功能(状态){
如果(状态!=“成功”)
{
console.log(“无法加载URL,返回状态:+状态”);
幻影。出口(1);
}
其他的
{
setTimeout(函数(){
page.evaluate(函数(){
var nodeList=document.getElementsByTagName(“*”);
Arrenventhandlerattributes变量=[
“onblur”、“onchange”、“onclick”、“ondblick”、“onfocus”、“onkeydown”、“onkeydup”、“onkeypress”、“onkeydup”、“onload”,
“onmousedown”,“onmouse”
//http://stackoverflow.com/a/12256190/584490

var page = require('webpage').create();
page.onConsoleMessage = function (msg) { console.log(msg); };

var system = require('system');
var address, output, size;


if (system.args.length!=3)
{
    console.log('Usage: save_as_html.js URL filename');
    phantom.exit(1);
}
else
{
    address = system.args[1];
    output = system.args[2];

    page.viewportSize = {    
        width: 1680, 
        height: 1050,
    };

    //SECURITY_ERR: DOM Exception 18: An attempt was made to break through the security policy of the user agent.
    //Enable cross site scripting:
    page.settings.XSSAuditingEnabled=false;
    page.settings.localToRemoteUrlAccessEnabled=true;
    page.settings.webSecurityEnabled=false;

    page.settings.userAgent="Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/22.0.1207.1 Safari/537.1";
    page.settings.ignoreSslErrors=true;

    page.open(address, function (status){
        if (status!=='success')
        {
            console.log("Unable to load URL, returned status: "+status);
            phantom.exit(1);
        }
        else
        {
            window.setTimeout(function (){
                page.evaluate(function(){
                    var nodeList=document.getElementsByTagName("*");

                    var arrEventHandlerAttributes=[
                        "onblur", "onchange", "onclick", "ondblclick", "onfocus", "onkeydown", "onkeyup", "onkeypress", "onkeyup","onload",
                        "onmousedown", "onmousemove", "onmouseout", "onmouseover", "onmouseup", "onreset", "onselect", "onsubmit", "onunload"
                    ];


                    //http://stackoverflow.com/a/7372816/584490
                    var base64Encode=function(str)
                    {
                        var CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
                        var out = "", i = 0, len = str.length, c1, c2, c3;
                        while (i < len) {
                            c1 = str.charCodeAt(i++) & 0xff;
                            if (i == len) {
                                out += CHARS.charAt(c1 >> 2);
                                out += CHARS.charAt((c1 & 0x3) << 4);
                                out += "==";
                                break;
                            }
                            c2 = str.charCodeAt(i++);
                            if (i == len) {
                                out += CHARS.charAt(c1 >> 2);
                                out += CHARS.charAt(((c1 & 0x3) << 4) | ((c2 & 0xF0) >> 4));
                                out += CHARS.charAt((c2 & 0xF) << 2);
                                out += "=";
                                break;
                            }
                            c3 = str.charCodeAt(i++);
                            out += CHARS.charAt(c1 >> 2);
                            out += CHARS.charAt(((c1 & 0x3) << 4) | ((c2 & 0xF0) >> 4));
                            out += CHARS.charAt(((c2 & 0xF) << 2) | ((c3 & 0xC0) >> 6));
                            out += CHARS.charAt(c3 & 0x3F);
                        }
                        return out;
                    };


                    for(var n=nodeList.length-1; n>0; n--)
                    {
                        try
                        {
                            var el=nodeList[n];

                            if(el.nodeName=="IMG" && el.src.substr(0, 5)!="data:")
                            {
                                /*var canvas=document.createElement("canvas");

                                canvas.width=parseInt(el.width);
                                canvas.height=parseInt(el.height);

                                var ctx=canvas.getContext("2d");
                                ctx.drawImage(el, 0, 0);
                                el.src=canvas.toDataURL();*/

                                var xhr=new XMLHttpRequest();

                                xhr.open(
                                    "get",
                                    el.src,
                                    /*Asynchronous*/ false
                                );

                                xhr.overrideMimeType("text/plain; charset=x-user-defined");

                                xhr.send(null);

                                var strResponseContentType=xhr.getResponseHeader("Content-type").split(";")[0].replace(/[^a-z0-9\/-]/gi, "");
                                el.src="data:"+strResponseContentType+";base64,"+base64Encode(xhr.responseText);
                            }
                            else if(el.nodeName=="LINK")
                            {
                                if(el.rel=="alternate")
                                {
                                    el.parentNode.removeChild(el);
                                }
                                else if(el.href.substr(0, 5)!="data:")
                                {
                                    var xhr=new XMLHttpRequest();

                                    xhr.open(
                                        "get",
                                        el.href,
                                        /*Asynchronous*/ false
                                    );

                                    xhr.overrideMimeType("text/plain; charset=x-user-defined");

                                    xhr.send(null);

                                    //var strResponseContentType=xhr.getResponseHeader("Content-type").split(";")[0].replace(/[^a-z0-9\/-]/gi, "");
                                    //el.href="data:"+strResponseContentType+";base64,"+base64Encode(xhr.responseText);
                                    el.href="data:"+el.type+";base64,"+base64Encode(xhr.responseText);
                                }

                                continue;
                            }
                            else if(el.nodeName=="SCRIPT")
                            {
                                el.parentNode.removeChild(el);

                                continue;
                            }
                            else if(el.nodeName=="IFRAME")
                            {
                                el.src="about:blank";

                                continue;
                            }

                            for(var z=arrEventHandlerAttributes.length-1; z>=0; z--)
                                el.removeAttribute(arrEventHandlerAttributes[z]);

                            var strBackgroundImageURL=window.getComputedStyle(el).getPropertyValue("background-image").replace("/[\s]/g", "");
                            if(strBackgroundImageURL.substr(0, 4)=="url(" && strBackgroundImageURL.substr(4, 5)!="data:")
                            {
                                strBackgroundImageURL=strBackgroundImageURL.substr(4, strBackgroundImageURL.length-5);

                                /*var imageTemp=document.createElement("img");
                                imageTemp.src=strBackgroundImageURL;

                                imageTemp.onload=function(e){
                                    var canvas=document.createElement("canvas");

                                    canvas.width=parseInt(imageTemp.width);
                                    canvas.height=parseInt(imageTemp.height);

                                    var ctx=canvas.getContext("2d");
                                    ctx.drawImage(imageTemp, 0, 0);
                                    el.style.backgroundImage="url("+canvas.toDataURL()+")";
                                };

                                if (imageTemp.complete)
                                    imageTemp.onload();
                                */

                                var xhr=new XMLHttpRequest();

                                xhr.open(
                                    "get",
                                    strBackgroundImageURL,
                                    /*Asynchronous*/ false
                                );

                                xhr.overrideMimeType("text/plain; charset=x-user-defined");

                                xhr.send(null);

                                var strResponseContentType=xhr.getResponseHeader("Content-type").split(";")[0].replace(/[^a-z0-9\/-]/gi, "");
                                el.style.backgroundImage="url("+"data:"+strResponseContentType+";base64,"+base64Encode(xhr.responseText)+")";
                            }

                            if(el.nodeName=="A")
                            {
                                el.href="#";//TODO convert relative paths to absolute ones (keep URLs);
                                el.setAttribute("onclick", "return false;");//TODO: remove this when the above is fixed.
                            }
                            else if(el.nodeName=="FORM")
                            {
                                el.setAttribute("action", "");
                                el.setAttribute("onsubmit", "return false;");
                            }
                        }
                        catch(error)
                        {
                            //what can be done about it?
                        }
                    }
                });

                require("fs").write(output, page.content, "w");

                phantom.exit();
            }, 1000);
        }
    });
}