LINUX.ORG.RU

php-шный loadHTML неверно работает с JS

 ,


0

2

Пытаюсь загрузить следующий код в domDocument (код упрощён):

<html>
  <body>
    <div>
      <script type="text/javascript">
        <!--
        div.innerHTML = "<div><table><tr><td><a href='#'>close</a></td></tr></table></div>";
        //-->
      </script>
    </div>
  </body>
</html>

Затем делаю saveHTML, на выходе получается:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html>
  <body>
	<div>
	  <script type="text/javascript">
		<!--
		div.innerHTML = "<div><table><tr><td><a href='#'>close</script>
		</div>";
	    //--&gt;
</body></html>

Т.е. JS парсится как обычный HTML. В документации по loadHTML нет особых упоминаний, как можно управлять её работой. Оборачивание в //<![CDATA[ не помогает. В интернетах информации по проблеме крайне мало, самое подробное, что удалось найти: http://bytes.com/topic/php/answers/646507-problem-loading-html-containing-scr..., но это аж за 2007 год и без решения. Подозреваю, что я просто что-то упустил, но не понимаю что. Кто-нибудь сталкивался?

★★

Ответ на: комментарий от TDrive

Совсем не в тему. Смысл же не в том, чтобы просто вывести html, а в том, чтобы загрузить его, провести с ним манипуляции, а потом уже вывести. Соответственно, какие могут быть манипуляции, если он ломается на этапе загрузки.

SOmni ★★ ()
Ответ на: комментарий от SOmni

Загружаешь, проводишь манипуляции как с обычным текстом с помощью всяких сплитов и регэкспов и выводишь с помощью echo. не?
При этом ты будешь знать как именно обрабатывается текст, а не как сейчас «загружаю одно, на выводе другое, почему?»

TDrive ★★★★★ ()
Ответ на: комментарий от stevejobs

Так и не понял, что за неадекват по ссылке и что такое КСЖ.

TDrive ★★★★★ ()
Ответ на: комментарий от TDrive

