Парсинг html страницы php. Пишем парсер контента на 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 . Остальные ключи просто игнорируются.

Резюме

Написанный мной парсер состоит из одной функции с двумя параметрами (для частных и общих настроек), позволяет загружать страницу целиком или её отдельный фрагмент, а также, по желанию, обрабатывать результат таблицей стилей 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. Скачайте архив:
контент php парсить страниц

Заметка посвящается парсингу, в частности парсинг сайтов, парсинг страниц, парсинг в веб-среде, парсинг html-контента сайта.

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

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

Давайте попробуем спарсить нужную информацию в html, попробуем достать все ссылки с нескольких страниц нашего сайта.

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

Хочу показать 2 основных способа получения контента со страницы сайта:

В первую очередь приготовим массив с нужными адресами страниц:

//3 ссылки нашего сайта: $urls = array("http://hello-site..ru/games/");

1 вариант - php функция file_get_contents . Функция возвращает html-строку, которую мы будем парсить на ссылки:

//помещаем каждую ссылку в функцию file_get_contents foreach($urls as $urlsItem){ $out .= file_get_contents($urlsItem); //и добавляем содержание каждой страницы в строку } echo $out; //здесь контент всех трех страниц

2 вариант - CURL . Библиотека, которая поддерживается php и имеет большой набор настроек, от POST-запросов до работы с FTP. Рассмотрим стандартный вызов библиотеки curl, который отдаст нам контент сайта:

foreach($urls as $urlsItem){ //пропускаем каждую ссылку в цикле $output = curl_init(); //подключаем курл curl_setopt($output, CURLOPT_URL, $urlsItem); //отправляем адрес страницы curl_setopt($output, CURLOPT_RETURNTRANSFER, 1); curl_setopt($output, CURLOPT_HEADER, 0); $out .= curl_exec($output); //помещаем html-контент в строку curl_close($output); //закрываем подключение } echo $out; //здесь контент всех трех страниц

Теперь в нашей строке $out находится контент всех трех страниц. Итак, переходим непосредственно к парсингу нашей строки.

Опять же хочу показать 3 варианта решения нашей задачи: "нативный" способ на php, с помощью встроенной библиотеки DOMDocument и библиотеки SimpleHTMLDOM.

1. php функция explode . Функция находит искомый символ или часть строки и делит целую строку на элементы массива.

Повторюсь, нам необходимо получить значения всех атрибутов href у тегов a, для этого будем делить общую строку на некоторые части\отрезки:

// explode $hrefs = explode("

Если распечатать наш массив, будет примерно следующее:

Array ( => / => /hello => /timer/ => /leftmenu/ => /faq/ => /blog/ => /web-notes/ => /ordersite/ => /games)

2. встроенная библиотека DOMDocument . Работаем с классом примерно следующим образом:

//domelement $dom = new DOMDocument; //создаем объект $dom->loadHTML($out); //загружаем контент $node = $dom->getElementsByTagName("a"); //берем все теги a for ($i = 0; $i < $node->length; $i++) { $hrefText = $node->item($i)->getAttribute("href"); //вытаскиваем из тега атрибут href } foreach($hrefText as $hrefTextItem){ //избавляемся от ссылок с пустым атрибутом href if($hrefTextItem!=""){ $clearHrefs=$hrefTextItem; } } $clearHrefs = array_unique($clearHrefs); //избавляемся от одинаковых ссылок print_r($clearHrefs); // в итоге у нас массив со всем ссылками с 3х страниц

Результат такого кода ровно такой же, что и с помощью функции explode.

3. библиотека SimpleHTMLDOM . Ее необходимо подключать из файла. Работа примерно схожа с DOMDocument. Работаем с классом:

//simplehtml include("simple_html_dom.php"); //подключаем файл с классом SimpleHTMLDOM $html = new simple_html_dom(); //создаем объект $html->load($out); //помещаем наш контент $collection = $html->find("a"); //собираем все теги a foreach($collection as $collectionItem) { $articles = $collectionItem->attr; //массив всех атрибутов, href в том числе } foreach($articles as $articlesItem){ $hrefText = $articlesItem["href"]; //собираем в массив значения подмассива с ключом href } foreach($hrefText as $hrefTextItem){ //избавляемся от ссылок с пустым атрибутом href if($hrefTextItem!=""){ $clearHrefs=$hrefTextItem; } } $clearHrefs = array_unique($clearHrefs); //избавляемся от одинаковых ссылок print_r($clearHrefs); // в итоге у нас массив со всем ссылками с 3х страниц

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

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


Чтобы написать хороший и работоспособный скрипт для парсинга контента нужно потратить немало времени. А подходить к сайту-донору, в большинстве случаев, стоит индивидуально, так как есть масса нюансов, которые могут усложнить решение нашей задачи. Сегодня мы рассмотрим и реализуем скрипт парсера при помощи CURL, а для примера получим категории и товары одного из популярных магазинов.

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

Работать мы будем с CURL, но для начала давайте разберёмся, что эта аббревиатура обозначает. CURL – это программа командной строки, позволяющая нам общаться с серверами используя для этого различные протоколы, в нашем случаи HTTP и HTTPS. Для работы с CURL в PHP есть библиотека libcurl, функции которой мы и будем использовать для отправки запросов и получения ответов от сервера.


Как можно увидеть из скриншота все категории находятся в ненумерованном списке, а подкатегории:


Внутри отельного элемента списка в таком же ненумерованном. Структура несложная, осталось только её получить. Товары мы возьмем из раздела «Все телефоны»:


На странице получается 24 товара, у каждого мы вытянем: картинку, название, ссылку на товар, характеристики и цену.

Пишем скрипт парсера

Если вы уже прочли предыдущею статью, то из неё можно было подчеркнуть, что процесс и скрипт парсинга сайта состоит из двух частей:

  1. Нужно получить HTML код страницы, которой нам необходим;
  2. Разбор полученного кода с сохранением данных и дальнейшей обработки их (как и в первой статье по парсингу мы будем использовать phpQuery, в ней же вы найдете, как установить её через composer).

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

Class Parser{ public static function getPage($params = ){ if($params){ if(!empty($params["url"])){ $url = $params["url"]; // Остальной код пишем тут } } return false; } }

Основной метод, который у нас будет – это getPage() и у него всего один обязательный параметр URL страницы, которой мы будем парсить. Что ещё будет уметь наш замечательный метод, и какие значения мы будем обрабатывать в нем:

  • $useragent – нам важно иметь возможность устанавливать заголовок User-Agent, так мы сможем сделать наши обращения к серверу похожими на обращения из браузера;
  • $timeout – будет отвечать за время выполнения запроса на сервер;
  • $connecttimeout – так же важно указывать время ожидания соединения;
  • $head – если нам потребуется проверить только заголовки, которые отдаёт сервер на наш запрос этот параметр нам просто будет необходим;
  • $cookie_file – тут всё просто: файл, в который будут записывать куки нашего донора контента и при обращении передаваться;
  • $cookie_session – иногда может быть необходимо, запрещать передачу сессионных кук;
  • $proxy_ip – параметр говорящий, IP прокси-сервера, мы сегодня спарсим пару страниц, но если необходимо несколько тысяч, то без проксей никак;
  • $proxy_port – соответственно порт прокси-сервера;
  • $proxy_type – тип прокси CURLPROXY_HTTP, CURLPROXY_SOCKS4, CURLPROXY_SOCKS5, CURLPROXY_SOCKS4A или CURLPROXY_SOCKS5_HOSTNAME;
  • $headers – выше мы указали параметр, отвечающий за заголовок User-Agent, но иногда нужно передать помимо его и другие, для это нам потребуется массив заголовков;
  • $post – для отправки POST запроса.

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

$useragent = !empty($params["useragent"]) ? $params["useragent"] : "Mozilla/5.0 (Windows NT 6.3; W…) Gecko/20100101 Firefox/57.0"; $timeout = !empty($params["timeout"]) ? $params["timeout"] : 5; $connecttimeout = !empty($params["connecttimeout"]) ? $params["connecttimeout"] : 5; $head = !empty($params["head"]) ? $params["head"] : false; $cookie_file = !empty($params["cookie"]["file"]) ? $params["cookie"]["file"] : false; $cookie_session = !empty($params["cookie"]["session"]) ? $params["cookie"]["session"] : false; $proxy_ip = !empty($params["proxy"]["ip"]) ? $params["proxy"]["ip"] : false; $proxy_port = !empty($params["proxy"]["port"]) ? $params["proxy"]["port"] : false; $proxy_type = !empty($params["proxy"]["type"]) ? $params["proxy"]["type"] : false; $headers = !empty($params["headers"]) ? $params["headers"] : false; $post = !empty($params["post"]) ? $params["post"] : false;

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

If($cookie_file){ file_put_contents(__DIR__."/".$cookie_file, ""); }

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

Для работы с CURL нам необходимо вначале инициализировать сеанс, а по завершению работы его закрыть, также при работе важно учесть возможные ошибки, которые наверняка появятся, а при успешном получении ответа вернуть результат, сделаем мы это таким образам:

$ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); // Далее продолжаем кодить тут curl_setopt($ch, CURLINFO_HEADER_OUT, true); $content = curl_exec($ch); $info = curl_getinfo($ch); $error = false; if($content === false){ $data = false; $error["message"] = curl_error($ch); $error["code"] = self::$error_codes[ curl_errno($ch) ]; }else{ $data["content"] = $content; $data["info"] = $info; } curl_close($ch); return [ "data" => $data, "error" => $error ];

Первое, что вы могли заметить – это статическое свойство $error_codes, к которому мы обращаемся, но при этом его ещё не описали. Это массив с расшифровкой кодов функции curl_errno(), давайте его добавим, а потом разберем, что происходит выше.

Private static $error_codes = [ "CURLE_UNSUPPORTED_PROTOCOL", "CURLE_FAILED_INIT", // Тут более 60 элементов, в архиве вы найдете весь список "CURLE_FTP_BAD_FILE_LIST", "CURLE_CHUNK_FAILED" ];

После того, как мы инициализировали соединения через функцию curl_setopt(), установим несколько параметров для текущего сеанса:

  • CURLOPT_URL – первый и обязательный - это адрес, на который мы обращаемся;
  • CURLINFO_HEADER_OUT –массив с информацией о текущем соединении.

Используя функцию curl_exec(), мы осуществляем непосредственно запрос при помощи CURL, а результат сохраняем в переменную $content, по умолчанию после успешной отработки результат отобразиться на экране, а в $content упадет true. Отследить попутную информацию при запросе нам поможет функция curl_getinfo(). Также важно, если произойдет ошибка - результат общения будет false, поэтому, ниже по коду мы используем строгое равенство с учетом типов. Осталось рассмотреть ещё две функции это curl_error() – вернёт сообщение об ошибке, и curl_errno() – код ошибки. Результатом работы метода getPage() будет массив, а чтобы его увидеть давайте им воспользуемся, а для теста сделаем запрос на сервис httpbin для получения своего IP.

Кстати очень удобный сервис, позволяющий отладить обращения к серверу. Так как, например, для того что бы узнать свой IP или заголовки отправляемые через CURL, нам бы пришлось бы писать костыль.
$html = Parser::getPage([ "url" => "http://httpbin.org/ip" ]);

Если вывести на экран, то у вас должна быть похожая картина:

Если произойдет ошибка, то результат будет выглядеть так:


При успешном запросе мы получаем заполненную ячейку массива data с контентом и информацией о запросе, при ошибке заполняется ячейка error. Из первого скриншота вы могли заметить первую неприятность, о которой я выше писал контент сохранился не в переменную, а отрисовался на странице. Чтобы решить это, нам нужно добавить ещё один параметр сеанса CURLOPT_RETURNTRANSFER.

Curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

Обращаясь к страницам, мы можем обнаружить, что они осуществляют редирект на другие, чтобы получить конечный результат добавляем:

Curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);

Теперь можно увидеть более приятную картину:

Curl_setopt($ch, CURLOPT_USERAGENT, $useragent); curl_setopt($ch, CURLOPT_TIMEOUT, $timeout); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $connecttimeout);

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

If($head){ curl_setopt($ch, CURLOPT_HEADER, true); curl_setopt($ch, CURLOPT_NOBODY, true); }

Мы отключили вывод тела документа и включили вывод шапки в результате:


If(strpos($url, "https") !== false){ curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, true); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true); }

Уже получается весьма неплохой скрипт парсера контента, мы добрались до кук и тут стоит отметить - частая проблема, когда они не сохраняются. Одной из основных причин может быть указание относительного пути, поэтому нам стоит это учесть и написать следующие строки:

If($cookie_file){ curl_setopt($ch, CURLOPT_COOKIEJAR, __DIR__."/".$cookie_file); curl_setopt($ch, CURLOPT_COOKIEFILE, __DIR__."/".$cookie_file); if($cookie_session){ curl_setopt($ch, CURLOPT_COOKIESESSION, true); } }

Предлагаю проверить, а для этого я попробую вытянуть куки со своего сайта:


If($proxy_ip && $proxy_port && $proxy_type){ curl_setopt($ch, CURLOPT_PROXY, $proxy_ip.":".$proxy_port); curl_setopt($ch, CURLOPT_PROXYTYPE, $proxy_type); } if($headers){ curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); } if($post){ curl_setopt($ch, CURLOPT_POSTFIELDS, $post); }

