Матвей Земсков

Заметки веб-мастера

Воскресенье, 29 июля 2018 10:10

Парсинг HTML c помощью библиотеки DiDOM

Оцените материал
(2 голосов)

Время от времени разработчикам необходимо парсить веб-страницы, чтобы получить некоторую информацию с какого-нибудь веб-сайта. Например, предположим, что вы работаете над своим персональным проектом для которого вам необходимо получить географическую информацию о столицах разных стран из Википедии. Добавление информации вручную займет много времени. Однако, вы сможете это сделать очень быстро, получив информацию со страниц Википедии с помощью PHP. Вы также сможете автоматически спарсить HTML-код, чтобы получить конкретную информацию, вместо того чтобы обрабатывать всю разметку вручную.

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

Установка и использование

Вы можете установить DiDOM в директорию вашего проекта выполнив следующую команду:

composer require imangazaliev/didom

Однажды выполнив вышеуказанную команду, вы сможете загружать HTML из строки, локального файла или веб-страницы. Пример использования:

PHP

	require_once('vendor/autoload.php'); 
	use DiDom\Document; 
	$document = new Document($washington_dc_html_string); 
	$document = new Document('washington_dc.html', true); 
	$url = 'https://en.wikipedia.org/wiki/Washington,_D.C.';
	$document = new Document($url, true);

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

Если HTML должен загружаться из файла или по URL , то вы можете передать его первым параметром в объект Document(), а второму параметру установить значение true.

Вы также можете создать новый объект Document, используя команду new Document() без аргументов. В этом случае вы можете вызвать метод loadHtmlFile(), чтобы загрузить HTML и файла и веб-страницы.

Поиск HTML-элементов

Перед тем, как получить HTML или текст из элемента, нужно найти сам элемент. Самый элементарный способ сделать это – воспользоваться методом find() и передать CSS-селектор необходимого элемента в качестве первого параметра.

Вы также можете передать XPath-путь к элементу первым аргументом метода find(). Однако, в этом случае требуется передать вторым аргументом Query::TYPE_XPATH.

Если вы хотите пользоваться только выражениями XPath для поиска HTML- элементов, вы может использовать метод xpath() вместо передачи каждый раз второго аргумента Query::TYPE_XPATH в метод find().

Если DiDOM найдет элементы, подходящие по параметрам (CSS-селектор или выражения XPath), то будет возвращен массив экземпляр DiDom\Element. Если ничего не будет найдено, то вернется пустой массив.

Поскольку оба метода возвращают массив, вы можете напрямую обращаться к соответствующему n-му элементу, используя find()[n-1].

Пример

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

PHP

	require_once('vendor/autoload.php'); 
	use DiDom\Document; 
	$document = new Document('https://en.wikipedia.org/wiki/Washington,_D.C.', true); 
	$main_heading = $document->find('h1.firstHeading')[0];
	echo $main_heading->html(); 
	$sub_headings = $document->find('h2'); 
	foreach($sub_headings as $sub_heading) {
		if($sub_heading->text() !== 'See also') {
			echo $sub_heading->html();
		} else {
			break;
		}
	}

Мы начинаем с создания нового экземпляра объекта Document, передавая ему URL статьи из Википедии. После этого мы получаем основные элементы заголовков, используя метод find() и сохраняем их в переменной $main_heading. Теперь мы можем вызывать различные методы для этого элемента, например, такие как: text(), innerHtml(), html() и прочие.

Для основного заголовка мы просто вызовем метод html(), который вернет HTML-код всего заголовка. Аналогично, мы можем вернуть HTML-код, находящийся внутри конкретного элемента, используя метод innerHtml(). Иногда, нам необходим простой текст без тегов, содержащийся в элементе. В таких случаях, вы можете просто вызвать метод text() и получить с помощью него желаемый результат.

Заголовки второго уровня делят страницу Википедии на определенные секции. Однако, вам может понадобиться избавиться от некоторых из них, таких как “Смотрите также” или «Примечания» и тп.

Одним из способов сделать это может быть следующий: обойти заголовки второго уровня в цикле и проверить значение, которое вернет метод text(). В примере мы выводим значения всех заголовков, расположенных выше заголовка с текстом «Смотрите также». Дойдя до него цикл прекращается.

Вы можете получить четвертый или шестой заголовок второго, если вам это необходимо, используя соответствующие команды: $document->find('h2')[3] и $document->find('h2')[5].

Перемещаемся вверх и вниз по DOM

Мы получили доступ к одному конкретном элементу, библиотека также позволяет перемещаться вверх и вниз по дереву DOM, чтобы с легкостью получить доступ к другим элементам.

Вы можете обратиться к родителю HTML-элемента, используя метод parent(). Аналогично вы можете получить доступ к следующему и предыдущему элементам находящимся на одном уровне с текущим, используя методы nextSibling() и previousSibling().

Также в библиотеке содержится множество методов для доступа к потомкам элемента по дереву DOM. Например, вы можете получить конкретный элемент-потомок, используя метод child(n). Аналогично, вы можете получить первого и последнего потомка текущего элемента, обратившись к методам firstChild() и lastChild(). Вы можете обойти в цикле всех потомков текущего DOM-элемента, используя метод children().

Как только вы перейдете к определенному элементу, у вас появится возможность получить его HTML и тп, применяя методы html(), innerHtml() и text().

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