Так можно делать только в очень простых случаях (и я так делаю, где это возможно), но здесь мне надо грузить десятки тысяч страниц размером до мегабайта, выбирать нужные теги, заменять, удалять. Короче, regexp для такого не подходит (удачи в построении regexp-а, который может сделать что-нибудь такое: $elements = $xpath->query(«//div[@id='footer']/ul[@class='links']/li»);)

SOmni ★★ ()
Ответ на: комментарий от SOmni

удачи в построении regexp-а, который может сделать что-нибудь такое: $elements = $xpath->query(«//div[@id='footer']/ul[@class='links']/li»);

что этот xpath запрос делает? просто не работал с этим, хочу сравнить с регэкспами.

TDrive ★★★★★ ()
Ответ на: комментарий от TDrive

А всё разобрался.
/<div.*?id=«footer».*?>.*?<ul.*?class=«links».*?><li.*?>.*?<\/li>.*?</ul>.*?<\/div>/
это просто пример, думаю можно и более точное составить.

но согласен что ваш способ удобнее.

TDrive ★★★★★ ()
Ответ на: комментарий от r_asian

Это ещё нахрен. Только хардкор, только <!-- -->

Более того, это тоже не нужно. Браузеры, не понимавшие тег script и выводившие его содержимое в виде текста, вымерли наверно ещё в прошлом тысячелетии.

Tigger ★★★★★ ()
Ответ на: комментарий от Tigger

Речь идёт не о браузерах, а о loadHTML, который мог бы пропустить текст внутри комментария, но не пропускает.

SOmni ★★ ()
Ответ на: комментарий от TDrive

В качестве домашнего задания поручаю тебе разработать тест, на котором этот регэксп зафэйлится, сколь более точно его не составляй. И это даже не говоря о том, что он не выполняет поставленную задачу.

SOmni ★★ ()

simple_html_dom с этой шнягой не работает?

anonymous ()
Ответ на: комментарий от SOmni

В loadHTML совершенно другая проблема, насколько я понимаю. Ругательства почему-то были на закрывающие теги внутри js. После разбивки этих тегов на части, всё работает как надо.

Tigger ★★★★★ ()
Ответ на: комментарий от SOmni

Очень толсто.
Это у тебя проблемы с решением твоей задачи, а не у меня. Я тебе предложил альтернативу и показал как составляются такие регэкспы. Не нравится, успехов разобраться с loadHTML.

TDrive ★★★★★ ()
Ответ на: комментарий от TDrive

Я тебе предложил альтернативу и показал как составляются такие регэкспы

Это не альтернатива, и такие регэкспы никак не составляются, потому что для решения общего случая их никак нельзя составить. Что, например, будет, если в указанном примере кавычки не двойные, а одинарные? А если где-то двойные, а где-то одинарные или вообще без кавычек? А если пробелы до или после =? Если html невалидный? А что если нужно сделать ещё и [position()=1]. Не говоря уже о том, что регэксп вернёт только первый li. Вот именно, что нужно разбираться с loadHTML (или аналогом), а не регэкспы городить.

SOmni ★★ ()
Ответ на: комментарий от SOmni

Всё что ты написали, можно описать регэкспами, причём это далеко не самая сложная задачка.

Если html невалидный?

Твой вариант даже js не может переварить так что... ))
Причём в случае регэкспов любая проблема легко решаема, а ты уже второй день разобраться не можешь.
И что будет быстрее работать тоже вопрос.

TDrive ★★★★★ ()
Ответ на: комментарий от Tigger

Любопытно. Оказывается, можно даже так не делать, а просто ставить пробел до или после закрывающего слэша и тоже будет работать. Вопрос в том, как будет потом такой html работать. Буду разбираться.

SOmni ★★ ()
Ответ на: комментарий от TDrive

Как часто тебе приходится парсить html/xml регэкспами? Невалидный html встречается повсеместно - один забытый закрывающий тэг или скобка и хана, парсер на регэкспах будет о такое спотыкаться постоянно, поддерживать его будет намного сложнее работы через DOM и в итоге всё равно придётся переписывать, поэтому, если надо, я и неделю потрачу, но зато потом сэкономлю. Короче, как перейдёшь от теории к практике - поймёшь.

SOmni ★★ ()
Ответ на: комментарий от SOmni

Кучу парсеров сайтов уже переписал для вытаскивания новостей или других данных, по пол года работают без проблем. Всё о чём ты говоришь тебе сможет объяснить любой человек хоть чуть чуть разбирающийся в регэкспах.

TDrive ★★★★★ ()
Ответ на: комментарий от SOmni

Пробел до или после слеша - это сразу явная ошибка в html-коде, с этим лучше не экспериментировать. А конкатенация строк в js - вполне нормальная вещь.

Tigger ★★★★★ ()
Ответ на: комментарий от TDrive

Моя задача сложнее вытаскивания данных. Как насчёт удаления поддеревьев? Прочитал текст по ссылке от stevejobs-а, мне нечего больше добавить к этому:

No matter how many times we say it, they won't stop coming every day... every hour even. It is a lost cause, which someone else can fight for a bit. So go on, parse HTML with regex, if you must. It's only broken code, not life and death.

Так что, используй, пока работает. Хочешь что-то доказать, попробуй построить выражение, которое покроет случаи, которые я привёл. А потом прогони его через что-нибудь вроде:

<div id="footer">
</div>
<div id="not_footer">
  <ul class="links">
    <li></li>
  </ul>
</div>
или
<div onclick='javascript: global_id="footer";'>
  <ul class="links">
    <li></li>
  </ul>
</div>
Ещё вопросы?

SOmni ★★ ()
Ответ на: комментарий от Tigger

Точно. Правда, в любом случае придётся писать какой-то анализатор, ведь тэги за пределами script трогать нельзя.

SOmni ★★ ()
Ответ на: комментарий от SOmni

В первом случае, то что я писал ранее, ничего не найдёт, как и должно быть.
Для второго нужно чутка поправить. Проблем не вижу.

TDrive ★★★★★ ()
Ответ на: комментарий от TDrive

В первом случае, то что я писал ранее, ничего не найдёт, как и должно быть.

Правда? А что помешает?

#!/usr/bin/perl
my $str = '<div id="footer"></div><div id="not_footer"><ul class="links"><li>hello</li></ul></div>';
if ($str =~ /<div.*?id="footer".*?>.*?<ul.*?class="links".*?><li.*?>(.*?)<\/li>.*?<\/ul>.*?<\/div>/) {
    print "passed: $1\n";
} else {
    print "failed\n";
}
:~$ ./1.pl
passed: hello

SOmni ★★ ()
Ответ на: комментарий от SOmni

Да точно ошибся.
Вот более грамотный вариант
#!/usr/bin/perl
use strict;
my $str = '<div id=«footer»></div><div id=«not_footer»><ul class=«links»><li>hello</li></ul></div>';
if ($str =~ m/<div.*?id=«footer».*?>(.*?)<\/div>/ && $1 =~ m/<ul.*?class=«links».*?>(.*?)<\/ul>/ && $1 =~ m/<li.*?>(.*?)<\/li>/) {
print «passed: $1\n»;
} else {
print «failed\n»;
}

Для второго варианта, если нужно только найти что то.
$str =~ s/on[a-z]*='.*?'//i;
Далее как и в первом варианте.

Если нужно заменить, не ломая изначальный код, то нужно посмотреть на возможный js и придумать что нибудь подходящее, по ситуации.
В ситуации которую ты привёл, достаточно в регэкспе перед id поставить пробел.

Да, регэкспы больше подходят для частных случаев. НО
1) Я знаю все случаи в которых мой регэксп может споткнуться.
2) Я могу их исправить если понадобится.
В отличие от этого DOMDocument() споткнулся о js, и единственное решение которое удалось найти за 2 дня это изменить изначальный текст о который спотыкается DOMDocument(). олололо
А сколько ещё таких сюрпризов может быть?
Что будет если встретится css, вставки на php или asp?

