Advertisement
  1. Web Design
  2. HTML/CSS
  3. HTML

Парсинг HTML на PHP с использованием DiDOM

Scroll to top
Read Time: 7 min

() translation by (you can also view the original English article)

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

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

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

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

1
composer require imangazaliev/didom

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

1
require_once('vendor/autoload.php');
2
3
use DiDom\Document;
4
5
$document = new Document($washington_dc_html_string);
6
7
$document = new Document('washington_dc.html', true);
8
9
$url = 'https://en.wikipedia.org/wiki/Washington,_D.C.';
10
$document = new Document($url, true);

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

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

Вы также можете создать новый объект Document, используя new Document() без каких-либо параметров. В этом случае вы можете вызвать метод loadHtml() для загрузки HTML из строки и 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 из всех заголовков первого и второго уровня в статье Википедии о Washington, D.C.

1
require_once('vendor/autoload.php');
2
3
use DiDom\Document;
4
5
$document = new Document('https://en.wikipedia.org/wiki/Washington,_D.C.', true);
6
7
$main_heading = $document->find('h1.firstHeading')[0];
8
echo $main_heading->html();
9
10
$sub_headings = $document->find('h2');
11
12
foreach($sub_headings as $sub_heading) {
13
    if($sub_heading->text() !== 'See also') {
14
        echo $sub_heading->html();
15
    } else {
16
        break;
17
    }
18
}

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

Для основного заголовка мы просто вызываем метод html(), который возвращает HTML всего элемента заголовка. Аналогично, мы можем получить HTML внутри определенного элемента, используя метод innerHtml(). Иногда вас будет больше интересовать текстовое содержимое элемента, а не его HTML. В таких случаях вы можете просто использовать метод 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().

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

1
require_once('vendor/autoload.php');
2
3
use DiDom\Document;
4
5
$document = new Document('https://en.wikipedia.org/wiki/Washington,_D.C.', true);
6
7
$sub_headings = $document->find('h2');
8
9
for($i = 1; $i < count($sub_headings); $i++) {
10
    if($sub_headings[$i]->text() !== 'See also') {
11
        $next_sibling = $sub_headings[$i]->nextSibling();
12
        while(!$next_elem->html()) {
13
            $next_sibling = $next_sibling->nextSibling();
14
        }
15
16
        echo $next_elem->html()."<br>";
17
    } else {
18
        break;
19
    }
20
}

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

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

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

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

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

Как только вы получите доступ к атрибутам 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(), либо использовать метод replace() для использования вновь созданного элемента в качестве замены некоторого старого элемента HTML в документе. Следующий пример должен помочь в дальнейшем разъяснении этой концепции.

1
require_once('vendor/autoload.php');
2
3
use DiDom\Document;
4
use DiDom\Element;
5
6
$document = new Document('https://en.wikipedia.org/wiki/Washington,_D.C.', true);
7
8
// This will result in error.

9
echo $document->find('h2.test-heading')[0]->html()."\n";
10
11
$test_heading = new Element('h2', 'This is test heading.');
12
$test_heading->class = 'test-heading';
13
14
$document->find('h1')[0]->replace($test_heading);
15
16
echo $document->find('h2.test-heading')[0]->html()."\n";

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

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

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

Последние мысли

В этом учебном руководстве описаны основы HTML-парсера PHP DiDOM. Мы начали с установки, а затем научились загружать HTML из строки, файла или URL. После этого мы обсудили, как найти определенный элемент на основе его CSS-селектора или XPath. Мы также узнали, как получить братьев и сестер, родителей или детей элемента. В остальных разделах рассказывается, как мы можем манипулировать атрибутами определенного элемента или добавлять, удалять и заменять элементы в документе HTML.

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

Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Web Design tutorials. Never miss out on learning about the next big thing.
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.