php – 使用已完成渲染并完成运行脚本的页面的当前样式(可能是内联的)获取HTML

前端之家收集整理的这篇文章主要介绍了php – 使用已完成渲染并完成运行脚本的页面的当前样式(可能是内联的)获取HTML前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我需要使用服务器端应用程序获取已完成呈现并完成运行脚本的页面的当前样式(可能是内联)的 HTML(仅提供URL)(没有额外信息,如cookie,没有POST,没有阻碍形式)等).

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

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

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

如果它可以使用纯PHP来完成它将是一个加号(虽然我怀疑它,我没有发现任何有趣的东西).

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

编辑2
示例输入HTML:

  1. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
  2. <html>
  3. <head>
  4. <title></title>
  5.  
  6. <Meta http-equiv="Content-Type" content="text/html;charset=utf-8">
  7.  
  8. <link rel="stylesheet" type="text/css" href="/css/example.css">
  9. <script type="text/javascript" src="/javascript/example.js"></script>
  10.  
  11. <script type="text/javascript">
  12. window.addEventListener("load",function(event){
  13. document.title="New title";
  14.  
  15. document.getElementById("pic_0").style.border="0px";
  16. }
  17. );
  18. </script>
  19. <style type="text/css">
  20. p{
  21. color: blue;
  22. }
  23. </style>
  24. </head>
  25. <body>
  26. <p>Hello world!</p>
  27. <p>
  28. <img
  29. alt=""
  30. style="border: 1px"
  31. id="pic_0"
  32. src="http://linuxgazette.net/144/misc/john/helloworld.png"
  33. >
  34. </p>
  35. </body>
  36. </html>

输出示例:

  1. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
  2. <html>
  3. <head>
  4. <title>New title</title>
  5.  
  6. <Meta http-equiv="Content-Type" content="text/html;charset=utf-8">
  7.  
  8. <style type="text/css">
  9. b{font-weight: bold}
  10. </style>
  11.  
  12. <style type="text/css">
  13. p{
  14. color: blue;
  15. }
  16. </style>
  17. </head>
  18. <body>
  19. <p>Hello world!</p>
  20. <p>
  21. <img
  22. alt=""
  23. style="border: 0px"
  24. id="pic_0"
  25. src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoBAMAAAB+0KVeAAAAK3RFWHRDcmVhdGlvbiBUaW1lAFYgMzEgYXVnLiAyMDEyIDE3OjU4OjU1ICswMjAwWMdbPwAAAAd0SU1FB9wIHw8ABeoUyU4AAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAEZ0FNQQAAsY8L/GEFAAAABlBMVEX///8AAABVwtN+AAAAXklEQVR42uWQUQ6AMAhD6Q3a+19WqsawwMf+NLEfy3iDlC7idTGQp/YglFAsUMqSwjlQOhN3mIMTHDq70SeEWBbt0EG8POWkDySvmCh/SssvNfwIfb+hFmgjFKPf6gDQBAQ368m09AAAAABJRU5ErkJggg=="
  26. >
  27. </p>
  28. </body>
  29. </html>

请注意< title>标签已更改,边框如何:1px变为border:0px,图像URL如何转换为data URI.

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

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

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

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

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

在过去2-3天的业余时间里,我为我的问题编写了解决方案,它完美地涵盖了所有要求.我还没有找到一个不起作用的网页.

.

用法,命令行:

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

.

允许Javascript在其他所有内容加载后运行n秒,它甚至可以用于完全由javascript生成的网页.

.

笔记:

>在可能的情况下,XHR加载资源优先于HTML5的画布渲染,因为文件大小减小,质量损失(重用原始文件比任何东西都要好).
>< link>和< img>标签保持在原位,数据:URI分别在href和src属性中使用,而不是URL.对于background-image也是如此,它在所有DOM节点上使用getComputedStyle()读取.
>< script>标记和事件处理程序属性删除.
>< link> rel =“alternative”的标签也被删除(也许它们不应该被删除,而是固定在绝对URL中,如果是相对的).
>< iframe>目前尚未处理,其src属性设置为about:blank.

