Подскажите по xPath

вопросы и ответы по использованию PHP
Ответить
statov12
Сообщения: 3
Зарегистрирован: 07 май 2019, 23:37

Подскажите по xPath

Сообщение statov12 » 07 май 2019, 23:58

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

Подскажите как правильно составить запрос в xPath чтобы найти данный блок в ценой

Пытался сделать так

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

$div->get_by_xpath('/html/body/div/div[1]/*/[@class="price"]');
div[1] - перебирается циклом чтоб выбрать все блоки

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

Re: Подскажите по xPath

Сообщение Support » 08 май 2019, 01:36

А не пробовали получить нужный вам элемент без использования xpath. По вашему коду видно, что у интересующего вас элемента есть class="price". Можно получить этот элемент с помощью

$obj=$div->get_by_attribute("class","price");

если у вас несколько div с class="price", получаете тогда все их и находите нужный вам среди них. Скорее всего порядок этих элементов будет меняться не так часто как xpath.

print_r($div->get_all_by_attribute("class","price")->elements);

statov12
Сообщения: 3
Зарегистрирован: 07 май 2019, 23:37

Re: Подскажите по xPath

Сообщение statov12 » 08 май 2019, 02:21

Support писал(а):
08 май 2019, 01:36
А не пробовали получить нужный вам элемент без использования xpath. По вашему коду видно, что у интересующего вас элемента есть class="price". Можно получить этот элемент с помощью

$obj=$div->get_by_attribute("class","price");

если у вас несколько div с class="price", получаете тогда все их и находите нужный вам среди них. Скорее всего порядок этих элементов будет меняться не так часто как xpath.

print_r($div->get_all_by_attribute("class","price")->elements);
Вашим способом мы получим все .price без привязки к соседним элементам с названием товара, наличием и т.д.
Расскажите пожалуйста как их связать вместе


Пример одной из вариаций кода

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

<div class="container">
	<div class="item">
		<div class="wrap">
			<div class="name">Название товара 1</div>
			<div>
				<div class="price">9999 руб.</div>
			</div>
			<ul>
				<li>В продаже</li>
			</ul>
		</div>
	</div>
</div>
и таких .item может быть бесконечное количество
Предполагалось что примерно таким образом можно получить цену и другие элементы, чтоб связать их между собой

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

$item = $div->get_all_by_attribute("class","item")->elements;
foreach ($item as $key => $val) {
	$path = $v->get_xpath();
	$price = $div->get_by_xpath($path . '/*/[@class="price"]');
	$name = $div->get_by_xpath($path . '/*/[@class="name"]');
}
наверное я криворукий)
или программа не поддерживает xPath с указанием css класса?

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

Re: Подскажите по xPath

Сообщение Support » 08 май 2019, 10:11

statov12 писал(а):
08 май 2019, 02:21
Support писал(а):
08 май 2019, 01:36
А не пробовали получить нужный вам элемент без использования xpath. По вашему коду видно, что у интересующего вас элемента есть class="price". Можно получить этот элемент с помощью

$obj=$div->get_by_attribute("class","price");

если у вас несколько div с class="price", получаете тогда все их и находите нужный вам среди них. Скорее всего порядок этих элементов будет меняться не так часто как xpath.

print_r($div->get_all_by_attribute("class","price")->elements);
Вашим способом мы получим все .price без привязки к соседним элементам с названием товара, наличием и т.д.
Расскажите пожалуйста как их связать вместе


Пример одной из вариаций кода

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

<div class="container">
	<div class="item">
		<div class="wrap">
			<div class="name">Название товара 1</div>
			<div>
				<div class="price">9999 руб.</div>
			</div>
			<ul>
				<li>В продаже</li>
			</ul>
		</div>
	</div>
</div>
и таких .item может быть бесконечное количество
Предполагалось что примерно таким образом можно получить цену и другие элементы, чтоб связать их между собой

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

$item = $div->get_all_by_attribute("class","item")->elements;
foreach ($item as $key => $val) {
	$path = $v->get_xpath();
	$price = $div->get_by_xpath($path . '/*/[@class="price"]');
	$name = $div->get_by_xpath($path . '/*/[@class="name"]');
}
наверное я криворукий)
или программа не поддерживает xPath с указанием css класса?
Смотрите, в цикле вы используете не объявленную переменную

$path = $v->get_xpath();

наверное должно быть так:
$path = $val->get_xpath();
Без xpath задача ваша решается так:
// получить все товары
$items = $div->get_all_by_attribute("class","item")->elements;

foreach ($items as $item) 
{
  // get_child_by_attribute($attr_name,$attr_value,$exactly=true,$include_subchildren=false); -
	echo $price = $item->get_child_by_attribute("class","price",true,true)->get_inner_text();
    echo  "<br>";
	echo $name = $item->get_child_by_attribute("class","name",true,true)->get_inner_text();
    echo  "<br>";
}


statov12
Сообщения: 3
Зарегистрирован: 07 май 2019, 23:37

Re: Подскажите по xPath

Сообщение statov12 » 08 май 2019, 11:18

хм, если продолжать в вашем стиле, как тогда получить то что внутри <li> особенно учитывая что внутри всего блока .item может быть несколько списков ul>li и нас интересует только тот что внутри .wrap

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

Re: Подскажите по xPath

Сообщение Support » 08 май 2019, 12:51

statov12 писал(а):
08 май 2019, 11:18
хм, если продолжать в вашем стиле, как тогда получить то что внутри <li> особенно учитывая что внутри всего блока .item может быть несколько списков ul>li и нас интересует только тот что внутри .wrap
Можно получить html .wrap и разобрать его как строку на составляющие части. вот пример для li. Аналогично можно разбирать всё остальное, в том числе и цену и название и т.д.


// получить все товары
$items = $div->get_all_by_attribute("class","item")->elements;

foreach ($items as $item) 
{

      echo $wrap= $item->get_child_by_attribute("class","wrap",true,true)->get_inner_html();
      echo  "<br>";
      $ind_st = 0;
      $li1 = get_string($wrap, "<li>", "</li>", $ind_st); 
      $li2 = get_string($wrap, "<li>", "</li>", $ind_st);     
}

// получить строку по префиксам
function get_string($str1, $pr1, $pr2, &$ind_st = 0)
{
	//получаем стартовый индекс
	$ind1 = strpos($str1, $pr1, $ind_st);
	if($ind1 === false)
	{
		return "";
	}
	$ind1_1 = $ind1 + strlen($pr1);
	//получаем финишный индекс
	$ind2 = strpos($str1, $pr2, $ind1_1);
	if ($ind2 === false)
	{
		return "";
	}
	// получим результат
	$sres = substr($str1, $ind1 + strlen($pr1), $ind2 - $ind1_1);
	return trim($sres); 
}


Ответить