• Главная»
  • Уроки»
  • PHP»
  • Парсинг HTML и скрепинг с помощью простой библиотеки HTML DOM

Парсинг HTML и скрепинг с помощью простой библиотеки HTML DOM

Если вам нужно организовать парсинг HTML, то регулярные выражения мало помогут. В данном уроке вы узнаете как использовать простой парсер с открытым кодом  для того, чтобы прочитать, модифицировать и использовать HTML с внешнего источника. В качестве примера будет использоваться сайт net.tutsplus.com. Вы узнаете, как получить список всех статей, опубликованных на сайте.

sourse

Шаг 1. Подготовка

В первую очередь нужно скопировать библиотеку simpleHTMLdom, которая доступна на сайте sourceforge.net.

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

Загрузка с Sourceforge

Шаг 2. Основы парсинга

Данную библиотеку очень просто использовать, но есть несколько основных моментов, которые следует изучить до того, как вы начнете приводить ее в действие.

Загрузка HTML

$html = new simple_html_dom();
// Загрузка из строки
$html->load('<html><body><p>Hello World!</p><p>We're here</p></body></html>');
// Загрузка файла
$html->load_file('http://net.tutsplus.com/');

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

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

Доступ к информации

Трансформация HTML

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

<html>
<body>
<p>Hello World!</p>
<p>We're Here.</p>
</body>
</html>

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

1.  # создаем и загружаем HTML
2. include('simple_html_dom.php');
3. $html = new simple_html_dom();
4. $html->load(“<html><body><p>Hello World!</p><p>We're here</p></body></html>“);
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: Находим все тэги <p> в HTML, и возвращаем их в массив. Первый параграф будет иметь индекс 0, а последующие параграфы индексируются соответственно.

Строка 8: Получаем доступ ко второму элементу в нашей коллекции параграфов (индекс 1), добавляем текст к его атрибуту innertext. Атрибут innertext представляет содержимое между тэгами, а атрибут outertext представляет содержимое включая тэги. Мы можем заменить тэг полностью, используя атрибут outertext.

Теперь добавим одну строку и модифицируем класс тэга нашего второго параграфа.

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

Окончательный вид HTML после команды save будет иметь вид:

<html>
<body>
<p>Hello World!</p>
<p class=“class_name“>We're here and we're here to stay.</p>
</body>
</html>

Другие селекторы

Несколько других примеров селекторов. Если вы использовали 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 - единичный элемент, а не не массив элементов с одним членом.

Остальные примеры достаточно очевидны.

Документация

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

special properties

Шаг 3. Пример из реального мира

Для демонстрации библиотеки в действии мы напишем скрипт для скрепинга содержимого сайта net.tutsplus.com и формирования списка заголовков и описания статей, представленных на сайте….только в качестве примера. Скрепинг относится к области трюков в веб, и не должен использоваться без разрешения владельца ресурса.

Скрепинг сайта Nettuts

include('simple_html_dom.php');
$articles = array();
getArticles('http://net.tutsplus.com/page/76/');

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

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

<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>

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

Шаг 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 - это <div class=”text”>. Нам нужен текст описания из него, поэтому мы используем outertext – в описание будет включен тег параграфа. Единичная запись в массиве статей будет выглядеть примерно так:

$articles[0][0] = “Заголовок статьи“;
$articles[0][1] = “This is my article description“

Шаг 6, Работа со страницами

первым делом нужно определить, как найти следующую страницу. На сайте Nettuts+ о номере страницы очень легко догадаться по URL, но нам нужно получать ссылку в парсинге.

Найдем следующую страницу для парсинга

Если посмотреть на HTML, то можно найти следующее:

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

Это сслыка на следующую страницу, и мы можем легко ее найти по классу ‘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 в странице для вывода предварительно сохраненной информации.

<?php
foreach($articles as $item) {
echo "<div class='item'>";
echo $item[0];
echo $item[1];
echo "</div>";
}
?>

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

Шаг 8. Заключение

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

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

Данный урок подготовлен для вас командой сайта ruseller.com
Источник урока: www.net.tutsplus.com
Перевел: Сергей Фастунов
Урок создан: 12 Июля 2010
Просмотров: 94361
Правила перепечатки


5 последних уроков рубрики "PHP"

  • Фильтрация данных с помощью zend-filter

    Когда речь идёт о безопасности веб-сайта, то фраза "фильтруйте всё, экранируйте всё" всегда будет актуальна. Сегодня поговорим о фильтрации данных.

  • Контекстное экранирование с помощью zend-escaper

    Обеспечение безопасности веб-сайта — это не только защита от SQL инъекций, но и протекция от межсайтового скриптинга (XSS), межсайтовой подделки запросов (CSRF) и от других видов атак. В частности, вам нужно очень осторожно подходить к формированию HTML, CSS и JavaScript кода.

  • Подключение Zend модулей к Expressive

    Expressive 2 поддерживает возможность подключения других ZF компонент по специальной схеме. Не всем нравится данное решение. В этой статье мы расскажем как улучшили процесс подключение нескольких модулей.

  • Совет: отправка информации в Google Analytics через API

    Предположим, что вам необходимо отправить какую-то информацию в Google Analytics из серверного скрипта. Как это сделать. Ответ в этой заметке.

  • Подборка PHP песочниц

    Подборка из нескольких видов PHP песочниц. На некоторых вы в режиме online сможете потестить свой код, но есть так же решения, которые можно внедрить на свой сайт.

или авторизуйтесь, чтобы добавлять комментарии, оценивать уроки и сохранять их в личном кабинете
  • 13 Июля 2010 22:08
    AronTito
    5 балов
  • 14 Июля 2010 02:01
    Alexxhub
    Отличный урок. 5 баллов
  • 14 Июля 2010 03:50
    mikola
    Больщое спасибо, +5
  • 26 Января 2011 22:18
    Huseyn
    Урок просто супер !! Какраз надо такое зделать !! Пасиб !!!
  • 30 Января 2011 23:18
    Олег Мухомор
    Спасибо большое, эта статья просто спасла меня!
  • 23 Июля 2011 08:43
    Женя Авганец
    Спасибо
  • 1 Октября 2011 21:12
    vbodarev
    Урок отличный, но только одно но! Почему-то скрипт не парсит весь список страниц, а только текущую
    'http://net.tutsplus.com/'
    ... Вроде условие
    if($next = $html->find('a[class=nextpostslink]', 0))
    выполняется...
    • 27 Октября 2011 13:17
      SlavaIsaev
      Аналогично! Может страницы сделать циклическим перебором? Как вариант...
  • 6 Декабря 2011 15:43
    shurik330
    А вот как спарсить тэг param из <object>?? Он его просто не видит!!
  • 17 Апреля 2012 12:22
    sanyok953
    Здравствуйте подскажите вот если у меня сайт с кодировкой 1251 а контент который я спарсил utf-8 Возможно ли её поменять?
  • 17 Апреля 2012 13:59
    sanyok953
    Всё решил проблему.
    <table>
    <?php
    include('simple_html_dom.php');
    $html = new simple_html_dom();
    $html->load_file('http://www.moskva.fm/charts/users/play/songs');
    $img = $html->find("img[src^=http://t.moskva.fm/covers/]");
    $artist = $html->find(".artist");
    $name = $html->find(".song");
    $num = 0;
    do
    {
    $artist[$num] = iconv( 'utf-8' , 'cp1251', $artist[$num]);
    $name[$num] = iconv( 'utf-8' , 'cp1251', $name[$num]);
    $a = $artist[$num];
    $n = $name[$num];
    $i = $img[$num];
    printf ("
    <tr><td>%s</td>
    <td>%s</td>
    <td>%s</td></tr>
    ", $i, $n, $a);
    $num = $num + 1;
    }
    while ($num<10);
    ?>
    </table>
    
  • 17 Апреля 2012 14:01
    sanyok953
    Мне надо было вытащить 10 топов с сайта всего лишь
  • 8 Июля 2012 14:10
    igor3310
    Ждем видео уроков по парсерам!
  • 10 Декабря 2012 13:32
    webivan
    Спасибо! То что нужно)
  • 2 Мая 2013 16:51
    shamko.denis
    Подскажите, где и как можно спарсить цену определенной акций какой-либо фирмы?
  • 17 Октября 2013 20:03
    adminus
    скачал исходник, не работает попробовал переписать, все равно не работает. А как сделать парсер цены со страницы?
  • 25 Июня 2014 11:45
    master_z1zzz
    Удивляет только одно! Почему автор урока никогда не отвечает в комментариях? Сколько уроков пересмотрел и нигде ни одного ответа от автора на заданные ему вопросы. Смешно!
^ Наверх ^