Php парсер html страниц. Парсер на PHP – это просто. Получение блока по id

Решил привести статью в актуальный вид. Ранее на данной странице был представлен универсальный парсер HTML страниц на PHP. Но прошло уже более 4 лет, я наработал больше опыта в области разработки парсеров. И решил выложить новый пример PHP парсера с детальным разбором алгоритма работы.

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

Иногда необходимо читать данные пользователя, такие как выражения формул, простую разметку или даже форматирование строк. Этот пользовательский ввод должен быть проанализирован и преобразован в форму, которую вы можете обрабатывать. Возможно, вы хотите построить иерархию объектов или вы хотите создать форматированную выходную строку, которая отражает то, что пользователь набрал.

Кроме того, вы хотите, чтобы ваш парсер сообщал пользователю, когда возникла проблема с вводом, например, синтаксическая ошибка, и создать значимое сообщение об ошибке. Процесс разбора пользовательского ввода содержит ряд шагов. Маркер может быть одним символом или рядом символов.

Я подумал, подумал и решил, что более универсальным решением будет показать пример парсера на PHP и рассказать, как он работает. Так программисты, которые ранее не писали парсеров смогут решить свои задачи. А заказчики смогут понять возможности PHP в области парсинга сайтов и что реально можно требовать от программистов.

Парсер — это программа, которая анализирует входные текстовые данные, извлекает нужную информацию и на основе полученных данных выдаёт результат в заданном формате.

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

Общий алгоритм PHP парсинга предполагает, что ваш скрипт делает запрос по заданному адресу, получает ответ от сервера в виде HTML страницы, либо в каком-то другом текстовом формате, например CSV, JSON, XML. Далее полученная информация анализируется, из неё извлекаются (парсятся) нужные данные, на основе которых формируется результат. Полученные данные можно вывести на экран, либо записать в файл или БД.

В этой серии мы рассмотрим только простую грамматику. Для простых грамматик парсер может быть закодирован вручную с использованием алгоритма рекурсивного спуска. Эти действия необходимы, чтобы превратить входную строку в структуру данных, которую позже может использовать программа. Действия могут включать построение древовидной структуры объектов или запись фрагмента форматированной строки в поток.

Написание анализатора, в зависимости от языка, представляет собой умеренно сложную задачу. По сути, он должен преобразовать кусок кода в «абстрактное синтаксическое дерево». Например, для следующего текста программы. Основная трудность написания парсера состоит в неспособности правильно организовать код. Парсер должен работать на более высоком уровне, чем чтение символов из строки. Несколько советов о том, как сохранить сложность в управлении.

Пример простого PHP парсера html контента

Предположим нам нужно спарсить цену на товара на сайте gearbest.com. Скрипт считывает заданную страницу, потом посредством регулярных выражений анализирует её контент и выделяет нужные нам куски HTML кода. Далее полученный результат выводится на экран.

/Us"; $buffer = array(); preg_match($regexp, $page, $buffer); $res_arr["price_list"]["currency"] = $buffer; $res_arr["error"] = ""; } else { $res_arr["price"] = 0; $res_arr["currency"] = "nodata"; $res_arr["error"] = "Ошибка загрузки страницы"; } return $res_arr; } /* --- 1.4 --- Вывод данных в HTML */ /* --- 1.4.1 --- Вывод полученых цен */ function price_list_html($price_list) { echo "

Цена: " . $price_list["price"] . " " . $price_list["currency"] . "

Получение элементов по классу

  • Напиши много функций и сохрани их мало.
  • В каждой функции делайте одно и делайте это хорошо.
  • Не пытайтесь использовать регулярные выражения для синтаксического анализа.
Поскольку это сторонний модуль, вам придется установить его самостоятельно. Эта библиотека очень проста в использовании, но есть некоторые основы, которые вы должны рассмотреть, прежде чем вводить их в действие.

Первый абзац будет иметь индекс 0, а последующие абзацы будут индексироваться соответственно. Внутренний текст представляет собой содержимое между тегами, в то время как внешний текст представляет содержимое, включая тег. Мы можем полностью заменить тег, используя внешний текст. Мы собираемся добавить еще одну строку и изменить класс нашего тега второго абзаца.

"; } /* --- 1.4.2 --- Вывод ошибок */ function error_list_html($error) { if (!empty($error)) { echo "

Во время обработки запроса произошли следующие ошибки:

\n"; echo "
    \n"; foreach($error as $error_row) { echo "
  • " . $error_row . "
  • \n"; } echo "
\n"; echo "

Статус: FAIL

\n"; } else { echo "

Статус: OK

\n"; } } /* --- 1.4.3 --- Вывод ошибок загрузки страниц */ function error_page_list_html($error_page) { if (!empty($error_page)) { echo "
    \n"; foreach($error_page as $error_row) { echo "
  • [" . $error_row . "] " . $error_row . " - " . $error_row . "
  • \n"; } echo "
\n"; } } /* --- 1.4.4 --- Вывод работы скрипта */ function run_time_html($time_start) { if(!empty($time_start)) echo "\n"; } /* --- 2 --- Получение контента из каталога Gearbest */ if($action) { // если ошибок нет и данные формы поиска получены if(!empty($gearbest_url)) { $gearbest_url = trim($gearbest_url); $din_url = $gearbest_url; $res_arr = get_gearbest_price($din_url); $price_list = $res_arr["price_list"]; $error_page = $res_arr["error_page"]; $error = $res_arr["error"]; } else { $error = "Не задан адрес страницы с товаром"; } } /* --- 3 --- Вывод результатов работы парсера */ ?>

