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

С недавних пор я работаю в компании ООО «Радио Сити Сахалин» в команде разработчиков и журналистов информационно-развлекательного портала «Ситисах ». Специально для футбольных фанатов на портале поддерживается раздел «Спорт » с новостями из мира футбола, турнирными таблицами и списком игроков команды ФК «Сахалин».

Сейчас портал переживает редизайн, поэтому разделом «Спорт» было поручено заняться мне. Основная моя функция в команде - вёрстка макетов нового дизайна. Иногда приходится решать и побочные задачи, дабы облегчить и без того нелёгкую работу нашего основного программиста. Сегодня я расскажу о «Микропарсере».

Ранее на портале футбольные турнирные таблицы заполнялись контент-менеджерами вручную. Известны случаи, когда результаты матчей появлялись на сайте Чемпионат.com быстрее, чем на нашем портале. Теперь же мы решили, наконец-то, сделать обновление таблиц автоматическим. Так как Чемпионат.com не предоставляет API (по крайней мере некоего открытого) для получения выводимых им турнирных таблиц, единственный выход - парсить.

Как использовать «Микропарсер»

«Микропарсер» состоит всего-навсего из одной функции - parse_site(array $sites, array $defaults = array()) . Первым аргументом передаётся массив сайтов (или страниц на одном сайте), которые необходимо распарсить, а вторым - массив настроек по умолчанию.

Массив $sites имеет следующий формат:

Array("zona_vostok" => array("url" => "http://www.championat.com/football/_russia2d/589/table/all.html", "xpath" => "some/x/path", //необязательный "xsl" => "absolute/path/to/xsl", //необязательный), "stackoverflow" => array("url" => "http://stackoverflow.com", "xpath" => "some/x/path", "transform" => false //необязательный));

Все ключи, кроме url - опциональны. В случае, если выражение XPath отсутствует, страница, указанная в значении ключа url , будет обработана полностью. Лист стилей XSL также можно подключить только в случае необходимости обработки «сырого» кода.

Обратите внимание на ключ "transform" => false . Он используется в том, случае, если массив $defaults содержит лист стилей XSL по умолчанию, но для данной страницы в трансформации нет необходимости.

Массив $defaults позволяет избежать копирования настроек в массиве $sites . Он может содержать только два ключа: xpath и xsl . Остальные ключи просто игнорируются.

Резюме

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

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

Рабочий пример

Давайте рассмотрим турнирную таблицу чемпионата России по футболу во втором дивизоне, зона «Восток».

Поскольку нам необходимо «вытащить» со страницы непосредственно турнирную таблицу, выражение XPath будет следующим: //div[@id="section-statistics"]/table

Исходная таблица содержит много мусора: атрибуты, классы, инлайновые стили. Поэтому мы преобразим её в более приятный вид с помощью листа стилей XSL со следующим содержанием:

Команда Игры Победы Ничьи Проигрыши Мячи Очки
even odd

Теперь напишем код, чтобы вывести готовую турнирную таблицу.

$results = parse_site(array("zona_vostok" => array("url" => "http://www.championat.com/football/_russia2d/589/table/all.html", "xpath" => "xpath" => "//div[@id="section-statistics"]/table", "xsl" => __DIR__."/football.xsl")); print $results["zona_vostok"];

И на выходе получим вот такой код HTML:

Команда Игры Победы Ничьи Проигрыши Мячи Очки ...
1 Луч-Энергия 20 12 6 2 30-17 42
2 Чита 20 12 5 3 28-14 41

Скачать «Микропарсер»

Вот несколько способов заполучить «Микропарсер»:

  • Форкните на Гитхабе: git clone https://github.com/franzose/microparser.git
  • Скачайте архив:
  • Потихоньку изучаю возможности PHP для создания парсеров. Я уже писала о том, как парсить . Сейчас расскажу об одном из способов парсинга html (он подойдет и для xml тоже, кстати). Повторю, что в php я не гуру, поэтому буду очень признательна, если вы оставите свои комментарии к поднятой теме.

    Побродив по нашим и англоязычным форумам, поняла, что спор о том, лучше ли парсить html регулярными выражениями или использовать для этих целей возможности PHP DOM , является холиваром. Сама же я пришла к выводу, что все зависит от сложности структуры данных. Ведь если структура достаточно сложная, то с помощью регулярок приходится парсить в несколько этапов: сначала выделить большой кусок, потом разделить его на более маленькие и т.д.. В итоге, если данные сложные (или их очень много), то процесс парсинга может значительно затянуться. Ресурсоемкость в этом случае еще будет зависеть, конечно же, от самих регулярных выражений. Если в регэкспах много ".*" (они являются самыми ресурсоемкими, т.к. "прочесывают" исходный код с максимальной жадностью), то замедление будет заметным.

    И вот как раз в этом-то случае как нельзя кстати приходится PHP DOM. Это удобный инструмент для парсинга как XML, так и HTML. Некоторые придерживаются мнения, что парсить html регэкспами вообще нельзя, и яростно защищают PHP DOM.

    В свою очередь я ознакомилась с этим расширением, написав простенький скрипт. Который и привожу здесь, чтобы наглядно показать, как это все легко и просто. В примере разбирается html с частью карты сайта этого блога. Он присвоен переменной прямо внутри кода. В "боевых" же условиях исходные данные следует получать, например, через file_get_contents().