Как получить исходный код innerHTML без содержимого, сгенерированного Javascript?

Можно ли каким-то образом получить исходный HTML-код без изменений, внесенных обработанным Javascript? Например, если я делаю:

<div id="test">
    <script type="text/javascript">document.write("hello");</script>
</div>

If I do:

alert(document.getElementById('test').innerHTML);

это показывает:

<script type="text/javascript">document.write("hello");</script>hello

Проще говоря, я бы хотел, чтобы alert показывало только:

<script type="text/javascript">document.write("hello");</script>

без конечного hello (результат обработанного скрипта).


person Marco Demaio    schedule 09.12.2010    source источник
comment
В каком браузере вы это тестировали? В FF4b7 и Chrome 8 я получаю <script type="text/javascript">document.write("hello");</script>hello   -  person Marcel Korpel    schedule 09.12.2010
comment
@Marcel: IE7 и IE8 (также IE6)   -  person Marco Demaio    schedule 09.12.2010
comment
@Marcel: я обновил вопрос, я забыл кое-что. Простите за это.   -  person Marco Demaio    schedule 09.12.2010
comment
И я боюсь, вы не знаете заранее, какой текст добавляется, не так ли?   -  person Marcel Korpel    schedule 09.12.2010
comment
@ Марсель: что ты имеешь в виду? В примере добавлен текст hello, потому что он создан document.write("hello"). Я ищу решение общего назначения, не зависящее от кода внутри DIV, что-то, что всегда возвращает исходный код без изменений, сделанных движком Javascript.   -  person Marco Demaio    schedule 09.12.2010
comment
Да, этого я и опасался. Но когда элементы добавляются в DOM, невозможно отличить исходную разметку от динамически добавленных элементов/узлов (если только вы не пометите их как таковые), по крайней мере, насколько я знаю.   -  person Marcel Korpel    schedule 09.12.2010
comment
Зачем вам это нужно? Я уверен, что есть обходной путь к тому, что вы пытаетесь сделать, если вы скажете нам, что это такое.   -  person Sasha Chedygov    schedule 16.12.2010
comment
@musicfreak: допустим, у вас есть простая CMS, innerHTML для DIV на вашей странице может быть изменен конечным пользователем с помощью javascript, а затем, когда он сохраняет страницу, содержимое innerHTML каждого DIV отправляется на сервер для хранения в БД. Когда innerHTML содержит ‹script›, innerHTML будет привинчен и сохранен в БД.   -  person Marco Demaio    schedule 18.12.2010
comment
Это немного хак, но почему бы просто не загрузить текущий URL-адрес с помощью AJAX? Вы должны получить исходный код с парой предостережений (данные POST будут игнорироваться, а любые случайные или зависящие от времени данные могут отличаться)   -  person Basic    schedule 10.07.2014


Ответы (9)


Я не думаю, что есть простое решение просто «захватить исходный код», так как это должно быть что-то, что предоставляется браузером. Но, если вы хотите сделать это только для части страницы, у меня есть для вас обходной путь.

Вы можете обернуть интересующий раздел внутри «замороженного» скрипта:

<script id="frozen" type="text/x-frozen-html">

Атрибут type я только что придумал, но он заставит браузер игнорировать все внутри него. Затем вы добавляете еще один тег сценария (на этот раз правильный javascript) сразу после этого — сценарий «оттаивания». Этот сценарий оттаивания получит замороженный сценарий по идентификатору, возьмет текст внутри него и выполнит document.write, чтобы добавить фактическое содержимое на страницу. Всякий раз, когда вам нужен исходный код, он по-прежнему фиксируется в виде текста внутри замороженного сценария.

И вот оно. Недостатком является то, что я бы не стал использовать это для всей страницы... (SEO, подсветка синтаксиса, производительность...), но это вполне приемлемо, если у вас есть особые требования к части страницы.


Изменить: вот пример кода. Кроме того, как правильно указал @FlashXSFX, любые теги сценария в замороженном сценарии необходимо экранировать. Итак, в этом простом примере я создам тег <x-script> для этой цели.

<script id="frozen" type="text/x-frozen-html">
   <div id="test">
      <x-script type="text/javascript">document.write("hello");</x-script>
   </div>
</script>
<script type="text/javascript">
   // Grab contents of frozen script and replace `x-script` with `script`
   function getSource() {
      return document.getElementById("frozen")
         .innerHTML.replace(/x-script/gi, "script");
   }
   // Write it to the document so it actually executes
   document.write(getSource());
</script>

Теперь, когда вам нужен источник:

alert(getSource());

См. демонстрацию: http://jsbin.com/uyica3/edit.

person David Tang    schedule 10.12.2010
comment
Не могли бы вы показать короткий фрагмент кода. Я не понимаю. - person Marco Demaio; 10.12.2010
comment
Я подумал, что это действительно может сработать, поэтому я попробовал. Основная проблема, которую я видел, заключалась в том, что вы пытаетесь поместить теги script внутри замороженного тега. (Я использовал фрагменты оригинального плаката) Вам нужно будет сделать некоторое экранирование и замену строк, чтобы заставить это работать. - person FlashXSFX; 10.12.2010