PHP

	require_once('vendor/autoload.php'); 
	use DiDom\Document; 
	$document = new Document('https://en.wikipedia.org/wiki/Washington,_D.C.', true); 
	$sub_headings = $document->find('h2'); 
	for($i = 1; $i < count($sub_headings); $i++) {
		if($sub_headings[$i]->text() !== 'See also') {
			$next_sibling = $sub_headings[$i]->nextSibling();
			while(!$next_elem->html()) {
				$next_sibling = $next_sibling->nextSibling();
			} 
			echo $next_elem->html()."<br>";
		} else {
			break;
		}
	}

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

Манипулирование атрибутами элементов

Способность получить или установить значение атрибута для различных элементов может оказаться очень полезной в определенных ситуациях. Например, мы может получить значение атрибута src тегов img в нашей статье в Википедия, используя $image_elem->attr('src'). Похожим способом, вы можете получить значения атрибута href всех тагов a в документе.

Существует 3 способа получения значений определенных атрибутов HTML-элемента. Вы можете использовать метод getAttribute('attrName') и передавать имя интересующего атрибута в качестве аргумента. Вы также можете использовать метод attr('attrName'), который работает также как getAttribute(). Наконец, библиотека также позволяет вам напрямую получить значение атрибута с помощью $elem->attrName. Это означает, что вы можете получить значение атрибута src для элемента изображения img напрямую, используя $imageElem->src.

PHP

	require_once('vendor/autoload.php'); 
	use DiDom\Document; 
	$document = new Document('https://en.wikipedia.org/wiki/Washington,_D.C.', true); 
	$images = $document->find('img'); 
	foreach($images as $image) {
		echo $image->src."<br>";
	}

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

Также тремя способами вы можете установить значение атрибутов у элементов. Во-первых, вы можете использовать метод setAttribute('attrName', 'attrValue') чтобы установить значение атрибута, во-вторых, метод attr('attrName', 'attrValue') также устанавливает значение атрибута. И наконец, установить значение атрибута определенного элемента возможно так: $Elem->attrName = 'attrValue'.

Добавление, удаление и замена элементов

Вы также можете внести изменения в загруженный HTML-документ, используя различные методы, предоставляемые библиотекой. Например, вы можете добавлять, заменять или удалять элементы из дерева DOM с помощью методов appendChild(), replace() и remove().

Библиотека также позволяет создавать собственные HTML-элементы, чтобы добавить их в исходный HTML-документ. Вы можете создать новый объект Element, используя new Element('tagName', 'tagContent').

Имейте в виду, что вы получите ошибку следующего содержания: “Uncaught Error: Class 'Element' not found”, если до этой строчки кода ваша программа не содержит следующий код: use DiDom\Element.

Когда у вас есть элемент, вы можете либо добавить его к другим элементам в DOM, используя метод appendChild(), либо заменить им какой-нибудь HTML-элемент, находящийся на странице, используя метод replace().

Следующий пример должен помочь в дальнейшем разъяснении этой темы.

PHP

	require_once('vendor/autoload.php'); 
	use DiDom\Document;
	use DiDom\Element; 
	$document = new Document('https://en.wikipedia.org/wiki/Washington,_D.C.', true); 
	// This will result in error.
	echo $document->find('h2.test-heading')[0]->html()."\n"; 
	$test_heading = new Element('h2', 'This is test heading.');
	$test_heading->class = 'test-heading'; 
	$document->find('h1')[0]->replace($test_heading); 
	echo $document->find('h2.test-heading')[0]->html()."\n";

Сначала в нашем документе нет заголовка h2 с классом test-heading. Поэтому мы получим ошибку, если попытаемся до него «достучаться».

После проверки того, что такого элемента нет, мы создадим новый элемент h2 и заменим значение его атрибута class на test-heading.

Затем, мы заменим первый элемент h1 в документе только что созданным заголовком h2. При повторной попытке найти в нашем документе элемент h2 с классом test-heading используя метод find(), мы получим добавленный нами заголовок.

Финальные размышления

Эта обучающая статья познакомила вас с основами работы с HTML-парсером на PHP под названием DiDOM. Мы начали изучение с установки этой библиотеки и загрузки HTML из строки, файла или URL. Далее мы обсудили как можно найти определенный элемент по его CSS-селектору или выражению XPath. Также мы узнали, как найти элемент-родитель, элементы-потомки и соседние («сестринские») элементы относительно текущего. В следующих разделах статьи было рассказано, как мы можем манипулировать атрибутами определенного элемента, а также добавлять, удалять и заменять элементы в документе HTML.

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

Оригинал статьи - https://code.tutsplus.com/tutorials/parsing-html-with-php-using-didom--cms-31242

Перевод – Матвей Земсков

Прочитано 8951 раз
Мои услуги

Предлагаю следующие услуги:

  • Верстка шаблона сайта из дизайн-макета для CMS «1С-Битрикс Управление сайтом» и CMS “Joomla”
  • Создание форм различной сложности (обратная связь, анкеты и тп) для указанных CMS
  • Настройка и кастомизация компонентов и модулей для указанных CMS
  • Доработка модулей и компонентов для указанных CMS, добавление нестандартного функционала
  • Разработка лендингов (landing-pages)

По все вопросам обращайтесь через форму обратной связи

Скачать

Предлагаю вашему вниманию:

Наверх