апреля 2, 2010

Парсеры на PHP. Часть 1.

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

file_get_contents(string $url) – функция принимает в качестве параметра URL(кроме этого там может быть просто путь к файлу), на выходе возвращает содержимое страницы со  всеми тегами. У этой функции есть недостатки, к примеру в User-agent посылается значение переменной user_agent из файла настроек PHP, а это может помешать при парсинге.

Библиотека  CURL. Библиотека нужна что бы можно было получать содержимое страниц с заголовками как у браузеров. Почитать более подробно можно здесь: http://ru2.php.net/manual/en/book.curl.php

preg_match(string $pattern, string $subject, array &$matches) – функция для работы с регулярными выражениями, на входе идут 3 парметра: $pattern – регулярное выражение, $subject – строка где идет поиск по регулярному выражению, $matches – массив результатов).

preg_match_all(string $pattern, string $subject, array &$matches) – та же самая функция, что и preg_match, только она ищет все вхождения шаблона.

Теперь перейдем к  самому парсингу. Объяснять буду на примере этого сайта (vilblog.ru)

1. Рассмотрим сайт и определим принцип построения URL-ов, что бы их можно по очереди открыть. К пример на этом сайте посты расположены на страницах с URL-ами вида http://vilblog.ru/page/номер_страницы. Всего страниц 4, следовательно, необходимо открыть в каждую из них  внутри цикла, а оттуда смотреть как устроены URL-ы постов.

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

<h2><a href="http://vilblog.ru/2010/01/26/onlajn-treningi/" title="Онлайн тренинги">
Онлайн тренинги</a></h2>

Как видно ссылка расположена внутри тега h2. То есть внутри регулярного выражения нужно найти все что расположено внутри тега A, который расположен внутри тега H2 и извлечь атрибут href.

3.    После того как мы получили URL-ы всех статей нам необходимо отпарсить их. Открываем любую и смотрим где расположен html-код самого контента. Тут все сложнее, текст расположен между элементами:

Прокомментировать</a></p>
и
</p>

Так же извлекаем его регулярным выражением

4.  Собственно сам код парсера:

<?php
//массив с контентом
$cont = array();

//парсим в цикле 4 страницы
for($i=1;$i<=1;$i++)
{
    //загружаем страницу
    $data = file_get_contents("http://vilblog.ru/page/".$i);
    //извлекаем ссылки
    preg_match_all("/\<h2\>\<a\ href\=\"(.*)\"/U",$data,$mch);
    
    //в переменно $mch[1] получаем массив ссылок на посты
    //в цикле просматриваем все URL
    foreach($mch[1] as $p)
    {
        $tmp = "";
        //загружаем пост
        $post = file_get_contents($p);
        //извлекаем содержимое страницы (ТУТ СПЕЦBFАЛЬНО СДЕЛАНА ОШBБКА)
        preg_match_all("/ть\<\/a\>\<\/p\>(.*)\<p\ class\=\"meta2\"\>/",$post,$mch2);
        
        
        //убираем ненужные пробелы
        $tmp = trim($mch2);
        
        $cont[] = $tmp;
        
    }
    
}
//на выходе получаем массив $cont со всеми статьями блога
?>';

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

Опубликовано в: PHP, Программирование

22 комментария

А как с куками дела обстоят? Как примерно залогиниться на форум аля phpbb, vbulletin, ipb итд?

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

обработку ошибок вообще не делаю, это же просто парсер. запустил, вылезла ошибка, открывают исходный код и правлю. И так пока не заработает.

Вообще авторизация на любом сайте состоит из 2-ух шагов, первое отправить запрос к форме авторизации, в ответе выдернуть строку с Cookie, а потом ее подставлять во все следующие запросы. Если надо, то приведу пример на каком-нибудь движке. У всех принцип примерно одинаковый, в форме есть поля для логина и пароля. Они посылаются на скрипт авторизации методом POST.

Отличный вариант парсера.

о спасибо

