Как стать автором
Обновить

MODx и парсер таблички с чужого сайта

Время на прочтение 4 мин
Количество просмотров 2.4K
Наверное любой программист слэш администратор сайта сталкивается с проблемой импорта данных с чужих сайтов. Задача эта очень тривиальна, и не требует каких-то особых знаний… вопрос только в обертке. Чтобы дополнить коллекцию статей по MODx пишу эту статью, быть может кому и пригодится.
Внимание! Никакой практической ценности данная запись не несет, только теоретическую нагрузку а-ля «Простой пример работы с back-end'ом MODx».
А задача была: таблицу со страницы example.com распарсить, переоформить и себе на сайт засунуть.

Пять копеек


Собственно пользоваться мы будем cURL'ом, поскольку для этой цели оптимальнее инструмента не найти. Перво-наперво мы создадим два шаблона parserTplOuter и parserTplInner — соответственно обертка и её «внутренности». Лично я делал таблицу, поэтому в примере будем на это ориентироваться, но никто не запрещает сделать дивы с заданными стилями.

parserTplOuter
<table>
    [+content+]
</table>

Обертка вынесена отдельно специально, чтобы можно было прописать внешний вид, расположение элементов или еще какие-то верстальские штучки не залазя в код. Придерживаемся модели MVC свято!

parserTplInner
<tr>
     <td>[+0+]</td><td>[+1+]</td><td>[+2+]</td><td>[+3+]</td>
</tr>

Тут хочется пояснить почему я сделал числовые идентификаторы: во-первых, при разработке ассоциативные массивы просто не потребовались :) а во-вторых, хоть и существует шанс запутаться, но зато получается некая стандартизация, когда очень просто добавить еще один элемент в «ряд».

Ну что ж, получили банки, давайте же их наполним соком и создадим сниппет, который назовем parser:

<?php

if (empty($url)) return false; //если сниппету не дать адреса - завершить исполнение
// тут надо сделать еще кучу проверок на валидность урла, но мы то знаем что зла не напишем сюда 
// и балбесам не дадим доступа ;)

$tplInner = (empty($tplInner)) ? 'parserTplInner' : $tplInner;        // Зададим умолчательные
$tplOuter = (empty($tplOuter)) ? 'parserTplOuter' : $tplOuter;   // чанки для сниппета

$c = (empty($count) || (!is_numeric($count)))? 6 : $count;        // Сделаем некое ограничение по кол-ву записей
$c = ($c>100) ? 100 : $c; // максимальное кол-во
$c = ($c<1) ? 1 : $c;         // минимальное кол-во

// инициализация сеанса курла
$ch = curl_init();

// установка URL и других необходимых параметров
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_TIMEOUT, 5);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

// загрузка страницы и выдача её в переменную
$html = curl_exec($ch);

// завершение сеанса и освобождение ресурсов
curl_close($ch);

if (mb_strlen($html) < 100) {return '';} //если ответ слишком короткий для обработки выходим.
//тут надо быть осторожным, поскольку вернутся может самый разнообразный код, но стандартные обрамления HTML в сумме дают примерно 100 символов..

$pattern = "/<table(?:[^>]+)>([\s\S]+)<\/table>/i";  //эта часть вырежет нам все таблицы с сайта. 
// теоретически этот шаблон можно запихнуть в чанк и там его менять, но как показывает практика все равно парсинг будет более-менее уникальный для каждого случая, и проще на основе кода написать свой, чем подгонять параметры так, чтобы получился корректный результ...

preg_match($pattern, $html, $matches);
unset($matches[0]); // кто не помнит - в 0 элемент записывается найденая строка целиком и она нам не нужна

$array = explode('</tr>', $matches[1]); //тут я пошел очень хитрым способом и преобразовал все ряды в элементы массива 

$separator = '|==|'; $table = array();   // подготовился и...

foreach ($array as &$value) {
  //(быдлокод в действии) 
    $value = str_replace('</td><td', '</td>'.$separator.'<td', $value); // ... сделал финт ушами :) 
    $value = strip_tags($value); //регулярками убирать тэги таблицы было лениво, проще разделить ячейки служебным набором символов и..
    $table[] = explode($separator, $value); //... разбить оставшееся от strip_tags по этому разделителю
}

$i = 0; //здесь стоит отметить, что 0й элемент это заголовки таблицы. если они не нужны, то следует поставить 1 и unset($table[0]); прописать
$rows = '';

foreach ($table as $row) {  
//ну теперь пробегаем по каждому ряду 
  if ($i++ > $c) break; //сверяемся со счетчиком записей
  $rows .= $modx->parseChunk($tplRow, $row, '[+', '+]'); //записываем ряд

}

echo $modx->parseChunk($tplTable, array('content'=>$rows), '[+', '+]'); // вставляем ряд и выводим результат
?>

Собственно это все что и требовалось, теперь вставляем в нужном месте на сайте такое:
 [[parser?tplInner=`parserTplInner` &tplOuter=`parserTplOuter` &url=`http://example.com` &count=`10`]] 

и видеть сформированную аккуратную табличку.

Стопроцентно ЭТОТ скрипт никому не понадобится, но при наличии головы и серого вещества в ней очень легко адаптировать данный сниппет под свои нужды. Сменить шаблон или механизм обработки вполне просто, вместо обработки таблицы прописать вырезание дива — все равно любой парсинг подоразумевает, что сайт-цель имеет какую-либо статичную структуру. И уже ориентируясь по ней мы получаем данные для обработки, а как их отобразить для решения поставленной задачи уже совсем другая головная боль.
Теги:
Хабы:
+7
Комментарии 9
Комментарии Комментарии 9

Публикации

Истории

Ближайшие события

Московский туристический хакатон
Дата 23 марта – 7 апреля
Место
Москва Онлайн
Геймтон «DatsEdenSpace» от DatsTeam
Дата 5 – 6 апреля
Время 17:00 – 20:00
Место
Онлайн