Парсим сайты с phpQuery
На моей практике довольно часто встречались задачи вроде: спарсить таблицу с какого-то сайта в csv-файл, сграбить картинки с какого-то сайта и т.д. Все эти задачи можно обобщить термином парсинг сайтов. Большинство из нас, как и я раньше для решения таких проблем использовали стандартные средства php для парсинга xml-файлов (html все-таки является подвидом xml) совместно с регулярными выражениями.
Скрипты получались довольно громоздкими и непонятными. К счастью для себя, я недавно наткнулся на библиотеку под названием phpQuery (https://code.google.com/p/phpquery/), которая является портированным jQuery в php.
Если Вы пользовались jQuery, то должны знать о его очень удобном механизме селекторов, который мог бы быть чрезвычайно полезным при парсинге сайтов.
Допустим у нас есть такой кусок кода:
<ol class="results" start="1"> ... <li> <div class="title"> <i style="background-image: url(https://favicon.yandex.net/favicon/www.medvedev-da.ru);"/> <a target="_blank" href="https://www.medvedev-da.ru/" onmousedown="w(this,'80.22.82','84=85,186=80');" tabindex="2">Дмитрий <b>Медведев</b> - Главная</a> </div> <div class="text"> <span>"Правительству нужно действовать незамедлительно, бегом!" - Итоги <wbr/>2008 года - взгляд Президента России Дмитрия <b>Медведева</b>.</span><br/> </div> <div class="info"> <span style="color: rgb(0, 102, 0);"> www.medvedev-da.ru · 9 КБ </span> </div> <div class="info"> <nobr><a target="_blank" href="...">Сохраненная копия</a></nobr> · <nobr><a onmousedown="..." href="...">Еще с сайта</a> <span class="count">39241</span></nobr> · <nobr>Рубрика: <a href="..." onmousedown="w(this,'80.83','84=85');">Политика</a></nobr> </div> </li> ... </ol>
Это код обычной страницы с результатами поиска Yandex`а по запросу “медведев”.
Нам нужно спарсить title страницы-результата, ее краткое описание и адрес страницы.
С помощью phpQuery, код будет примерно таким:
<?php ini_set('max_execution_time', '0'); error_reporting(E_ALL); define('URL', 'https://yandex.ru/yandsearch?text=медведев'); require('phpQuery.php'); $results_page = get_xml_page(URL); $results = phpQuery::newDocument($results_page); $elements = $results->find('ol.results > li'); $info = array(); foreach ($elements as $element){ $title = pq($element)->find('div.title > a'); $title = pq($title)->text(); $descr = pq($element)->find('div.text > span'); $descr = pq($descr)->text(); $link_text = pq($element)->find('div.info:first > span'); $link_text = pq($link_text)->text(); $link_text = explode('•', $link_text); $link = trim($link_text[0]); $info[] = array('title' => $title, 'descr' => $descr, 'link' => $link); } print_r($info); function get_xml_page($url) { $ch = curl_init($url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); $page = curl_exec($ch); curl_close($ch); return $page; } ?>
Как видите, код довольно понятный и его можно очень легко модифицировать при необходимости. Что касается самой библиотеки phpQuery, в этой статье я рассмотрел лишь часть ее возможностей на примере парсинга сайтов. На самом деле, с ее помощью можно так же легко модифицировать структуру документа html и еще много другого.
Более подробную документацию к ней можно найти в блоге ее разработчика: https://phpquery-library.blogspot.com/.
На этом все. Удачи!
P.S.:
В связи с переездом FeedBurner`а в Google, адрес нашей RSS-ленты изменился на [ссылка]. Измените его в Ваших ридерах если уже подписаны и подписывайтесь на него в противном случае Повторяю: Новый адрес нашего RSS-фида - [ссылка].
[…] удобно, практично. А вчеру увидел порт jQuery на php. Вот тут хороший пример использования библиотеки. Рубрика: […]
https://i-novice.net/zheltaya-knopka-rss/
>Наш адрес - [ссылка].
исправьте
2 adw0rd: Спасибо. Я и забыл про эту страницу
Спс, не знал про такое. Сам странички парсил с помощью Snoopy
Актуально
еще есть не плохая софтинка webharvest опенсурс.
быстро и удобно
это тоже интерессный вариант, надо попробовать
Классная вещь.
У меня один вопрос :
Яндекс он в utf-8 выдает результаты поиска.
А если сайт в win-1251 , то у меня кракозябры выскакивают.
Посмотрите в сторону функции iconv
Если будете часто парсить, можно на бан по IP влететь ) Я уже пару раз влетел.
ктонибудь сравнивал скорость парсинга на phpQuery с регекспами?
Что то не работает код, может структура Яндекса поменялась?(
Вполне возможно, но лучше включить вывод ошибок и проверить нет ли какой-то ошибки или предупреждения.
А разве строка error_reporting(E_ALL); не говорит выводить все ошибки и предупреждения?
Ошибок нету, просто массив пустой(
чтот ругается…
Fatal error: Call to undefined function curl_init()
Олег, Вам нужно подключить модуль cURL в php.ini:
extension=php_curl.dll
Спасибо за ответ. Потом пришлось еще и dom включать…
Теперь не могу понять, как настроить. На удаленном источнике нет id вообще. Там верстка только таблицы и классы.
Что можно писать в find ? Какой синтаксис?
Пишу
$elements = $results->find(‘table’); //
…
$title = pq($element)->find(‘a’);
$title = pq($title)->text();
это не работает
Синтаксис параметра find очень похож на селекторы в css и jquery. Ознакомься с ним и заодно используй команду echo в php, для вывода промежуточных результатов.
Скрипт выдаёт ошибку:
Fatal error: Call to undefined function curl_init()
как исправить???
К PHP не подключена библиотека CURL, поэтому выдается такая ошибка.
Что б не было кракозябр с яндекса в начало страницы
header(‘Content-type: text/html; charset=utf-8′);
Html не является подвидом xml. Подвидом xml является xhtml.
А что будет если в коде сайта есть ошибки, например неправильно вложенные теги (………)?
Парсер “ниасилит”?
так и не нашел документации. пытаюсь найти аналог метода в jQuery “attr”, пока безуспешно
Даний скрипт создает масив значений што делать эсли нужна заливать в базу все промежуточние значения а не масив целиком.
Весьма интересная библиотека. На ней написал парсер для сайта. Но посмотрев код решил ждать пока его приведут до ума. Там куча недописанного и не доделаного. Так что DOM парсером пхп и вперед. С надеждой на то, что автор библиотеки его допилит и можно со спокойной душой будет юзать.
Можно ли как-то настроить чтобы парсинг осуществлялся регистронезависимый, а то если указать
“find(‘meta[name=”keywords”]’)”
а на странице будет Keywords (c большой буквы) то он не найдет. Strtolower всего контента - не пойдет.