Учусь парсить нужны советы

D
На сайте с 28.06.2008
Offline
1101
2091

Продолжаю учить пхп, теперь понемногу разбираюсь в парсинге. И я тут такое наговнокодил что самому страшно. У меня вот вопрос.

Если задача например следующая - забрать все абзацы на странице внутри id контент

Как мое творение можно оптимизировать и упростить?

<?php

$str = file_get_contents('http://code.mu/exercises/advanced/php/parsing/parsing-sajtov-regulyarnymi-vyrazeniyami-php/2/1.php');
//получаю блок контент
preg_match_all('~<div[^>]*?id="content"[^>]*?>(.+?)</div>~ms', $str, $matches2, PREG_SET_ORDER, 0);
//убираю лишнее
unset($matches2[0][0]);

//получаю все абзацы внутри контента
preg_match_all('~<p[^>]*?>(.*)</p>~mUs', $matches2[0][1], $matches3, PREG_SET_ORDER, 0);
//убираю лишнее
foreach ($matches3 as $lishnee){
unset($lishnee[0]);
var_dump($lishnee);
}
Samail
На сайте с 10.05.2007
Offline
361
#1
Dram:
preg_match_all('~<div[^>]*?id="conten

Зачем preg_match_all если такой блок будет всего один?

Апокалипсис
На сайте с 02.11.2008
Offline
391
#2

Для отладки регулярок очень рекомендую сервис: https://regex101.com/

Записки нищего (http://zapiskinishego.ru) - мой личный блог Услуги php программиста. Очень нужна любая работа. Не покупают? Поведенческий аудит интернет-магазина за 5000 руб. (/ru/forum/990312)
Samail
На сайте с 10.05.2007
Offline
361
#3
Dram:
(.+?)</div>~

Если внутри этого блока будет ещё один блок то захватится только то что идёт до закрывающего тега вложенного блока.

D
На сайте с 28.06.2008
Offline
1101
#4

Немного не правильно поставил вопрос.

Интересует - логика то правильная?

Сначала вычленяем нужный див, затем в нем ищем абзацы?

Итого две регулярки.

Или можно проще? Это просто моя первая попытка...

---------- Добавлено 15.05.2019 в 22:53 ----------

Samail:
Если внутри этого блока будет ещё один блок то захватится только то что идёт до закрывающего тега вложенного блока.

А как этого избежать?

edogs software
На сайте с 15.12.2005
Offline
775
#5

Dram,

Это вряд ли в тематике Вашего курса, но все же

$t='http://code.mu/exercises/advanced/php/parsing/parsing-sajtov-regulyarnymi-vyrazeniyami-php/2/1.php';
$doc = new DOMDocument();
$doc->loadHTMLFile($t);
$doc->normalizeDocument();
$res=$doc->getElementById('content')->getElementsByTagName('p');
$n=array();
foreach($res as $p) $n[]=$doc->saveHTML($p);
var_dump($n);

Регулярки использовать для парсинга в принципе хорошо и правильно (сами предпочитаем), но dom дерево имеет свои плюсы (простота).

Разработка крупных и средних проектов. Можно с криптой. Разумные цены. Хорошее качество. Адекватный подход. Продаем lenovo legion в спб, дешевле магазинов, новые, запечатанные. Есть разные. skype: edogssoft
_
На сайте с 24.03.2008
Offline
381
#6

Готовые парсеры парсят обычно неплохо.

Но в инете редко встретишь валидный документ...

И есть еще одна неприятная проблема: время. Сейчас, некоторые, генерируют html размером в сотни и даже тысячи килобайт. И распарсивать его целиком немного долго и геморно. Т.е. дело доходило до того, что на обработку одного документа по несколько секунд требовалось...

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

Регулярки не использую. Менее удобно отлаживать.

D
На сайте с 28.06.2008
Offline
1101
#7

edogs, спасибо за пример более элегантного способа. Начал его изучать плотнее. Решил попробовать вытащить абзацы с нужным классом и получил ошибку, почему?

$res=$doc->getElementById('content')->getElementsByClassName('www');

Fatal error: Uncaught Error: Call to undefined method DOMElement::getElementsByClassName() in C:\OSPanel\domains\localhost\index.php on line 58

( ! ) Error: Call to undefined method DOMElement::getElementsByClassName() in C:\OSPanel\domains\localhost\index.php on line 58

edogs software
На сайте с 15.12.2005
Offline
775
#8
Dram:
edogs, спасибо за пример более элегантного способа. Начал его изучать плотнее. Решил попробовать вытащить абзацы с нужным классом и получил ошибку, почему?

Fatal error: Uncaught Error: Call to undefined method DOMElement::getElementsByClassName() in C:\OSPanel\domains\localhost\index.php on line 58
( ! ) Error: Call to undefined method DOMElement::getElementsByClassName() in C:\OSPanel\domains\localhost\index.php on line 58

Потому что там нет такой функции. https://www.php.net/manual/ru/book.dom.php - тут смотрите что есть.

Для задач выбора класса и/или вообще более сложных выборов можно использовать xpath


$t='http://code.mu/exercises/advanced/php/parsing/parsing-sajtov-regulyarnymi-vyrazeniyami-php/2/1.php';
$doc = new DOMDocument();
$doc->loadHTMLFile($t);
$doc->normalizeDocument();
$xpath=new DOMXPath($doc);
$resX=$xpath->query('//*[@class="www"]');
$nX=array();
foreach($resX as $www) $nX[]=$doc->saveHTML($www);
var_dump($nX);

Обратите внимание - "ссылка 4" тут нет, ибо валидность.

Так же советуем (если тематика интересна) посмотреть на альтернативные классы html парсеров, не встроенных в php, они зачастую поинтереснее. С другой стороны на данном этапе можете не углубляться, тут важно знать сам факт возможности парсить не просто строковыми функциями, а через разбор dom дерева.

D
На сайте с 28.06.2008
Offline
1101
#9

Большое спасибо!

lutskboy
На сайте с 22.11.2013
Offline
170
#10

для етого есть xpath. simple html dom parser. pquery

Авторизуйтесь или зарегистрируйтесь, чтобы оставить комментарий