добавить
ссылку в
Email
Fb
подписка
RSS
Twitter
Email
Fb

Простой парсер на PHP

Простой парсер на PHP

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

В этой статье мы создадим простой парсер на популярном языке PHP.

Заранее извиняюсь перед своими читателями, которые не знакомы с программированием, но специфика SEO зачастую предполагает наличие и программерских навыков. Итак, приступим.

Что будем парсить? В качестве учебного примера предлагаю создать средство для сбора статей широкоизвестного технического журналиста Криса Касперски (популярного автора журнала "Хакер").

Getting started

Статьи Криса расположены по этому адресу: http://www.xakep.ru/post/35410/default.asp. Это и будет нашей отправной точкой. Скачивание страницы для парсинга будем выполнять, используя библиотеку cURL. Итак, инициализируем библиотеку и скачиваем нашу страницу:

$ch = curl_init (); // инициализация
curl_setopt ($ch , CURLOPT_URL , "http://www.xakep.ru/post/35410/default.asp"); // адрес страницы для скачивания
curl_setopt ($ch , CURLOPT_USERAGENT , "Mozilla/5.0 (Windows; U; Windows NT 5.1; ru-RU; rv:1.7.12) Gecko/20050919 Firefox/1.0.7"); // каким браузером будем прикидываться
curl_setopt ($ch , CURLOPT_RETURNTRANSFER , 1 ); // нам нужно вывести загруженную страницу в переменную
$content = curl_exec($ch); // скачиваем страницу
curl_close($ch); // закрываем соединение

Расчленение

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

<p>Название статьи<br>
<a href="адрес_статьи">адрес_статьи</a></p>

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

preg_match_all("/<p>(.*)<br>\r\n<a href=\"(.*)\">.*<\/a><\/p>/isU", $content, $matches, PREG_PATTERN_ORDER);

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

Вырезка

Мы подошли к основному циклу программы. В нём мы будем скачивать странички со статьями и вырезать из них интересующую нас информацию.

Просматривая код страницы, можно обнаружить, что текст статьи всегда обрамлён следующими тегами

<hr width="200" size="1" noshade align="left">
..текст статьи..
<center><p><a href="../">Содержание</a>

На основе этого закона мы и постоим парсер. Все необходимые поянения даны в комментариях:

for ($i =  0; $i < count($matches[1]); $i++) // цикл по всем, извлеченным из стартовой страницы, адресам 
{
    echo "<h1>".$matches[1][$i]."</h1>"; // выводим название статьи как заголово
    flush(); // заставляем вывести текст немедленно
    $ch = curl_init (); // инициализация
    curl_setopt ($ch , CURLOPT_URL , $matches[2][$i]); // ссылка на текущую статью, адрес которой мы извлекли из первой страницы
    curl_setopt ($ch , CURLOPT_USERAGENT , "Mozilla/5.0 (Windows; U; Windows NT 5.1; ru-RU; rv:1.7.12) Gecko/20050919 Firefox/1.0.7");
    curl_setopt ($ch , CURLOPT_RETURNTRANSFER , 1 );
    $content = curl_exec($ch);
    curl_close($ch);
 
    preg_match_all("/<hr width=\"200\" size=\"1\" noshade align=\"left\">(.*)<center><p><a href=\"\.\.\/\">.*<\/a>/isU", $content, $matches_art, PREG_PATTERN_ORDER); // выдираем текст статьи
    echo $matches_art[1][ 0]; // выводим её (опять же смотри описание функции preg_match_all в справочнике)
    flush(); // заставляем вывести текст немедленно
    sleep(2); // отдыхаем две секунды, чтобы не вызвать подозрение у сервера
}

Finish

Ну вот, собственно, и всё! В итоге мы получим ленту статей Криса, без рекламы, оформления сайта и прочих радостей.

Полный код скрипта:

$ch = curl_init ();
curl_setopt ($ch , CURLOPT_URL , "http://www.xakep.ru/post/35410/default.asp");
curl_setopt ($ch , CURLOPT_USERAGENT , "Mozilla/5.0 (Windows; U; Windows NT 5.1; ru-RU; rv:1.7.12) Gecko/20050919 Firefox/1.0.7");
curl_setopt ($ch , CURLOPT_RETURNTRANSFER , 1 );
$content = curl_exec($ch);
curl_close($ch);
 
preg_match_all("/<p>(.*)<br>\r\n<a href=\"(.*)\">.*<\/a><\/p>/isU", $content, $matches, PREG_PATTERN_ORDER);
 
for ($i =  0; $i < count($matches[1]); $i++)
{
    echo "<h1>".$matches[1][$i]."</h1>";
    flush();
    $ch = curl_init ();
    curl_setopt ($ch , CURLOPT_URL , $matches[2][$i]);
    curl_setopt ($ch , CURLOPT_USERAGENT , "Mozilla/5.0 (Windows; U; Windows NT 5.1; ru-RU; rv:1.7.12) Gecko/20050919 Firefox/1.0.7");
    curl_setopt ($ch , CURLOPT_RETURNTRANSFER , 1 );
    $content = curl_exec($ch);
    curl_close($ch);
 
    preg_match_all("/<hr width=\"200\" size=\"1\" noshade align=\"left\">(.*)<center><p><a href=\"\.\.\/\">.*<\/a>/isU", $content, $matches_art, PREG_PATTERN_ORDER);
    echo $matches_art[1][ 0];
    flush();
    sleep(2);
}
 

