Как быстро получить элемент внутри DOM интерфейса

Все вопросы касающиеся использования
программы можно задать здесь
Ответить
klipper
Сообщения: 6
Зарегистрирован: 26 дек 2018, 17:59

Как быстро получить элемент внутри DOM интерфейса

Сообщение klipper » 26 дек 2018, 18:34

Пример страницы:

Код: Выделить всё

<div class='class_div'>
    <div>
        <p>ID=1</p>
        <div>
            <p>Title</p> 
            <div>
                Text
               <p class='class_p'>Text</p>
            </div>
        </div>
    </div>
</div>
<div class='class_div'>
    <div>
        <p>ID=2</p>
        <div>
            <p>Title</p> 
            <div>
                Text
               <p class='class_p'>Text</p>
            </div>
        </div>
    </div>
</div>
<div class='class_div'>
    <div>
        <p>ID=3</p>
        <div>
            <p>Title</p> 
            <div>
            	Text
               <p class='class_p'>Text</p>
            </div>
        </div>
    </div>
</div>
Задача: имеется страница, на которой информация расположена в отдельных блоках (в примере это будут div.class_div). Требуется собрать информацию поблочно, то есть не просто собрать все элементы в массив, а связанно с другой информацией в данном блоке.

Например вариант решения для сбора ID и p.class_p

Код: Выделить всё

