Статьи

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

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

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

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

1
composer require imangazaliev/didom

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

01
02
03
04
05
06
07
08
09
10
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() без каких-либо параметров. В этом случае вы можете вызвать метод loadHtml() для загрузки HTML из строки и loadHtmlFile() для загрузки 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 из всех заголовков первого и второго уровня в статье в Википедии о Вашингтоне, округ Колумбия.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
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() . Иногда вас больше интересует текстовое содержимое элемента, а не его HTML. В таких случаях вы можете просто использовать метод text() и покончить с этим.

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

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

Вы можете напрямую перейти к заголовку 4-го или 6-го уровня, используя $document->find('h2')[3] и $document->find('h2')[5] соответственно.

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

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

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

Добравшись до определенного элемента, вы сможете получить доступ к его HTML и т. Д. С помощью методов html() , innerHtml() и text() .

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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
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 в документе.

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

01
02
03
04
05
06
07
08
09
10
11
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: класс «Элемент» не найден, если ваша программа не содержит строки, use DiDom\Element до создания экземпляра объекта элемента.

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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
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 и меняем значение его атрибута класса на test-heading .

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

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

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