Это малая доля параметров, с которыми можно работать, все остальные находятся в официальной документации PHP . Вот мы завершили с нашей оберткой, и пришло время, что-нибудь спарсить!

Парсим категории и товары с сайта

Теперь, при помощи нашего класса Parser, мы можем сделать запрос и получить страницу с контентом. Давайте и поступим:

$html = Parser::getPage([ "url" => "https://www.svyaznoy.ru/catalog" ]);

Следующим шагом разбираем пришедший ответ и сохраняем название и ссылку категории в результирующий массив:

If(!empty($html["data"])){ $content = $html["data"]["content"]; phpQuery::newDocument($content); $categories = pq(".b-category-menu")->find(".b-category-menu__link"); $tmp = ; foreach($categories as $key => $category){ $category = pq($category); $tmp[$key] = [ "text" => trim($category->text()), "url" => trim($category->attr("href")) ]; $submenu = $category->next(".b-category-submenu")->find(".b-category-submenu__link"); foreach($submenu as $submen){ $submen = pq($submen); $tmp[$key]["submenu"] = [ "text" => trim($submen->text()), "url" => trim($submen->attr("href")) ]; } } phpQuery::unloadDocuments(); }

Чуть более подробно работу с phpQuery я разобрал в первой статье по парсингу контента. Если вкратце, то мы пробегаемся по DOM дереву и вытягиваем нужные нам данные, их я решил протримить, чтобы убрать лишние пробелы. А теперь выведем категории на экран:

  • " target="_blank">
    • " target="_blank">