Простой способ — снова получить его с сервера. Скорее всего он будет в кеше. Вот мое решение с использованием jQuery.get(). Он берет исходный uri страницы и загружает данные с помощью вызова ajax:

$.get(document.location.href, function(data,status,jq) {console.log(data);})

Это напечатает исходный код без javascript. Он не выполняет никакой обработки ошибок!

Если вы не хотите использовать jQuery для получения исходного кода, обратитесь к ответу на этот вопрос: Как сделать вызов ajax без jquery?

person Michael_Scharf    schedule 08.08.2014
comment
Отличная идея! У меня была проблема, когда парсинг сайта без веб-браузера был невозможен, но в то же время сайт уничтожал некоторые данные (которые мне были нужны) после загрузки. При таком подходе медленная и неэффективная загрузка выполняется один раз, тогда как фактическое чтение html сайта очень эффективно выполняется из той же сессии браузера, что решает сразу две проблемы. - person Christian; 18.04.2020

Не могли бы вы отправить запрос Ajax на ту же страницу, на которой вы сейчас находитесь, и использовать результат в качестве исходного HTML? Это надежно при правильных условиях, поскольку вы буквально получаете исходный HTML-документ. Однако это не сработает, если страница меняется при каждом запросе (с динамическим содержимым) или если по какой-либо причине вы не можете сделать запрос на эту конкретную страницу.

person Sasha Chedygov    schedule 16.12.2010

Подход грубой силы

var orig = document.getElementById("test").innerHTML;
alert(orig.replace(/<\/script>[.\n\r]*.*/i,"</script>"));

РЕДАКТИРОВАТЬ:

Это может быть лучше

var orig = document.getElementById("test").innerHTML + "<<>>";
alert(orig.replace( /<\/script>[^(<<>>)]+<<>>/i, "<\/script>"));
person Jules    schedule 10.12.2010
comment
Помимо того факта, что вы забыли косую черту replace(/<\/script>[.\n\r]*.*/i,"<\/script>") и что я не понимаю, почему вы поставили точку внутри [.\n\r], в любом случае это может быть хорошей попыткой и возможным подходом, поэтому +1. В любом случае, это все еще очень специфично, т. Е. Если добавить простую новую строку document.write("hello\nchina");, ваше регулярное выражение заменит только hello и будет жить china там, где оно есть. - person Marco Demaio; 10.12.2010
comment
@Марко, спасибо за исправление регулярного выражения. Как я уже сказал, это подход грубой силы (не элегантный/общий). - person Jules; 14.12.2010

Если вы переопределите document.write, чтобы добавить некоторые идентификаторы в начало и конец всего, что записывается в документ сценарием, вы сможете удалить эти записи с помощью регулярного выражения.

Вот что я придумал:

    <script type="text/javascript" language="javascript">
        var docWrite = document.write;
        document.write = myDocWrite;

        function myDocWrite(wrt) {
            docWrite.apply(document, ['<!--docwrite-->' + wrt + '<!--/docwrite-->']);
        }
    </script>

Добавил ваш пример где-то на странице после исходного скрипта:

    <div id="test">
        <script type="text/javascript">     document.write("hello");</script>
    </div>

Затем я использовал это, чтобы предупредить о том, что было внутри:

    var regEx = /<!--docwrite-->(.*?)<!--\/docwrite-->/gm;
    alert(document.getElementById('test').innerHTML.replace(regEx, ''));
person FlashXSFX    schedule 10.12.2010
comment
Пожалуйста, будьте более конкретными. Исходный пост спрашивал, как использовать document.write и при этом получить исходный код. - person FlashXSFX; 30.11.2011

Если вам нужен первоначальный документ, вам нужно будет получить его снова. Нет никакого способа обойти это. Если бы не document.write() (или аналогичный код, который будет выполняться во время процесса загрузки), вы могли бы загрузить innerHTML исходного документа в память при загрузке/domready, прежде чем изменять его.

person Stan Rogers    schedule 10.12.2010

Я не могу придумать решение, которое работало бы так, как вы спрашиваете. Единственный код, к которому у Javascript есть доступ, — это DOM, который содержит результат только после обработки страницы.

Самое близкое, что я могу придумать для достижения того, чего вы хотите, - это использовать Ajax для загрузки новой копии необработанного HTML для вашей страницы в строку Javascript, и в этот момент, поскольку это строка, вы можете делать с ней все, что хотите, включая отображение это в окне предупреждения.

person Spudley    schedule 10.12.2010

Хитрый способ — использовать тег <style> для шаблона. Так что вам больше не нужно переименовывать x-script.

console.log(document.getElementById('test').innerHTML);
<style id="test" type="text/html+template">
    <script type="text/javascript">document.write("hello");</script>
</style>

Но мне не нравится это уродливое решение.

person tsh    schedule 02.01.2018

Я думаю, вы хотите пройти через узлы DOM:

var childNodes = document.getElementById('test').childNodes, i, output = [];

for (i = 0; i < childNodes.length; i++)
    if (childNodes[i].nodeName == "SCRIPT")
        output.push(childNodes[i].innerHTML);

return output.join('');
person Marcel Korpel    schedule 09.12.2010