//на выходе получаем массив $cont со всеми статьями блога
и как дальше из массива извлечь данные? либо записать весь спарсенный текст в файл?????

Все как обычно) например:

$file = fopen(“text.txt”,”a+”);
foreach($cont as $p)
{
fputs($p,$file);
}

Присоединяюсь к вопросу примера парсера страниц с авторизацией. Можно пример в студию?

///for($i=1;$i<=1;$i++)
Поправь, ведь сам сказал – 4страницы парсим ;)
for($i=1;$i<=4;$i++)

Скиньте рабочую версию на kolobok776@ya.ru =)

спасибо за легкий пример парсера… будем учиться парсить))

никто не подкcажет: можно ли вообше написать парсер/граббер/скрипт который берет инфу из базы данных сайта на которм можно заказать Онлайн Авиабилет??? т.е. мне надо подключиться к базе данных какого либо сайта выдрать оттуда инфу о полетах и результат отобразить уже на МОЕМ сайте! Возможно ли это???

stefan, возможно, но это уже будет не парсингом. Спарсить расписание полетов можно, а вот заказать билет нет. реализовать можно с помощью партнерской программы http://www.anywayanyday.com/partners/

А если страниц на сайте много.. и шаблон сложно определить.. и время ответа сервера плавающее (скрипт умрёт раньше, чем соберет все страницы).. и стоит ограничение на количество запросов в секунду и ещё куча всяких “но”…
А в общем – спасибо за подробное объяснение работы парсера.. очень удобно – подставляй свои регулярки и “работай”

У меня почему то массив cont выводится как:
Array
Array
Array
Array
Array

Это можно официально сделать, без всяких парсеров) На anywayanyday.com есть партнерская программа)

Здравствуйте.
Помогите пожалуйста.
//извлекаем содержимое страницы (ТУТ СПЕЦBFАЛЬНО СДЕЛАНА ОШBБКА)
preg_match_all(“/ть\\(.*)\/”,$post,$mch2)

Как этот код применить вот к этой странице http://www.newsvl.ru/photos/2012/01/20/95633/

нужно вытащить текст статьи начиная с “Сегодня во Владивостоке” и заканчивая “северной половине края. ”

Спасибо

Как-то так. Это верно, если там всегда есть написанный жирным текстом комментатор.
$data = file_get_contents(“http://www.newsvl.ru/photos/2012/01/20/95633/”);
preg_match(“/\/h2\>(.*)\ echo $match[1];

Как этот код применить вот к этой странице http://www.newsvl.ru/photos/2012/01/20/95633/
Можно так – preg_match_all(“/(.*)\s*(.*)(.*)(.*)(.*)/U”
echo $match[4];

или такой вот скрипт:

–=MegaPARSER

<?php
$ch = curl_init ();
curl_setopt ($ch , CURLOPT_URL , "http://www.newsvl.ru/photos/2012/01/20/95633/&quot ;) ;
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("/(.*)\s*(.*)(.*)(.*)(.*)/isU”, $content, $matches, PREG_PATTERN_ORDER);

for ($i = 0; $i < count($matches[1]); $i++)

echo "”.$matches[4][$i].”";

?>

а можно подробней, а то я ваще валенок в программировании:
алгоритм ясен, но не ясно куда скрипт помещать.

Привет! Может, вопрос не по теме и далеко не относится к данной статье, но все таки спрошу, буковки к посту не помешают))

Подскажи, Admin! Я начал работать с XHE и мне вдруг захотелось почистить txt файл от пустых строк. Как мне это осуществить?

file_put_contents(‘text2.txt’,file(‘text.txt’, FILE_SKIP_EMPTY_LINES)); – это не работает на XHE, мне просто очень нужно чистку от пустоты забить в цикл)) Помоги))

Ваш комментарий

Сумма 2 + 16 ?

Реклама

Жалко тратить бензин, а главное время?Производство барных подстолий под столешницы в 40км от Москвы.

Счетчики