$html = Parser::getPage([ "url" => "https://www.svyaznoy.ru/catalog/phone/224", "timeout" => 10 ]);

Получаем страницу, тут я увеличил время соединения, так как 5 секунд не хватило, и разбираем её, парся необходимый контент:

If(!empty($html["data"])){ $content = $html["data"]["content"]; phpQuery::newDocument($content); $products = pq(".b-listing__generated-container")->find(".b-product-block .b-product-block__content"); $tmp = ; foreach($products as $key => $product){ $product = pq($product); $tmp = [ "name" => trim($product->find(".b-product-block__name")->text()), "image" => trim($product->find(".b-product-block__image img")->attr("data-original")), "price" => trim($product->find(".b-product-block__misc .b-product-block__visible-price")->text()), "url" => trim($product->find(".b-product-block__info .b-product-block__main-link")->attr("href")) ]; $chars = $product->find(".b-product-block__info .b-product-block__tech-chars li"); foreach($chars as $char){ $tmp[$key]["chars"] = pq($char)->text(); } } phpQuery::unloadDocuments(); }

Теперь проверим, что у нас получилось, и выведем на экран:

" target="_blank" class="tovar"> " alt="" />

Вот мы и написали парсер контента PHP, как видите, нет нечего сложного, при помощи этого скрипта можно легко спарсить страницы любого сайта, но перед тем, как заканчивать статью, хотелось пояснить некоторые моменты. Во-первых, если вы хотите парсить более одной страницы, то не стоит забывать, что сам процесс парсинга ресурса затратная операция, поэтому в идеале лучше, чтобы скрипт был вынесен на отдельный сервер, где и будет запускаться по крону. Ещё один момент - к каждому донору стоит подходить индивидуально, так как, во-первых: у них разный HTML код и он, с течением времени, может меняться, во-вторых: могут быть различные защиты от парсинга и проверки, поэтому для подбора необходимого набора заголовков и параметров может потребоваться отладочный прокси (я пользуюсь Fiddler). И последние, что я добавлю - используйте для парсинга прокси и чем больше, тем лучше, так как, когда на сервер донора полетят тысячи запросов, то неизбежно IP, с которого осуществляется обращение будет забанен, поэтому стоит прогонять свои запросы через прокси-сервера.