Если если вам понравилась эта статья, вы можете подписаться на материалы моего блога через rssRSS или emailemail, а также присоединиться ко мне в twitterTwitter или vkontakteВКонтакте.

Статьи на эту же тему
* эксперт · Дата 28 февраля 2010 г. · seo  php  парсер 
RSS подписка Комментарии (16 штук)
Gravatar MyFreeWeb 28 февраля 2010 г. в 19:13 #
http://stackoverflow.com/questions/1732348/regex-match-open-tags-except-xhtml-self-contained-tags/1732454#1732454
«You can't parse [X]HTML with regex. Because HTML can't be parsed by regex. Regex is not a tool that can be used to correctly parse HTML. As I have answered in HTML-and-regex questions here so many times before, the use of regex will not allow you to consume HTML. Regular expressions are a tool that is insufficiently sophisticated to understand the constructs employed by HTML. HTML is not a regular language and hence cannot be parsed by regular expressions. Regex queries are not equipped to break down HTML into its meaningful parts. so many times but it is not getting to me. Even enhanced irregular regular expressions as used by Perl are not up to the task of parsing HTML. You will never make me crack. HTML is a language of sufficient complexity that it cannot be parsed by regular expressions. Even Jon Skeet cannot parse HTML using regular expressions. Every time you attempt to parse HTML with regular expressions, the unholy child weeps the blood of virgins, and Russian hackers pwn your webapp…»

А еще вместо PHP нужно использовать Python. В котором есть, например, замечательный модуль xml.dom,minidom.
Gravatar Zver 28 февраля 2010 г. в 20:47 #
Не сказал бы что это простой парсер :) простой можно и без cURL написать.
Gravatar Алексей Московский 1 марта 2010 г. в 00:00 #
MyFreeWeb, в PHP тоже есть библиотеки для разбора DOM. Но я сталкивался с рядом проблем с разбором невалидного HTML с помощью DOM. А вот регулярки работают всегда.

Zver, можно, но cURL — удобная штучка от которой грех отказываться.
Gravatar Алексей 1 марта 2010 г. в 12:56 #
Есть ещё вариант использовать яху-пайпс, Тормоз писал о них: http://brokenbrake.biz/2008/07/29/yahoo-pipes_29.html
Gravatar Johhny 15 марта 2010 г. в 23:01 #
Понравился Ваш парсер. Дорабатываю под свои нужды, но знание php пока хромает. Есть один вопрос.

Передаю через формы данные с одной страницы на другую:

URL:


далее, в index3.php (где ваш скрипт парсера сидит) хочу переменную urla вставить вместо урла сайта в эту строку Вашего скрипта:
curl_setopt ($ch , CURLOPT_URL , «http://www.xakep.ru/post/35410/default.asp»);

пробовал и так:
curl_setopt ($ch , CURLOPT_URL , $urla);
и так:
curl_setopt ($ch , CURLOPT_URL , $_POST['urla']);

но не получается заставить работать(
Может подскажете, где тут ошибка?
Заранее спасибо)
Gravatar Johnny 15 марта 2010 г. в 23:04 #
там не «URL:» в посте выше, а это криво вставилось

< form action=« index3.php» method=«post» >
URL:

< /form >
Gravatar Johnny 15 марта 2010 г. в 23:06 #
криво вставляется(( в общем там из поля input передаётся переменная urla в скрипт index3.php

она туда доходит т.к.
echo $_POST['urla'];
работает нормально — выводит значение переменной
Gravatar Алексей Московский 16 марта 2010 г. в 04:47 #
Johnny, скиньте мне на alexkucherov@gmail.com исходники — разберемся где ошибка.
Gravatar Johnny 16 марта 2010 г. в 10:51 #
Отправил.
Gravatar dionis44 25 марта 2010 г. в 16:15 #
Ну спасибо. Как хорошо, что есть люди, которые могут так просто и доступно, на живом примере рассказывать и показывать реально полезные вещи.
Искал и нашел.
Еще раз спасибо.
Gravatar Владимир 17 апреля 2010 г. в 13:54 #
а может еще подскажете как прикидываться, что как будто бы я с разных ip адресов захожу на сайт?

Т.е. я парсю огромный сайт, и что бы он не добавил мой айпи в блок, можно ли сделать так, что бы мой айпи адрес был не реальный, а вымышленный например, и все время разный.
Gravatar Алексей Московский 17 апреля 2010 г. в 16:32 #
Владимир, посмотрите документацию к модулю CURL — иам есть опция позволяющая указать прокси-сервер при загрузке страницы.
Gravatar Алесандр 10 мая 2010 г. в 07:27 #
Спасибо большое за статью!

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

Спасибо!
Gravatar 247365 10 мая 2010 г. в 13:24 #
Если нужно логиниться, разбери сначала каким методом и какие переменные посылаются с твоим логином и паролем, затем пошли их сам. Далее все зависит от технологии: либо сессии либо куки
Gravatar Игорь 10 мая 2010 г. в 23:56 #
а можно в примерах?
а то я уже неделю бьюсь
Gravatar Игорь 11 мая 2010 г. в 00:06 #
лучше конечно пример как и куда куки подставлять.
у большинства сайтов по кукам авторизация