$result = array();
$all_div = $div->get_all_by_attribute("class", "class_div", true);
foreach ($all_div as $each_div) {
    $id = $each_div->get_child_by_number(0)->get_child_by_number(0)->get_inner_text(); //получаем ID
    $text = $each_div->get_child_by_number(0)->get_child_by_number(1)->get_child_by_number(1)->get_child_by_attribute("class", "class_p", false)->get_inner_text(); //получаем Text
    $result[] = array('id' => $id, 'text' => $text);
}
Данный вариант работает, но получается очень неудобный для чтения и переделки код, при незначительных изменения в html он будет уже нерабочий (достаточно переставить местами таги и get_child_by_number(0) уже указывает на другой элемент). Поэтому у меня вопрос: можно ли как-то получить одним методом сразу текст с классом class_p, не используя хождения по многочисленным child`ам? Я имею в виду получить что-то вроде:

Код: Выделить всё

$text = $each_div->get_inner_text_by_attribute("class", "class_p", false);

Аватара пользователя
Support
Site Admin
Сообщения: 957
Зарегистрирован: 10 апр 2009, 17:45
Контактная информация:

Re: Как быстро получить элемент внутри DOM интерфейса

Сообщение Support » 26 дек 2018, 19:35

Да конечно, есть такая функция :

get_all_inner_texts_by_attribute($attr_name,attr_value,$exactly,$frame=-1); - данная функция используется для получения массива внутренних текстов у всех элементов страницы, с заданным значением аттрибута или его частью.

Пример кода:
print_r($div->get_all_inner_texts_by_attribute("class", "class_p", false))."<br>";

Аватара пользователя
bigfozzy
Site Admin
Сообщения: 2708
Зарегистрирован: 28 июл 2008, 17:24
Контактная информация:

Re: Как быстро получить элемент внутри DOM интерфейса

Сообщение bigfozzy » 26 дек 2018, 21:58

get_child_by_attribute($atr_name,$atr_value,$exactly=true,$include_subchildren=false)
get_child_by_inner_html($inner_html,$exactly=false,$include_subchildren=false)

еще можно использовать последний параметр

klipper
Сообщения: 6
Зарегистрирован: 26 дек 2018, 17:59

Re: Как быстро получить элемент внутри DOM интерфейса

Сообщение klipper » 26 дек 2018, 23:12

Support писал(а):
26 дек 2018, 19:35
Да конечно, есть такая функция :

get_all_inner_texts_by_attribute($attr_name,attr_value,$exactly,$frame=-1); - данная функция используется для получения массива внутренних текстов у всех элементов страницы, с заданным значением аттрибута или его частью.

Пример кода:
print_r($div->get_all_inner_texts_by_attribute("class", "class_p", false))."<br>";
Видимо я все таки не очень понятно выразился. Я специально привел кусок кода для обработки последовательно каждого div.class_div. Вашей функцией я получу голый массив, который никак не сопоставить с тем из какого же div я получил данные.
Изменим пример страницы:

Код: Выделить всё

<div class='class_div'>
    <div>
        <p>ID=1</p>
        <div>
            <p>Title</p> 
            <div>
                Text
               <p class='class_p'>Text</p>
            </div>
        </div>
    </div>
</div>
<div class='class_div'>
    <div>
        <p>ID=2</p>
        <div>
            <p>Title</p> 
            <div>
                Text
            </div>
        </div>
    </div>
</div>
<div class='class_div'>
    <div>
        <p>ID=3</p>
        <div>
            <p>Title</p> 
            <div>
            	Text
               <p class='class_p'>Text</p>
            </div>
        </div>
    </div>
</div>
Итого у меня будет 3 блока и 3 'id' (1, 2, 3) и только 2 элемента в массиве print_r($div->get_all_inner_texts_by_attribute("class", "class_p", false)). Ну и к каким id они будут относиться? Я уже молчу, если вдруг где-то на странице окажутся еще элементы с таким же классом "class_p" (а это случается). Я почему акцентирую внимание на моём алгоритме обработки:

Код: Выделить всё

$result = array();
$all_div = $div->get_all_by_attribute("class", "class_div", true);
foreach ($all_div as $each_div) {
    $id = $each_div->get_child_by_number(0)->get_child_by_number(0)->get_inner_text(); //получаем ID
    $text = $each_div->get_child_by_number(0)->get_child_by_number(1)->get_child_by_number(1)->get_child_by_attribute("class", "class_p", false)->get_inner_text(); //получаем Text
    $result[] = array('id' => $id, 'text' => $text);
}
После того, как я получил по каждому div.calss_div DOM в $each_div, я бы хотел пересканировать все дерево элементов как будто это отдельная страница со своей структурой, чтобы обращаться к элементам внутри нового дерева сразу на любую глубину, например, $p->get_inner_text_by_attribute(), а не шастать по чайлдам в глубину. Получается имея целую страницу, DOM можно построить и обратиться одним методом на любую глубину, а имея часть страницы в виде того же блока div (в данном случае в переменной $each_div) попасть вглубь уже нельзя, только последовательно по чайлдам.
Последний раз редактировалось klipper 26 дек 2018, 23:20, всего редактировалось 1 раз.

klipper
Сообщения: 6
Зарегистрирован: 26 дек 2018, 17:59

Re: Как быстро получить элемент внутри DOM интерфейса

Сообщение klipper » 26 дек 2018, 23:17

bigfozzy писал(а):
26 дек 2018, 21:58
get_child_by_attribute($atr_name,$atr_value,$exactly=true,$include_subchildren=false)
get_child_by_inner_html($inner_html,$exactly=false,$include_subchildren=false)

еще можно использовать последний параметр
А это что-то новенькое...
Читаю на сайте:
get_child_by_attribute($attr_name,$attr_value,$exactly=true); - получить интерфейс дочернего элемента DOM с заданным значением атрибута (доступна с 4.9.34 версии)
get_child_by_inner_html($inner_html,$exactly=true); - получить интерфейс дочернего элемента DOM с заданным внутренним html (доступна с 4.9.34 версии)
Нигде $include_subchildren не указано. Я правильно понимаю, что этот параметр как раз и отвечает за возможность искать только в чайлде на уровне ниже или на всех уровнях?

Аватара пользователя
bigfozzy
Site Admin
Сообщения: 2708
Зарегистрирован: 28 июл 2008, 17:24
Контактная информация:

Re: Как быстро получить элемент внутри DOM интерфейса

Сообщение bigfozzy » 26 дек 2018, 23:51

да - это поиск по всем чайлд , а справку сейчас в соответствие с нововведениями приводим.

klipper
Сообщения: 6
Зарегистрирован: 26 дек 2018, 17:59

Re: Как быстро получить элемент внутри DOM интерфейса

Сообщение klipper » 29 дек 2018, 22:41

bigfozzy писал(а):
26 дек 2018, 23:51
да - это поиск по всем чайлд , а справку сейчас в соответствие с нововведениями приводим.
В последней демо-версии $include_subchildren у меня не работает. Так и должно быть?

Аватара пользователя
bigfozzy
Site Admin
Сообщения: 2708
Зарегистрирован: 28 июл 2008, 17:24
Контактная информация:

Re: Как быстро получить элемент внутри DOM интерфейса

Сообщение bigfozzy » 30 дек 2018, 14:25

klipper писал(а):
29 дек 2018, 22:41
bigfozzy писал(а):
26 дек 2018, 23:51
да - это поиск по всем чайлд , а справку сейчас в соответствие с нововведениями приводим.
В последней демо-версии $include_subchildren у меня не работает. Так и должно быть?
А что именно не работает - можно пример кода ?

Аватара пользователя
Kuzne4ik
Сообщения: 5
Зарегистрирован: 19 мар 2018, 01:56

Re: Как быстро получить элемент внутри DOM интерфейса

Сообщение Kuzne4ik » 12 фев 2019, 15:01

Можно использовать php библиотеку simple_html_dom.php (используется принципы jQuery ) и работать с html непосредственно. Выгода в том, что запрос к движку только один, это получение DOM дерева, это работает быстрее. И Хуман не достает слишком глубоко вложенный тэг. :D

Код: Выделить всё

$body = @"<div class='class_div'>
    <div>
        <p>ID=1</p>
        <div>
            <p>Title 1</p> 
            <div>
                Text 0 
               <p class='class_p'>Text 1</p>
            </div>
        </div>
    </div>
</div>
<div class='class_div'>
    <div>
        <p>ID=2</p>
        <div>
            <p>Title 2</p> 
            <div>
                Text
               <p class='class_p'>Text 2</p>
            </div>
        </div>
    </div>
</div>
<div class='class_div'>
    <div>
        <p>ID=3</p>
        <div>
            <p>Title 3</p> 
            <div>
            	Text
               <p class='class_p'>Text 3</p>
            </div>
        </div>
    </div>
</div>";

$html_ = str_get_html($body); 

$result = array();

$e = $html_->find('.class_div');

foreach($e as $div_c)
{
	//var_dump($td_html);
    $id = $div_c->children(0)->children(0)->plaintext; echo('$id = '.$id.PHP_EOL);
	$title = $div_c->children(0)->children(1)->children(0)->plaintext;echo('$title = '.$title.PHP_EOL);
	$text1 = $div_c->children(0)->children(1)->children(1)->children(0)->plaintext;echo('$text = '.$text1.PHP_EOL);	
	$result[] = array('id' => $id, '$title' => $title, 'text' => $text1);
}
$html_->clear();
$app->quit();

klipper
Сообщения: 6
Зарегистрирован: 26 дек 2018, 17:59

Re: Как быстро получить элемент внутри DOM интерфейса

Сообщение klipper » 29 янв 2021, 19:50

bigfozzy писал(а):
30 дек 2018, 14:25
klipper писал(а):
29 дек 2018, 22:41
bigfozzy писал(а):
26 дек 2018, 23:51
да - это поиск по всем чайлд , а справку сейчас в соответствие с нововведениями приводим.
В последней демо-версии $include_subchildren у меня не работает. Так и должно быть?
А что именно не работает - можно пример кода ?
Прошло почти два года, а поиск чайлдов на несколько уровней ниже так и не работает. И что удивительно, никто на это не обращает внимание. Ну что ж, надоело это, так что нашел время для примера:
<?php

$xhe_host = "127.0.0.1:7010";

// The following code is required to properly run XWeb Human Emulator
require("../Templates/xweb_human_emulator.php");
$bUTF8Ver=true;

//грузим страницу
$browser->navigate("https://xn--80awbbeioodeq4h3a.xn--p1ai/about_studio.php")."<br>";

//получаем div class="page"
$block1 = $div->get_by_attribute("class","page", true);

//получаем чайлд уровнем ниже с классом 'mobile-center' и проверяем его тэг:
$find_child1 = $block1->get_child_by_attribute("class", "mobile-center", true);
echo "Получим тэг элемента уровнем ниже c классом 'mobile-center': ";
echo $find_child1->get_tag()."\n";

//пробуем получить чайлд на несколько уровней ниже
$find_child2 = $block1->get_child_by_attribute("class", "container hr", true, true);
echo "Получим тэг элемента c классом 'container hr' на несколько уровней ниже: ";
echo $find_child2->get_tag()."\n";

//а теперь тот же чайлд, но с одного уровня выше:
$block2 = $section->get_by_attribute("class","well1 ins3", true);
$find_child3 = $block2->get_child_by_attribute("class", "container hr", true, true);
echo "Получим тэг элемента c классом 'container hr', но из уровня выше: ";
echo $find_child3->get_tag()."\n";

// конец
echo "<hr><br>";

// Quit
$app->quit();
?>
Полагаю из примера будет понятно, что тэг <div class="container hr"> нашелся только из родительского. Проверено в демо и платной версии.

Аватара пользователя
bigfozzy
Site Admin
Сообщения: 2708
Зарегистрирован: 28 июл 2008, 17:24
Контактная информация:

Re: Как быстро получить элемент внутри DOM интерфейса

Сообщение bigfozzy » 30 янв 2021, 00:14

Спасибо, займемся эти вопросом на следующей неделе

Аватара пользователя
bigfozzy
Site Admin
Сообщения: 2708
Зарегистрирован: 28 июл 2008, 17:24
Контактная информация:

Re: Как быстро получить элемент внутри DOM интерфейса

Сообщение bigfozzy » 01 фев 2021, 03:36

Спасибо , Исправлено, будет доступно при следующем обновлении

Ответить