Парсер цены товара на Gearbest.com

Мы здесь, и мы здесь, чтобы остаться. Вот некоторые примеры селекторов. Однако, указав второй параметр, мы говорим: «верните только первый элемент этой коллекции». Остальные примеры не требуют пояснений. Полную документацию по библиотеке можно найти на.

Поиск информации, которую мы хотим

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

index.php — основной файл PHP скрипта парсера. Код парсера актуален на момент публикации. Со временем HTML код сайта источника может меняться и регулярные выражения уже не будут к нему подходить.

Существуют разные способы установки скрипта. Я работал с ним из-под XAMPP. Но можно парсер запускать прямо с . Просто заливаете файл index.php к себе на сайт в какую-либо папку и обращаетесь к нему через адресную строку браузера. Предположим, что вы закинули скрипт в папку my-parser в корневой директории вашего хостинга. Тогда в адресной строке нужно набрать URL: http://вашдомен.ru/my-parser/ .

Первое, что мы делаем, - это определить, как найти нашу следующую страницу. Теперь эту информацию можно использовать. Несоблюдение этого требования может привести к тому, что вы съедите всю имеющуюся у вас память. Эта рекурсия заканчивается, когда больше не нужно анализировать страницы.

Получение и парсинг страницы

Сначала мы собираемся создать несколько базовых стилей. Это совершенно произвольно - вы можете сделать свой вывод таким, каким хотите. Если вы разбираете большое количество страниц, это может занять больше времени, чем максимальное время выполнения, разрешенное вашим сервером. Например, работая с моей локальной машины, она занимает около одной секунды на страницу.

Скриншот главной страницы парсера цены с сайта gearbest.com:

1. На главной странице парсера мы должны ввести адрес страницы товара. После нажатия на кнопку «Старт» страница перезагружается, отправляются данные формы на сервер и PHP скрипт делает запрос по заданному адресу с помощью библиотеки cURL.

За это действие отвечает функция curl_get_contents() , которая является аналогом стандартной PHP функции file_get_contents() , но с расширенным на основе cURL функционалом.
cURL — это расширение для PHP, которое обеспечивает поддержку библиотеки функций libcurl. Данный набор функций позволяет формировать POST и PUT запросы, скачивать файлы. Поддерживаются различные протоколы http, https, ftp и пр. Можно использовать прокси-серверы, cookies и аутентификацию пользователей. В общем, отличный инструмент для имитации действий пользователя в браузере.

В качестве заключительной заметки всегда помните о получении разрешения до соскабливания сайта; это важно. При выборе имени без хэш-префикса обратите внимание, что привязка шаблона страницы, имя которой идентично функции, за которой следует двоеточие, больше не возможно. В частности, избегайте имен функций, равных имени пространства имен.

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

cURL штука для разработки HTML парсеров очень полезная, и в одной из я более подробно расскажу о приёмах работы с ней для целей парсинга.


Обратите внимание, что скрипт видит страницу в текстовом формате и анализировать предстоит именно её HTML код.

Найдено Возвращаемый текст действителен, останавливая шаблон. Пользователи часто привыкли использовать вертикальные штрихи для разделения параметров, поэтому они также могут быть полезны в контексте функции парсера, чтобы это разрешить. Вот простой пример того, как это можно достичь. К этому добавляется код, который используется для вывода текста, то есть, например, абзац или заголовок. Существуют определенные символы из обычного набора символов для вывода текста.

Содержание между ними - это «область действия» соответствующего элемента. Теги отмечены в заостренных скобках. Пример показывает заголовок. Вводный тег сигнализирует, что заголовок следует порядку. Последний день сигнализирует о завершении курса. Последний день начинается с открытия заостренной фигурной скобки и косой черты.

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

Существуют также некоторые элементы с «автономными тегами», т.е. элементы, которые не содержат содержимого и поэтому состоят только из одного тега вместо начального и конечного тегов. Пустые «автономные» элементы и теги Освобожденные от льда потоки и потоки Через освежающий, бодрящий вид.

В конце первой строки это означает, что должен быть вставлен ручной разрыв строки. Кроме того, вы также можете записать элемент с начальным и конечным тегом, но без содержимого. Элементы могут вставляться друг в друга. Это создает иерархическую структуру. Поэтому эксперты также говорят о структурированной разметке.

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

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

Получение href ссылок

Текст между и получает другое представление, часто выделенное курсивом, в большинстве браузеров. Предварительные теги и автономные теги могут содержать дополнительную информацию. Атрибуты с назначением предопределенных значений, Например, поле ввода для простого текста - здесь допускаются только определенные значения. Атрибуты со свободным присваиванием значений, однако, ожидается определенный тип данных или соглашение, Например, чтобы определить диапазон для таблиц стилей. Или - поле ввода, в которое пользователь может ввести до 10 символов - здесь ожидается числовая спецификация. Одиночные атрибуты. . Это уменьшает вероятность ошибок при размещении всех значений, которые вы назначаете атрибутам, в простые «или двойные» кавычки.

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

«Микропарсер» состоит всего-навсего из одной функции - 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

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

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

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