Полный пример с библеотекай phpQuery вы найдете на github .

Отличная статья. Спасибо. Как раз сейчас разбираю пхп и тему парсеров.

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

Если вам необходимо сделать парсинг HTML документа, регулярные выражения не наилучший способ для этого. К тому же их написание, трудоемкий процесс, и они уменьшают скорость работы PHP приложения. В этой статье, вы узнаете, как использовать свободный парсер HTML, для чтения, изменения, извлечения некоторых DOM элементов из HTML страниц. Причем, HTML ресурсом может быть внешний источник. То есть адрес HTML страницы на другом домене. Используя, как пример, сайт sitear. ru , вы узнаете, как получить и вывести список всех опубликованных материалов на главной странице сайта. Другими словами, вы будете делать то, что вам необходимо, парсинг HTML с помощью PHP. В данном случае под PHP, подразумевается библиотека simple HTML DOM.

Просто следуйте всем шагам статьи, и узнаете много нового и полезного для себя!

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

Для начала, вам необходимо скачать копию simple HTML dom библиотеки. Скачивание свободно.

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

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

Эта библиотека, очень проста в использовании, но все же, необходимо разобрать некоторые основы, перед тем как ее использовать.

$html = new simple_html_dom(); // Load from a string $html->load("

Hello World!

"); // Load a file $html->load_file("http://сайт/");

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

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

Получение доступа к HTML DOM объектам


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

Hello World!

We"re Here.

Используя этот пример HTML кода, мы узнаем, как получить доступ к информации заключенной во втором параграфе (p). Также, мы изменим полученную информацию и выведем результат на дисплей.

// создание объекта парсера и получение HTML include("simple_html_dom.php"); $html = new simple_html_dom(); $html->load("

Hello World!

"); // получение массивов параграфов $element = $html->find("p"); // изменение информации внутри параграфа $element->innertext .= " and we"re here to stay."; // вывод echo $html->save();

Как видите реализовать PHP парсинг документа HTML, очень даже просто, используя simple HTML DOM библиотеку. В принципе, в этом куске PHP кода, все можно понять интуитивно, но если вы в чем-то сомневаетесь, мы рассмотрим код.

Линия 2-4 : подключаем библиотеку, создаем объект класса и загружаем HTML код из строки.

Линия 7: С помощью данной строки, находим все

теги в HTML коде, и сохраняем в переменной в виде массива. Первый параграф будет иметь индекс 0, остальные параграфы будут индексированы соответственно 1,2,3…

Линия 10: Получаем содержимое второго параграфа в нашей коллекции. Его индекс будет 1. Также мы вносим изменения в текст с помощью атрибута innertext. Атрибут innertext, меняет все содержимое внутри указанного тега. Также мы сможем изменить сам тег с помощью атрибута outertext.

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

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

Результатом выполнения нашего кода будет следующий HTML документ:

Hello World!

We"re here and we"re here to stay.

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

Ниже приведены другие примеры селекторов. Если вы использовали jQuery, то в библиотеке simple html dom синтаксис немножко схожий.

// получить первый элемент с id="foo" $single = $html->find("#foo", 0); // получает при парсинге все элементы с классом class="foo" $collection = $html->find(".foo"); // получает все теги при парсинге htmlдокумента $collection = $html->find("a"); // получает все теги , которые помещены в тег

$collection = $html->find("h1 a"); // получает все изображения с title="himom" $collection = $html->find("img");

