Парсинг Сервис

Парсинг html и скрепинг с помощью простой библиотеки html dom.

Если вам нужно организовать парсинг 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. # создаем и загружаем HTML
2. 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][0] = “Заголовок статьи“;
$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 для поиска элементов. Описанная в данном уроке библиотека проста для использования и отлично подходит для быстрого старта. Помните, что нужно спрашивать разрешения, прежде проводить скрепинг сайта.