апреля 2, 2010
Парсеры на PHP. Часть 1.
Написание парсера достаточно нестандартная задача к которой на первых парах тяжело подступится. В этой статье я расскажу алгоритма для парсинга почти любого сайта. В примере я использую 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 комментария
HenzO
апреля 2, 2010 в 15:57
1
А как с куками дела обстоят? Как примерно залогиниться на форум аля phpbb, vbulletin, ipb итд?
Сергей
апреля 4, 2010 в 23:23
2
Присоединяюсь, расскажите как залогинятся. Ну и интересно было бы прочитать про обработку всевозможных ошибок.
admin
апреля 6, 2010 в 16:01
3
обработку ошибок вообще не делаю, это же просто парсер. запустил, вылезла ошибка, открывают исходный код и правлю. И так пока не заработает.
admin
апреля 6, 2010 в 16:15
4
Вообще авторизация на любом сайте состоит из 2-ух шагов, первое отправить запрос к форме авторизации, в ответе выдернуть строку с Cookie, а потом ее подставлять во все следующие запросы. Если надо, то приведу пример на каком-нибудь движке. У всех принцип примерно одинаковый, в форме есть поля для логина и пароля. Они посылаются на скрипт авторизации методом POST.
Dolmatov
апреля 19, 2010 в 12:40
5
Отличный вариант парсера.
7IM0N
мая 5, 2010 в 10:44
6
о спасибо
kail
мая 27, 2010 в 14:59
7
//на выходе получаем массив $cont со всеми статьями блога
и как дальше из массива извлечь данные? либо записать весь спарсенный текст в файл?????
admin
мая 28, 2010 в 13:36
8
Все как обычно) например:
$file = fopen(“text.txt”,”a+”);
foreach($cont as $p)
{
fputs($p,$file);
}
WishMaster
октября 28, 2010 в 14:26
9
Присоединяюсь к вопросу примера парсера страниц с авторизацией. Можно пример в студию?
ukrpunk
февраля 20, 2011 в 19:26
10
///for($i=1;$i<=1;$i++)
Поправь, ведь сам сказал – 4страницы парсим
for($i=1;$i<=4;$i++)
Вячеслав
июля 11, 2011 в 17:46
11
Скиньте рабочую версию на kolobok776@ya.ru =)
Блокшот
июля 29, 2011 в 16:09
12
спасибо за легкий пример парсера… будем учиться парсить))
stefan
июля 30, 2011 в 18:05
13
никто не подкcажет: можно ли вообше написать парсер/граббер/скрипт который берет инфу из базы данных сайта на которм можно заказать Онлайн Авиабилет??? т.е. мне надо подключиться к базе данных какого либо сайта выдрать оттуда инфу о полетах и результат отобразить уже на МОЕМ сайте! Возможно ли это???
admin
августа 29, 2011 в 12:45
14
stefan, возможно, но это уже будет не парсингом. Спарсить расписание полетов можно, а вот заказать билет нет. реализовать можно с помощью партнерской программы http://www.anywayanyday.com/partners/
Levik
августа 30, 2011 в 21:45
15
А если страниц на сайте много.. и шаблон сложно определить.. и время ответа сервера плавающее (скрипт умрёт раньше, чем соберет все страницы).. и стоит ограничение на количество запросов в секунду и ещё куча всяких “но”…
А в общем – спасибо за подробное объяснение работы парсера.. очень удобно – подставляй свои регулярки и “работай”
Alex
сентября 8, 2011 в 16:52
16
У меня почему то массив cont выводится как:
Array
Array
Array
Array
Array
admin
января 11, 2012 в 08:03
17
Это можно официально сделать, без всяких парсеров) На anywayanyday.com есть партнерская программа)
Вадим
января 20, 2012 в 22:44
18
Здравствуйте.
Помогите пожалуйста.
//извлекаем содержимое страницы (ТУТ СПЕЦBFАЛЬНО СДЕЛАНА ОШBБКА)
preg_match_all(“/ть\\(.*)\/”,$post,$mch2)
Как этот код применить вот к этой странице http://www.newsvl.ru/photos/2012/01/20/95633/
нужно вытащить текст статьи начиная с “Сегодня во Владивостоке” и заканчивая “северной половине края. ”
Спасибо
admin
января 22, 2012 в 22:45
19
Как-то так. Это верно, если там всегда есть написанный жирным текстом комментатор.
echo $match[1];
$data = file_get_contents(“http://www.newsvl.ru/photos/2012/01/20/95633/”);
preg_match(“/\/h2\>(.*)\
Am@ruL
февраля 2, 2012 в 16:10
20
Как этот код применить вот к этой странице 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/"
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].”";
?>
spy686
февраля 5, 2012 в 19:42
21
а можно подробней, а то я ваще валенок в программировании:
алгоритм ясен, но не ясно куда скрипт помещать.
hoptop
марта 16, 2012 в 19:39
22
Привет! Может, вопрос не по теме и далеко не относится к данной статье, но все таки спрошу, буковки к посту не помешают))
Подскажи, Admin! Я начал работать с XHE и мне вдруг захотелось почистить txt файл от пустых строк. Как мне это осуществить?
file_put_contents(‘text2.txt’,file(‘text.txt’, FILE_SKIP_EMPTY_LINES)); – это не работает на XHE, мне просто очень нужно чистку от пустоты забить в цикл)) Помоги))