Использование первого селектора при php парсинге html документа, очень простое и понятное. Его уникальность в том что он возвращает только один html элемент, в отличии от других, которые возвращают массив (коллекцию). Вторым параметром (0), мы указываем, что нам необходим только первый элемент нашей коллекции. Надеюсь, вам понятны все варианты селекторов библиотеки simple HTML DOM, если вы чего-то не поняли, попробуйте метод научного эксперимента. Если даже он не помог, обратитесь в комментарии к статье.

Документация библиотеки simple HTML DOM

Полнейшую документацию по использованию библиотеки simple HTML DOM вы сможете найти по этому адресу:

http://simplehtmldom.sourceforge.net/manual.htm

Просто предоставлю вам иллюстрацию, которая показывает возможные свойства выбранного HTML DOM элемента.


Шаг 3 – Реальный пример PHP парсинга HTML документа

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


Include("simple_html_dom.php"); $articles = array(); getArticles("http://сайт/");

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

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

Это базовый шаблон данной страницы. При написании парсера html, нужно тщательно исследовать документ, так как и комментарии, типа , это тоже потомки. Другими словами, в глазах библиотеки simple HTML DOM, это элементы, которые равноценны другим тегам страницы.

Шаг 4 – Пишем основную функцию PHP парсера HTML

function getArticles($page) { global $articles; $html = new simple_html_dom(); $html->load_file($page); // ... далее будет... }

Вначале функции, мы вызываем наш глобальный массив, который мы указали ранее. Создаем новый объект simple_html_dom. Далее загружаем страницу, которую будем парсить.

Шаг 5 – Находим нужную информацию

$items = $html->find("div"); foreach($items as $names) { $articles = array($post->children(0)->plaintext); }

В этом куске кода все предельно просто, мы находим все div с class=name_material. Далее читаем коллекцию элементов и выбираем названия материалов. Все материалы будут сохранены в массиве в данном виде:

$articles = "Имя материала 1"; $articles = "Имя материала 2"; …

Шаг 6 – Выводим результат парсинга

Для начала, мы установим некоторые стили, для красоты выводимой информации, которую получили при парсинге.

Item { padding:10px; color:#600; font:bold 40px/38px helvetica, verdana, sans-serif; }

"; echo $item; echo "

"; } ?>

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

Заключение

Вот мы и научились php парсингу html документов. Помните, что парсинг это долгий процесс. Одна страница может парситься около одной секунды. Если вы будете делать парсинг большого числа HTML документов, ваш сервер может перервать работу скрипта в связи с истечением время отведенного для выполнения. Это можно исправить с помощью функции set_time_limit(240); 240 – это время в секундах, отведенное на выполнение скрипта.

Эта статья предназначена для формирования основных понятий парсинга HTML страницы с помощью PHP. Существуют и другие библиотеки и методы парсинга. Если вы знаете таковые, поделитесь в комментариях. Буду рад, узнать какими инструментами и методами html парсинга пользуетесь вы.

Потихоньку изучаю возможности PHP для создания парсеров. Я уже писала о том, как парсить . Сейчас расскажу об одном из способов парсинга html (он подойдет и для xml тоже, кстати). Повторю, что в php я не гуру, поэтому буду очень признательна, если вы оставите свои комментарии к поднятой теме.

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

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

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


$html = "
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

сайт Map


Последние темы блога















http://сайт/2009/08/blog-post_06.html Базы
MySQL и Delphi. Express-метод
http://сайт/2009/08/blog-post.html Пост о том, что лучше сто раз проверить



";
/** создаем новый dom-объект **/
$dom = new domDocument;

/** загружаем html в объект **/
$dom->loadHTML($html);
$dom->preserveWhiteSpace = false;

/** элемент по тэгу **/
$tables = $dom->getElementsByTagName("table");

/** получаем все строки таблицы **/
$rows = $tables->item(0)->getElementsByTagName("tr");

/** цикл по строкам **/
foreach ($rows as $row)
{
/** все ячейки по тэгу **/
$cols = $row->getElementsByTagName("td");
/** выводим значения **/
echo $cols->item(0)->nodeValue."
";
echo $cols->item(1)->nodeValue."
";
echo "


";
}
?>

В результате после запуска скрипта получаем такую картину:

Upd: Без всякого сомнения, для более удобной работы со структурой HTML в PHP вам надо познакомиться с библиотекой