Если вам нужно организовать парсинг HTML, то регулярные выражения мало помогут. В данном уроке вы узнаете как использовать простой парсер с открытым кодом для того, чтобы прочитать, модифицировать и использовать HTML с внешнего источника. В качестве примера будет использоваться сайт net.tutsplus. Вы узнаете, как получить список всех статей, опубликованных на сайте.
Шаг 1. Подготовка
В первую очередь нужно скопировать библиотеку simpleHTMLdom, которая доступна на сайте sourceforge.net.
В архиве для загрузки хранятся несколько файлов, но вам нужен только один simple_html_dom.php. Все остальные файлы - это примеры и документация.
Шаг 2. Основы парсинга
Данную библиотеку очень просто использовать, но есть несколько основных моментов, которые следует изучить до того, как вы начнете приводить ее в действие.
Загрузка HTML$html = new simple_html_dom();
// Загрузка из строки
$html->load('
Hello World!
We're here
');// Загрузка файла
$html->load_file('net.tutsplus/');
Вы можете создать исходный объект загрузив HTML либо из строки, либо из файла. Загрузка из файла может быть выполнена либо через указание URL, либо из вашей локальной файловой системы.
Примечания: Метод load_file() делегирует работу функции PHP file_get_contents. Если allow_url_fopen не установлен в значение true в вашем файле php.ini, то может отсутствовать возможность открывать удаленные файлы таким образом. В этом случае вы можете вернуться к использованию библиотеки CURL для загрузки удаленных страниц, а затем прочитать с помощью метода load().
Доступ к информацииКак только у вас будет объект DOM, вы сможете начать работать с ним, используя метод find() и создавая коллекции. Коллекция - это группа объектов, найденных по селектору. Синтаксис очень похож на jQuery.
Hello World!
We're Here.
В данном примере HTML мы собираемся разобраться, как получить доступ к информации во втором параграфе, изменить ее и затем вывести результат действий.
1. # создаем и загружаем HTML2. include('simple_html_dom.php');
3. $html = new simple_html_dom();
4. $html->load(“
Hello World!
We're here
“);5. # получаем элемент представляющий второй параграф
6. $element = $html->find(“p“);
7. # модифицируем его
8. $element[1]->innertext .= “ and we're here to stay.“;
9. # Выводим!
10. echo $html->save();
Строки 2-4: Загружаем HTML из строки, как объяснялось выше.
Строка 6: Находим все тэги
в HTML, и возвращаем их в массив. Первый параграф будет иметь индекс 0, а последующие параграфы индексируются соответственно.
Строка 8: Получаем доступ ко второму элементу в нашей коллекции параграфов (индекс 1), добавляем текст к его атрибуту innertext. Атрибут innertext представляет содержимое между тэгами, а атрибут outertext представляет содержимое включая тэги. Мы можем заменить тэг полностью, используя атрибут outertext.
Теперь добавим одну строку и модифицируем класс тэга нашего второго параграфа.
$element[1]->class = ""class_name"";echo $html->save();
Окончательный вид HTML после команды save будет иметь вид:
Hello World!
We're here and we're here to stay.
Другие селекторыНесколько других примеров селекторов. Если вы использовали jQuery, все покажется вам знакомым.
# получаем первый найденный элемент с id=“foo“$single = $html->find('#foo', 0);
# получаем все элементы с классом “foo“
$collection = $html->find('.foo');
# получаем все теги ссылок на странице
$collection = $html->find('a');
# получаем все теги ссылок, которые расположены внутри тега H1
$collection = $html->find('h1 a');
# получаем все теги img с title='himom'
$collection = $html->find('img[title=himom]');
Первый пример требует пояснений. Все запросы по умолчанию возвращают коллекции, даже запрос с ID, который должен вернуть только один элемент. Однако, задавая второй параметр, мы говорим “вернуть только первый элемент из коллекции”.
Это означает, что $single - единичный элемент, а не не массив элементов с одним членом.
Остальные примеры достаточно очевидны.
ДокументацияПолная документация по библиотеке доступна на странице проекта.
Шаг 3. Пример из реального мира
Для демонстрации библиотеки в действии мы напишем скрипт для скрепинга содержимого сайта net.tutsplus и формирования списка заголовков и описания статей, представленных на сайте….только в качестве примера. Скрепинг относится к области трюков в веб, и не должен использоваться без разрешения владельца ресурса.
include('simple_html_dom.php');
$articles = array();
getArticles('net.tutsplus/page/76/');
Начнем с подключения библиотеки и вызова функции getArticles с указанием страницы, с которой мы хотим начать парсинг.
Так же объявим глобальный массив, чтобы сделать проще сбор все информации о статьях в одном месте. Прежде чем начинать парсинг взглянем, как описывается статья на сайте Nettuts+.
...Title
...
Description
Так представлен основой формат поста на сайте, включая комментарии исходного кода. Почему важны комментарии? Они подсчитываются парсером как узлы.
Шаг 4. Начало функции парсингаfunction getArticles($page) {
global $articles;
$html = new simple_html_dom();
$html->load_file($page);
// ... Дальше ...
}
Начинаем с объявления глобального массива, создаем новый объект simple_html_dom, и затем загружаем страницу для парсинга. Данная функция будет рекурсивно вызываться, поэтому устанавливаем для нее в качестве параметра URL страницы.
Шаг 5. Находим ту информацию, которая нам нужна1. $items = $html->find('div[class=preview]');
2. foreach($items as $post) {
3. # помним про учет комментариев в качестве узлов
4. $articles[] = array($post->children(3)->outertext,
5. $post->children(6)->first_child()->outertext);
6. }
Это суть функции getArticles. Нужно разобраться более детально, чтобы понять, что происходит.
Строка 1: Создаем массив элементов – тег div с классом preview. Теперь у нас есть коллекция статей, сохраненная в $items.
Строка 4: $post теперь ссылается на единичный div класса preview. Если мы взглянем в оригинальный HTML, то увидим, что третий элемент потомок - это тег H1, который содержит заголовок статьи. Мы берем его и присваиваем $articles[index][0].
Помните о начале отсчета с 0 и учете комментариев исходного кода, когда будете определять правильный индекс узла.
Строка 5: Шестой потомок $post - это
. Нам нужен текст описания из него, поэтому мы используем outertext – в описание будет включен тег параграфа. Единичная запись в массиве статей будет выглядеть примерно так:
$articles[0][1] = “This is my article description“
Шаг 6, Работа со страницами
первым делом нужно определить, как найти следующую страницу. На сайте Nettuts+ о номере страницы очень легко догадаться по URL, но нам нужно получать ссылку в парсинге.
Если посмотреть на HTML, то можно найти следующее:
»Это сслыка на следующую страницу, и мы можем легко ее найти по классу ‘nextpostslink’. Теперь эта информация может быть использована.
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 следующей страницы. Рекурсия прерывается, когда не остается страниц для парсинга.
Шаг 7. Вывод результатовПервое, мы собираемся установить несколько основных стилей. Все абсолютно произвольно - вы можете устанавливать то, что нравится.
#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 в странице для вывода предварительно сохраненной информации.
foreach($articles as $item) {echo ""
"";
echo $item[0];
echo $item[1];
echo ""
"";
}
?>
Окончательный результат - это одна страница HTML со списком всех статей со страниц Nettuts+, начиная с той, которая была указана в первом вызове getArticles().
Шаг 8. ЗаключениеЕсли Вы запускаете парсинг для большого количества страниц (скажем, весь сайт), то это может занять много времени. На таком сайте как Nettuts+, который имеет боле 86страниц, процесс парсинга может длиться более минуты.
Данный урок открывает для вас тему парсинга HTML. Существуют другие методы методы работы с DOM, которые позволяют работать с селектором xpath для поиска элементов. Описанная в данном уроке библиотека проста для использования и отлично подходит для быстрого старта. Помните, что нужно спрашивать разрешения, прежде проводить скрепинг сайта.