TDrive ★★★★★ ()
Ответ на: комментарий от TDrive

Вот более грамотный вариант

И тут внезапно оказывается, что если до <ul> что-то есть, то вполне годный html не проходит:

<div id="footer">
  <div>
  </div>
  <ul class="links">
    <li>hello</li>
  </ul>
</div>
:~$ ./1.pl
failed
И так до бесконечности ты будешь отлавливать все случаи, пока твой регэксп не обрастёт костылями со всех сторон, и это более невозможно будет поддерживать, и переписывание всего этого займёт не 2 дня. Плавали, знаем.

Для второго варианта, если нужно только найти что то.
$str =~ s/on[a-z]*='.*?'//i;

И тут мы спотыкаемся на onclick='javascript: var a=\'hello\'; id=«footer»;'
Ключевое тут " Я знаю все случаи в которых мой регэксп может споткнуться". Мои входные данные готовили 30 различных команд на протяжении многих лет, выискивать все возможные проблемы в десятках тысяч файлов - это жизни не хватит, проблема с тэгами в js на этом фоне - мелочь.

SOmni ★★ ()
Ответ на: комментарий от SOmni

проблема с тэгами в js на этом фоне - мелочь.

Проблемы с js это мелочь, а очередные неожиданные проблемы в тех местах где их не ожидаешь и очередные костыли для их решения уже не мелочь.
Регэкспы в этом плане надёжнее.

И так до бесконечности ты будешь отлавливать все случаи

Их не нужно отлавливать, нужно просто посмотреть на исходные данные и прогнать пару раз регэксп в целях теста. А не так что один придумывает проблему второй пишет регэксп, первый придумывает текст на котором этот регэксп споткнется. Так естественно до бесконечности можно).
А учитывая, что html структура источника входных данных как правило редко меняется, твои претензии к регэкспам выглядят очень смутно.

Мои входные данные готовили 30 различных команд на протяжении многих лет, выискивать все возможные проблемы в десятках тысяч файлов - это жизни не хватит.

Если сильно меняется структура DOM дерева то тебе в любом случае нужно будет это отлавливать. Я не знаю что там за входные данные и что с ними нужно сделать. Если приблизительно прикинуть, то какой нибудь парсер сайтов за пол года обрабатывает 200к+ html страниц. Так что количеством ты меня не удивил.

TDrive ★★★★★ ()
Ответ на: комментарий от SOmni

И ключевое слово тут «Я знаю как происходит обработка текста в моей программе а ты нет.»

TDrive ★★★★★ ()
Ответ на: комментарий от Deleted

Уже показывали. Так и не понял, есть там интересные мысли или нужно посмеяться над неадекватом, который на пол страницы раскопировал одну фразу?

TDrive ★★★★★ ()
Ответ на: комментарий от Deleted

Читай ещё раз. Парсить эту грамматику регэкспами нельзя.

Всё время парсил, а тут оказывается нельзя) эпично.
Я не говорю что регэкспы для этого подходят.
Просто хороший аналогов ещё найти нужно и во многих случаях регэксплов вполне хватает, это универсальное средство.

TDrive ★★★★★ ()
Ответ на: комментарий от TDrive

Всё время забивал гвозди микроскопом, а тут оказывается нельзя) эпично.
Я не говорю что микроскопы для этого подходят.
Просто хороший аналогов ещё найти нужно и во многих случаях микроскопов вполне хватает, это универсальное средство.

fixed

