【问题标题】:How to use PHP DomDocument when script elements contain HTML?当脚本元素包含 HTML 时如何使用 PHP DomDocument?
【发布时间】:2018-12-21 23:12:15
【问题描述】:

我正在尝试下载一个站点以供离线查看,这需要我进行一些 DOM 操作(相信我,wget 只是没有做我需要做的事情......)。

我发现包含带有异常文本内容的标签的网页正在关闭 saveHTML

对于某些 url,如果我使用 curl 读取页面并输出为

echo $contents;

那么一切都很好。

例如,页面的某个部分包含以下来源:

<div id="area2516" class="component interaction_component float-none clear-none ">
    <div id="area2516">
        <script type="text/javascript">
            window.bm = window.bm || {};
            bm.data = bm.data || [];
            bm.data['area2516'] = {};
        </script>

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

    <script class="main-template" type="text/x-handlebars-template">
            <div class="content_area">
                <div class="bg_image cf"></div>
                    {{#each rollovers}}
                <div class="rollover_content" style="left: {{x}}; top: {{y}}; display: none;" data-rollover-id="{{id}}">
                    {{{this.content}}}
                </div>
                {{/each}}
                </div>
                <div class="rollover_links">
                    <ul>
                        {{#each rollovers}}
                        <li>
                            <a class="rollover_link" href="#" data-rollover-id="{{id}}">
                                {{{link}}}
                            </a>
                        </li>
                        {{/each}}
                    </ul>
                </div>
        </script>


        <script type="text/javascript">
            bm.data['area2516'].assets = {};
            bm.data['area2516'].initial_json = '';
        </script>

从上面 curl 响应后的回声中可以看出。

现在,如果我这样做

$doc = new DOMDocument();
@$doc->loadHTML($contents);
$xpath = new DOMXpath($doc);
echo $doc->saveHTML();

HTML 搞砸了,所以上面现在变成了这样:

<div id="area2516" class="component interaction_component float-none clear-none ">
<div id="area2516">
    <script type="text/javascript">
        window.bm = window.bm || {};
        bm.data = bm.data || [];
        bm.data['area2516'] = {};
    </script>
    <link rel="stylesheet" type="text/css" href="/somecss.css"> . 
    <script type="text/javascript" src="/somejs.js"></script>
    <script class="main-template" type="text/x-handlebars-template">
        <div class="content_area">
            <div class="bg_image cf">
    </script>
            </div>
            {{#each rollovers}}
            <div class="rollover_content" style="left: {{x}}; top: {{y}}; display: none;" data-rollover-id="{{id}}">
              {{{this.content}}}
            </div>
          {{/each}}
        </div>
        <div class="rollover_links">
          <ul>
            {{#each rollovers}}
              <li>
                <a class="rollover_link" href="#" data-rollover-id="{{id}}">
                  {{{link}}}
                </a>
              </li>
            {{/each}}
          </ul></div>
<script type="text/javascript">
        bm.data['area2516'].assets = {};
        bm.data['area2516'].initial_json = '';
      </script>

对不起,这个新编辑器很烦人。关键是,您可以看到一些相当大的差异,但我不确定 saveHTML 是如何导致对源代码进行修改的。我怀疑这与编码以及模板系统使用的这些双括号和三括号的特殊性有关,但是尽管尝试使用各种编码参数,但我得到了相同的结果。然后我想可能与特殊字符、转义有关,但我只是不确定需要什么函数来阻止 saveHTML 弄乱输出。

想法?

谢谢

【问题讨论】:

  • 看起来很精简的 SPA JS 站点,可能运行 Vue - 我想我已经看到他们在模板上使用 Mustache 语法。幸运的是,模板引擎已被移植到基本上所有东西,你会发现它在这里:mustache.github.io

标签: php html dom domdocument


【解决方案1】:

输入甚至不像HTML,而是像Twig(或类似的)模板......

需要先通过模板引擎推送,才能得到HTML的输出;

除非通过(array) $rollovers ...这肯定不会产生预期的结果。

如果这些不是您自己的模板文件,您可能下载了错误的URL ...

另一方的人忘记阻止对模板的访问。

【讨论】:

  • 也许它与 loadHTML 与 loadXML 有关?据我所知,模板系统是 javascript Handlebars。我认为如果我可以让 DOMDocument 工具保持所有内容不变,除了我正在修改的 src 和 href 属性,该站点将为我在本地加载。谢谢,布赖恩
【解决方案2】:

根据 HTML 4 规范,您不能将任意文本放入 &lt;script&gt; 元素中。 (尽管这个is possible in HTML 5,PHP 中包含的libxml 解析器并不是那么新。)

如果您正确地转义了元素的内容,您的代码应该可以按预期工作。

$content = <<< HTML
<div id="area2516" class="component interaction_component float-none clear-none ">
    <div id="area2516">
        <script type="text/javascript">
            window.bm = window.bm || {};
            bm.data = bm.data || [];
            bm.data['area2516'] = {};
        </script>

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

    <script class="main-template" type="text/x-handlebars-template">
            &lt;div class="content_area"&gt;
                &lt;div class="bg_image cf"&gt;&lt;/div&gt;
                    {{#each rollovers}}
                &lt;div class="rollover_content" style="left: {{x}}; top: {{y}}; display: none;" data-rollover-id="{{id}}"&gt;
                    {{{this.content}}}
                &lt;/div&gt;
                {{/each}}
                &lt;/div&gt;
                &lt;div class="rollover_links"&gt;
                    &lt;ul&gt;
                        {{#each rollovers}}
                        &lt;li&gt;
                            &lt;a class="rollover_link" href="#" data-rollover-id="{{id}}"&gt;
                                {{{link}}}
                            &lt;/a&gt;
                        &lt;/li&gt;
                        {{/each}}
                    &lt;/ul&gt;
                &lt;/div&gt;
        </script>


        <script type="text/javascript">
            bm.data['area2516'].assets = {};
            bm.data['area2516'].initial_json = '';
        </script>
HTML;
$doc = new DOMDocument();
$doc->loadHTML($content, LIBXML_HTML_NODEFDTD|LIBXML_HTML_NOIMPLIED);
echo $doc->saveHTML();

输出如预期:

<div id="area2516" class="component interaction_component float-none clear-none ">
    <div id="area2516">
        <script type="text/javascript">
            window.bm = window.bm || {};
            bm.data = bm.data || [];
            bm.data['area2516'] = {};
        </script>

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

    <script class="main-template" type="text/x-handlebars-template">
            &lt;div class="content_area"&gt;
                &lt;div class="bg_image cf"&gt;&lt;/div&gt;
                    {{#each rollovers}}
                &lt;div class="rollover_content" style="left: {{x}}; top: {{y}}; display: none;" data-rollover-id="{{id}}"&gt;
                    {{{this.content}}}
                &lt;/div&gt;
                {{/each}}
                &lt;/div&gt;
                &lt;div class="rollover_links"&gt;
                    &lt;ul&gt;
                        {{#each rollovers}}
                        &lt;li&gt;
                            &lt;a class="rollover_link" href="#" data-rollover-id="{{id}}"&gt;
                                {{{link}}}
                            &lt;/a&gt;
                        &lt;/li&gt;
                        {{/each}}
                    &lt;/ul&gt;
                &lt;/div&gt;
        </script>


        <script type="text/javascript">
            bm.data['area2516'].assets = {};
            bm.data['area2516'].initial_json = '';
        </script></div></div>

请注意,您的 HTML 在其他方面无效;重复 id 属性和缺少结束元素。

【讨论】:

  • 不确定如何仅针对脚本内部内容以这种方式转义字符,但我遇到了这个:stackoverflow.com/questions/4029341/…,它似乎正在工作......一旦我有需要测试以确认页面的其余部分准备检查。谢谢
猜你喜欢
  • 2019-11-19
  • 1970-01-01
  • 1970-01-01
  • 2011-04-17
  • 2017-07-08
  • 1970-01-01
  • 1970-01-01
  • 2012-05-18
  • 2021-03-02
相关资源
最近更新 更多