Статьи

Разбор HTML и очистка экрана с помощью простой библиотеки HTML DOM

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

Кстати, вы также можете найти парсеры на Envato Market, такие как HTML5 Parser .

HTML5 парсер на рынке Envato
HTML5 парсер на рынке Envato

Первое, что вам нужно сделать, это загрузить копию библиотеки simpleHTMLdom, которая свободно доступна на sourceforge.

В загрузке есть несколько файлов, но вам нужен только файл simple_html_dom.php; Остальные примеры и документация.

Скачать с Sourceforge

Эта библиотека очень проста в использовании, но есть некоторые основы, которые вы должны рассмотреть, прежде чем приступить к работе.

1
2
3
4
5
6
7
$html = new simple_html_dom();
 
// Load from a string
$html->load(‘<html><body><p>Hello World!</p><p>We’re here</p></body></html>’);
 
// Load a file
$html->load_file(‘http://net.tutsplus.com/’);

Вы можете создать свой исходный объект, загрузив HTML из строки или из файла. Загрузка файла может быть выполнена либо через URL, либо через локальную файловую систему.

Предупреждение: метод load_file () делегирует свою работу PHP file_get_contents. Если для allow_url_fopen в файле php.ini не задано значение true, возможно, вы не сможете открыть удаленный файл таким способом. В этом случае вы всегда можете воспользоваться библиотекой CURL для загрузки удаленных страниц, а затем прочитать их с помощью метода load ().

Преобразование вашего HTML

Получив объект DOM, вы можете начать работать с ним, используя find () и создавая коллекции. Коллекция — это группа объектов, найденных с помощью селектора — синтаксис очень похож на jQuery.

1
2
3
4
5
6
<html>
<body>
    <p>Hello World!</p>
    <p>We’re Here.</p>
</body>
</html>

В этом примере HTML мы рассмотрим, как получить доступ к информации во втором абзаце, изменить ее и затем вывести результаты.

01
02
03
04
05
06
07
08
09
10
11
12
13
# create and load the HTML
include(‘simple_html_dom.php’);
$html = new simple_html_dom();
$html->load(«<html><body><p>Hello World!</p><p>We’re here</p></body></html>»);
 
# get an element representing the second paragraph
$element = $html->find(«p»);
 
# modify it
$element[1]->innertext .= » and we’re here to stay.»;
 
# output it!
echo $html->save();

Использование метода find () всегда возвращает коллекцию (массив) тегов, если только вы не укажете, что хотите использовать только n-й дочерний элемент, в качестве второго параметра.

Строки 2-4 : загрузить HTML из строки, как описано ранее.

Строка 7 : эта строка находит все теги <p> в HTML и возвращает их в виде массива. Первый абзац будет иметь индекс 0, а последующие абзацы будут проиндексированы соответственно.

строка 10 : получает доступ ко 2-му элементу в нашей коллекции абзацев (индекс 1) и добавляет к его атрибуту innertext. Innertext представляет содержимое между тегами, в то время как externaltext представляет содержимое, включая тег. Мы могли бы полностью заменить тег, используя externaltext.

Мы собираемся добавить еще одну строку и изменить класс нашего второго тега абзаца.

1
2
$element[1]->class = «class_name»;
echo $html->save();

В результате HTML-код команды save будет:

1
2
3
4
5
6
<html>
<body>
    <p>Hello World!</p>
    <p class=»class_name»>We’re here and we’re here to stay.</p>
</body>
</html>

Вот еще несколько примеров селекторов. Если вы использовали jQuery, они покажутся вам очень знакомыми.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
# get the first occurrence of id=»foo»
$single = $html->find(‘#foo’, 0);
 
# get all elements with class=»foo»
$collection = $html->find(‘.foo’);
 
# get all the anchor tags on a page
$collection = $html->find(‘a’);
 
# get all anchor tags that are inside H1 tags
$collection = $html->find(‘h1 a’);
 
# get all img tags with a title of ‘himom’
$collection = $html->find(‘img[title=himom]’);

Первый пример не совсем интуитивно понятен — все запросы по умолчанию возвращают коллекции, даже запрос идентификатора, который должен возвращать только один результат. Однако, указав второй параметр, мы говорим «вернуть только первый элемент этой коллекции».

Это означает, что $ single — это отдельный элемент, а не массив элементов с одним элементом.

Остальные примеры говорят сами за себя.

Полная документация по библиотеке может быть найдена на странице документации проекта .

специальные свойства

Чтобы запустить эту библиотеку в действие, мы собираемся написать быстрый сценарий для очистки содержимого веб-сайта Nettuts и составить список статей, представленных на сайте, по заголовкам и описаниям… только в качестве примера. Соскребание — сложная область в Интернете, и ее не следует выполнять без разрешения.

Нетто для чистки экрана
1
2
3
4
include(‘simple_html_dom.php’);
 
$articles = array();
getArticles(‘http://net.tutsplus.com/page/76/’);

Мы начнем с включения библиотеки и вызова функции getArticles со страницей, которую мы хотели бы начать анализировать. В этом случае мы начинаем ближе к концу и будем добры к серверу Nettuts.

Мы также объявляем глобальный массив, чтобы упростить сбор всей информации о статье в одном месте. Прежде чем приступить к анализу, давайте посмотрим, как описывается краткое изложение статьи на Nettuts +.

1
2
3
4
5
6
7
8
9
<div class=»preview»>
    <!— Post Taxonomies —>
    <div class=»post_taxonomy»> … </div>
    <!— Post Title —>
    <h1 class=»post_title»><a>Title</a></h1>
    <!— Post Meta —>
    <div class=»post_meta»> … </div>
    <div class=»text»><p>Description</p></div>
</div>

Это представляет собой основной формат сообщений на сайте, включая комментарии исходного кода. Почему комментарии важны? Они считаются узлами для парсера.


1
2
3
4
5
6
7
8
function getArticles($page) {
    global $articles;
 
    $html = new simple_html_dom();
    $html->load_file($page);
 
    // … more …
}

Мы начинаем очень просто, утверждая наш глобальный объект, создавая новый объект simple_html_dom, а затем загружая страницу, которую мы хотим проанализировать. Эта функция будет вызывать себя позже, поэтому мы настроим ее на прием URL-адреса в качестве параметра.


Считайте детей
1
2
3
4
5
6
7
$items = $html->find(‘div[class=preview]’);
 
foreach($items as $post) {
    # remember comments count as nodes
    $articles[] = array($post->children(3)->outertext,
                        $post->children(6)->first_child()->outertext);
}

Это основа функции getArticles. Нужно присмотреться, чтобы действительно понять, что происходит.

Строка 1 : создает массив элементов — div с классом предварительного просмотра. Теперь у нас есть коллекция статей, хранящихся в $ items.

Строка 5 : $ post теперь относится к одному предварительному просмотру класса. Если мы посмотрим на исходный HTML-код, то увидим, что третьим дочерним элементом является H1, содержащий заголовок статьи. Мы берем это и присваиваем его $ article [index] [0].

Не забудьте начинать с 0 и считать комментарии при попытке определить правильный индекс дочернего узла.

Строка 6 : шестым дочерним элементом $ post является <div class = «text»>. Нам нужен текст описания изнутри, поэтому мы берем внешний текст первого дочернего элемента — он будет включать тег абзаца. Отдельная запись в статьях теперь выглядит так:

1
2
$articles[0][0] = «My Article Name Here»;
$articles[0][1] = «This is my article description»

Первое, что мы делаем, это определяем, как найти нашу следующую страницу. В Nettuts + URL-адреса легко определить, но мы собираемся притвориться, что это не так, и получим следующую ссылку с помощью анализа.

Найти следующую страницу для разбора

Если мы посмотрим на HTML, мы увидим следующее:

1
<a href=»http://net.tutsplus.com/page/2/» class=»nextpostslink»>»</a>

Если есть следующая страница (и не всегда будет), мы найдем якорь с классом ‘nextpostslink’. Теперь эта информация может быть использована.

1
2
3
4
5
6
7
8
if($next = $html->find(‘a[class=nextpostslink]’, 0)) {
    $URL = $next->href;
 
    $html->clear();
    unset($html);
 
    getArticles($URL);
}

В первой строке мы видим, можем ли мы найти привязку с классом nextpostslink. Обратите особое внимание на второй параметр для find (). Это указывает, что мы хотим, чтобы возвращался только первый элемент (индекс 0) из найденной коллекции. $ next будет содержать только один элемент, а не группу элементов.

Затем мы присваиваем HREF ссылки переменной $ URL. Это важно, потому что мы собираемся уничтожить объект HTML. Из-за утечки памяти в циклических ссылках php5 текущий объект simple_html_dom должен быть очищен и сброшен перед созданием другого. Невыполнение этого требования может привести к потере всей доступной памяти.

Наконец, мы вызываем getArticles с URL-адресом следующей страницы. Эта рекурсия заканчивается, когда больше нет страниц для анализа.


Сначала мы собираемся настроить несколько основных стилей. Это совершенно произвольно — вы можете сделать вывод таким, каким пожелаете.

Окончательный вывод
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
#main {
    margin:80px auto;
    width:500px;
}
h1 {
    font:bold 40px/38px helvetica, verdana, sans-serif;
    margin:0;
}
h1 a {
    color:#600;
    text-decoration:none;
}
p {
    background: #ECECEC;
    font:10px/14px verdana, sans-serif;
    margin:8px 0 15px;
    border: 1px #CCC solid;
    padding: 15px;
}
.item {
    padding:10px;
}

Далее мы собираемся поместить небольшой кусочек PHP на страницу для вывода ранее сохраненной информации.

1
2
3
4
5
6
7
8
<?php
    foreach($articles as $item) {
        echo «<div class=’item’>»;
        echo $item[0];
        echo $item[1];
        echo «</div>»;
    }
?>

Конечным результатом является одна HTML-страница со списком всех статей, начиная со страницы, указанной первым вызовом getArticles ().


Если вы анализируете большое количество страниц (скажем, весь сайт), это может занять больше времени, чем максимальное время выполнения, разрешенное вашим сервером. Например, запуск с моего локального компьютера занимает около одной секунды на страницу (включая время для извлечения).

На таком сайте, как Nettuts, с текущими 78 страницами учебных пособий, это может занять более одной минуты.

Из этого туториала вы должны начать разбирать HTML. Есть и другие методы для работы с DOM, включая встроенный в PHP, который позволяет вам работать с мощными селекторами xpath для поиска элементов. Для простоты использования и быстрого запуска я считаю эту библиотеку одной из лучших. В качестве заключительного замечания всегда помните, чтобы получить разрешение, прежде чем очищать сайт; это важно. Спасибо за прочтение!