.

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

.

save_as_html.js内容

  1. //https://stackoverflow.com/a/12256190/584490
  2.  
  3. var page = require('webpage').create();
  4. page.onConsoleMessage = function (msg) { console.log(msg); };
  5.  
  6. var system = require('system');
  7. var address,output,size;
  8.  
  9.  
  10. if (system.args.length!=3)
  11. {
  12. console.log('Usage: save_as_html.js URL filename');
  13. phantom.exit(1);
  14. }
  15. else
  16. {
  17. address = system.args[1];
  18. output = system.args[2];
  19.  
  20. page.viewportSize = {
  21. width: 1680,height: 1050,};
  22.  
  23. //SECURITY_ERR: DOM Exception 18: An attempt was made to break through the security policy of the user agent.
  24. //Enable cross site scripting:
  25. page.settings.XSSAuditingEnabled=false;
  26. page.settings.localToRemoteUrlAccessEnabled=true;
  27. page.settings.webSecurityEnabled=false;
  28.  
  29. 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";
  30. page.settings.ignoreSslErrors=true;
  31.  
  32. page.open(address,function (status){
  33. if (status!=='success')
  34. {
  35. console.log("Unable to load URL,returned status: "+status);
  36. phantom.exit(1);
  37. }
  38. else
  39. {
  40. window.setTimeout(function (){
  41. page.evaluate(function(){
  42. var nodeList=document.getElementsByTagName("*");
  43.  
  44. var arrEventHandlerAttributes=[
  45. "onblur","onchange","onclick","ondblclick","onfocus","onkeydown","onkeyup","onkeypress","onload","onmousedown","onmousemove","onmouSEOut","onmouSEOver","onmouseup","onreset","onselect","onsubmit","onunload"
  46. ];
  47.  
  48.  
  49. //https://stackoverflow.com/a/7372816/584490
  50. var base64Encode=function(str)
  51. {
  52. var CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  53. var out = "",i = 0,len = str.length,c1,c2,c3;
  54. while (i < len) {
  55. c1 = str.charCodeAt(i++) & 0xff;
  56. if (i == len) {
  57. out += CHARS.charAt(c1 >> 2);
  58. out += CHARS.charAt((c1 & 0x3) << 4);
  59. out += "==";
  60. break;
  61. }
  62. c2 = str.charCodeAt(i++);
  63. if (i == len) {
  64. out += CHARS.charAt(c1 >> 2);
  65. out += CHARS.charAt(((c1 & 0x3) << 4) | ((c2 & 0xF0) >> 4));
  66. out += CHARS.charAt((c2 & 0xF) << 2);
  67. out += "=";
  68. break;
  69. }
  70. c3 = str.charCodeAt(i++);
  71. out += CHARS.charAt(c1 >> 2);
  72. out += CHARS.charAt(((c1 & 0x3) << 4) | ((c2 & 0xF0) >> 4));
  73. out += CHARS.charAt(((c2 & 0xF) << 2) | ((c3 & 0xC0) >> 6));
  74. out += CHARS.charAt(c3 & 0x3F);
  75. }
  76. return out;
  77. };
  78.  
  79.  
  80. for(var n=nodeList.length-1; n>0; n--)
  81. {
  82. try
  83. {
  84. var el=nodeList[n];
  85.  
  86. if(el.nodeName=="IMG" && el.src.substr(0,5)!="data:")
  87. {
  88. /*var canvas=document.createElement("canvas");
  89.  
  90. canvas.width=parseInt(el.width);
  91. canvas.height=parseInt(el.height);
  92.  
  93. var ctx=canvas.getContext("2d");
  94. ctx.drawImage(el,0);
  95. el.src=canvas.toDataURL();*/
  96.  
  97. var xhr=new XMLHttpRequest();
  98.  
  99. xhr.open(
  100. "get",el.src,/*Asynchronous*/ false
  101. );
  102.  
  103. xhr.overrideMimeType("text/plain; charset=x-user-defined");
  104.  
  105. xhr.send(null);
  106.  
  107. var strResponseContentType=xhr.getResponseHeader("Content-type").split(";")[0].replace(/[^a-z0-9\/-]/gi,"");
  108. el.src="data:"+strResponseContentType+";base64,"+base64Encode(xhr.responseText);
  109. }
  110. else if(el.nodeName=="LINK")
  111. {
  112. if(el.rel=="alternate")
  113. {
  114. el.parentNode.removeChild(el);
  115. }
  116. else if(el.href.substr(0,5)!="data:")
  117. {
  118. var xhr=new XMLHttpRequest();
  119.  
  120. xhr.open(
  121. "get",el.href,/*Asynchronous*/ false
  122. );
  123.  
  124. xhr.overrideMimeType("text/plain; charset=x-user-defined");
  125.  
  126. xhr.send(null);
  127.  
  128. //var strResponseContentType=xhr.getResponseHeader("Content-type").split(";")[0].replace(/[^a-z0-9\/-]/gi,"");
  129. //el.href="data:"+strResponseContentType+";base64,"+base64Encode(xhr.responseText);
  130. el.href="data:"+el.type+";base64,"+base64Encode(xhr.responseText);
  131. }
  132.  
  133. continue;
  134. }
  135. else if(el.nodeName=="SCRIPT")
  136. {
  137. el.parentNode.removeChild(el);
  138.  
  139. continue;
  140. }
  141. else if(el.nodeName=="IFRAME")
  142. {
  143. el.src="about:blank";
  144.  
  145. continue;
  146. }
  147.  
  148. for(var z=arrEventHandlerAttributes.length-1; z>=0; z--)
  149. el.removeAttribute(arrEventHandlerAttributes[z]);
  150.  
  151. var strBackgroundImageURL=window.getComputedStyle(el).getPropertyValue("background-image").replace("/[\s]/g","");
  152. if(strBackgroundImageURL.substr(0,4)=="url(" && strBackgroundImageURL.substr(4,5)!="data:")
  153. {
  154. strBackgroundImageURL=strBackgroundImageURL.substr(4,strBackgroundImageURL.length-5);
  155.  
  156. /*var imageTemp=document.createElement("img");
  157. imageTemp.src=strBackgroundImageURL;
  158.  
  159. imageTemp.onload=function(e){
  160. var canvas=document.createElement("canvas");
  161.  
  162. canvas.width=parseInt(imageTemp.width);
  163. canvas.height=parseInt(imageTemp.height);
  164.  
  165. var ctx=canvas.getContext("2d");
  166. ctx.drawImage(imageTemp,0);
  167. el.style.backgroundImage="url("+canvas.toDataURL()+")";
  168. };
  169.  
  170. if (imageTemp.complete)
  171. imageTemp.onload();
  172. */
  173.  
  174. var xhr=new XMLHttpRequest();
  175.  
  176. xhr.open(
  177. "get",strBackgroundImageURL,"");
  178. el.style.backgroundImage="url("+"data:"+strResponseContentType+";base64,"+base64Encode(xhr.responseText)+")";
  179. }
  180.  
  181. if(el.nodeName=="A")
  182. {
  183. el.href="#";//TODO convert relative paths to absolute ones (keep URLs);
  184. el.setAttribute("onclick","return false;");//TODO: remove this when the above is fixed.
  185. }
  186. else if(el.nodeName=="FORM")
  187. {
  188. el.setAttribute("action","");
  189. el.setAttribute("onsubmit","return false;");
  190. }
  191. }
  192. catch(error)
  193. {
  194. //what can be done about it?
  195. }
  196. }
  197. });
  198.  
  199. require("fs").write(output,page.content,"w");
  200.  
  201. phantom.exit();
  202. },1000);
  203. }
  204. });
  205. }

猜你在找的PHP相关文章