Tigger ★★★★★ ()
Ответ на: комментарий от Tigger

для забивания гвоздей как раз есть молоток, а для парсинга html?
DOMDocument() который качественно обрабатывает только сферический html в вакууме это хорошая замена регэкспам?

TDrive ★★★★★ ()
Ответ на: комментарий от TDrive

ССЗБ же :} Если у тебя данные случайны и приходят откуда-то извне, то в данном случае регэкспы ни разу не универсальны, т.к. могут сфейлиться. И на каждый такой случай ты будешь накручивать километры лапши в этот регэксп, пока не перестанешь совсем в нём разбираться.

Deleted ()
Ответ на: комментарий от TDrive

Их не нужно отлавливать, нужно просто посмотреть на исходные данные и прогнать пару раз регэксп в целях теста

Ну раз ты такой умный, вот тебе задача, приближенная к боевой: найти в html тэг div с id=«subtitle», а потом из исходного кода вырезать родительский элемент этого div со всем, что в нём есть. Почему так? Потому что у всех есть subtitle в какой-то обёртке, но у всех же и свой взгляд на то, как его оформить. Регэкспы соснут.

SOmni ★★ ()
Ответ на: комментарий от Deleted

ССЗБ же :}

У меня вроде нет проблем.

Если у тебя данные случайны и приходят откуда-то извне

Если данные случайны, то универсального средства в принципе нету.

Всё это можно сравнить например с парсерами yaml конфигов. Есть очень много библиотек для парсинга yaml, тем немение пару раз попадались yaml файлы на которых все библиотеки, которые я смог найти, спотыкались. Приходилось делать на регэспах. Не вижу в этом ничего страшного.

TDrive ★★★★★ ()
Ответ на: комментарий от SOmni

Не обязательно обрабатывать текст одним регэкспом или только регэкспами. Примеры я тебе уже показал, дальше включай мозг и решай свои задачки сам.

TDrive ★★★★★ ()
Ответ на: комментарий от TDrive

Я включил мозг и стал использовать DOMDocument вместо регэкспов, потому что к обозначенной мной задаче на регэкспах не подъехать совсем никак, примеры твои мимо.

SOmni ★★ ()
Ответ на: комментарий от TDrive

Под случайными понимаются, всё же, корректные данные.

>Всё это можно сравнить например с парсерами yaml конфигов.
>тем немение пару раз попадались yaml файлы на которых все библиотеки, которые я смог найти, спотыкались

Тут обратная ситуация. Нормальный парсер всегда сработает, а твои регэкспы будут спотыкаться.

Deleted ()
Ответ на: комментарий от Deleted

Под случайными понимаются, всё же, корректные данные.

Рандомная структура DOM дерева это не корректные данные?

Нормальный парсер всегда сработает, а твои регэкспы будут спотыкаться.

А кто с этим спорит? Специализированное решение для какой то задачи априори должно быть лучше чем общее решение.
Только ты найди нормальный парсер, который не будет спотыкаться о html переполненный css, js...

TDrive ★★★★★ ()
Ответ на: комментарий от TDrive

Рандомная структура DOM дерева это не корректные данные?

Что?

Специализированное решение для какой то задачи априори должно быть лучше чем общее решение.

Регэксп в данном случае под общее не подходит, т.к. работает только с определённым набором входных данных. Как быть?

Только ты найди нормальный парсер, который не будет спотыкаться о html переполненный css, js...

У ТСа обычный HTML, парсится нормальными парсерами.

Deleted ()
Ответ на: комментарий от Deleted

Что?

Структура html, какой элемент в каком расположен.

Регэксп в данном случае под общее не подходит, т.к. работает только с определённым набором входных данных. Как быть?

Что значит с определённым набором входных данных? А всё остальное без набора входных данных работает?

У ТСа обычный HTML, парсится нормальными парсерами.

У ТСа парсер споткнулся об простенький js и единственное решение которое нашли это изменить входные данные, что бы они подходили специально для парсера. Это огромный фейл. Собственно по этому он и создал тред, неожиданно да?

TDrive ★★★★★ ()
Ответ на: комментарий от TDrive

>Структура html, какой элемент в каком расположен.
И? Парсер разберёт правильно в любом случае, регэксп — нет. О чём и речь.

>Что значит с определённым набором входных данных? А всё остальное без набора входных данных работает?
Те, которые ты предусмотрел. Это сложнее, чем кажется.

>У ТСа парсер споткнулся об простенький js
У ТСа ПХП, это уже совсем другая история.

Deleted ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.