Блог

PHP парсер контента

27 апреля 2013 Рубрики: Программирование. Метки: php.

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

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

Ранее на портале футбольные турнирные таблицы заполнялись контент-менеджерами вручную. Известны случаи, когда результаты матчей появлялись на сайте Чемпионат.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. Остальные ключи просто игнорируются.

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

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

Изображение турнирной таблицы

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

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

<?xml version="1.0" encoding="UTF-8"?>

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:output method="html"/>

    <xsl:template match="/">
        <table>
            <thead>
                <tr>
                    <th></th>
                    <th>Команда</th>
                    <th>Игры</th>
                    <th>Победы</th>
                    <th>Ничьи</th>
                    <th>Проигрыши</th>
                    <th>Мячи</th>
                    <th>Очки</th>
                </tr>
            </thead>
            <tbody class="teams">
                <xsl:apply-templates select="//tr[position() > 1]" />
            </tbody>
        </table>
    </xsl:template>

    <xsl:template match="//tr[position() > 1]">
        <xsl:variable name="rowclass">
            <xsl:choose>
                <xsl:when test="position() mod 2 = 0">even</xsl:when>
                <xsl:otherwise>odd</xsl:otherwise>
            </xsl:choose>         
        </xsl:variable>

        <tr class="{$rowclass}">
            <td class="position"><xsl:number value="position()" /></td>
            <td class="name"><xsl:value-of select="td[3]/a" /></td>
            <td class="games"><xsl:value-of select="td[4]" /></td>
            <td class="wins"><xsl:value-of select="td[5]" /></td>
            <td class="draws"><xsl:value-of select="td[6]" /></td>
            <td class="losses"><xsl:value-of select="td[7]" /></td>
            <td class="balls"><xsl:value-of select="translate(td[8], '- ', '—')" /></td>
            <td class="points"><xsl:value-of select="td[9]" /></td>
        </tr>
    </xsl:template>

</xsl:stylesheet>

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

$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[2]',
        'xsl' => __DIR__.'/football.xsl'
));

print $results['zona_vostok'];

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

<table>
    <thead>
        <tr>
            <th></th>
            <th>Команда</th>
            <th>Игры</th>
            <th>Победы</th>
            <th>Ничьи</th>
            <th>Проигрыши</th>
            <th>Мячи</th>
            <th>Очки</th>
        </tr>
    </thead>
    <tbody class="teams">
        <tr class="odd">
            <td class="position">1</td>
            <td class="name">Луч-Энергия</td>
            <td class="games">20</td>
            <td class="wins">12</td>
            <td class="draws">6</td>
            <td class="losses">2</td>
            <td class="balls">30—17</td>
            <td class="points">42</td>
        </tr>
        <tr class="even">
            <td class="position">2</td>
            <td class="name">Чита</td>
            <td class="games">20</td>
            <td class="wins">12</td>
            <td class="draws">5</td>
            <td class="losses">3</td>
            <td class="balls">28—14</td>
            <td class="points">41</td>
        </tr>
        ...
    </tbody>
</table>

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

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

  1. Форкните на Гитхабе: git clone https://github.com/franzose/microparser.git
  2. Скачайте архив: https://github.com/franzose/microparser/archive/master.zip