В аську постучал один из читателей этого блога, и заказал универсальный парсер сайтов. Парсер должен был уметь грабить произвольный сайт и выдирать из него всю текстовую информацию. Кроме того, он должен найти все ссылки на сайте и пройти по ним. У парсера должна быть настройка, ограничивающая число страниц, которое он парсит за один раз. Цена была небольшой, но и задание само по себе несложное. Итак, приступим

Для начала нам потребуется библиотека Simple HTML Dom и функция которая будет запрашивать данные(request).

Выведем форму ввода адреса донора и создадим каркас класса парсера

<form method="POST">
	<input name="url" type="text" value="<?=isset($_REQUEST['url'])?$_REQUEST['url']:'http://xdan.ru/parser/parser/test.html';?>"/><input type="submit" value="Пошел">
</form>
<?php

include 'simple_html_dom.php';
class parser{
	var $cacheurl = array();
	var $result = array();
	var $_allcount = 10;
	function __construct(){
		if(isset($_POST['url'])){
			$this->parse($_POST['url']);
		}
	}
	function parse($url){}
	function readUrl($url){}
	function printresult(){
		foreach($this->result as $item){
			echo '<h2>'.$item['title'].' - <small>'.$item['url'].'</small></h2>';
			echo '<p style="margin:20px 0px;background:#eee; padding:20px;">'.$item['text'].'</p>';
		};
		exit();
	}
}
$pr = new Parser();
$pr->printresult();

Парсить будет метод parse. В остальном все просто. 

_allcount 

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

Напишем метод parse. Но перед этим, нам потребуется еще один метод. Он будет получать на вход $url и смотреть, если это локальный относительный  адрес (index.php) то добавлять в начало домен, если полный адрес, то запоминать папку в котором происходит парсинг и наконец если это полный адрес другого сайта, то возвращать false, потому как такие ссылки нам не нужны

var $protocol = '';
var $host = '';
var $path = '';
function readUrl($url){
	$urldata = parse_url($url);
	if( isset($urldata['host']) ){
		if($this->host and $this->host!=$urldata['host'])
			return false;
			
		$this->protocol = $urldata['scheme'];
		$this->host = $urldata['host'];
		$this->path = $urldata['path'];
		return $url;
	}
		
	if( preg_match('#^/#',$url) ){
		$this->path = $urldata['path'];
		return $this->protocol.'://'.$this->host.$url;
	}else{
		if(preg_match('#/$#',$this->path))
			return $this->protocol.'://'.$this->host.$this->path.$url;
		else{
			if( strrpos($this->path,'/')!==false ){
				return $this->protocol.'://'.$this->host.substr($this->path,0,strrpos($this->path,'/')+1).$url;
			}else 
				return $this->protocol.'://'.$this->host.'/'.$url;
		}
	}
}

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

не буду долго вас томить, метод parse прост, как две копейки

function parse($url){
	$url = $this->readUrl($url);
	
	if( !$url or $this->cacheurl[$url] or $this->cacheurl[preg_replace('#/$#','',$url)] )
		return false;
		
	$this->_allcount--;
	
	if( $this->_allcount<=0 )
		return false;
		
	$this->cacheurl[$url] = true;
	$item = array();	
	
	$data = str_get_html(request($url));
	$item['url'] = $url;
	$item['title'] = count($data->find('title'))?$data->find('title',0)->plaintext:'';
	$item['text'] = $data->plaintext;
	$this->result[] = $item;
	
	if(count($data->find('a'))){
		foreach($data->find('a') as $a){
			$this->parse($a->href);
		}
	}
	$data->clear();
	unset($data);
	
}

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

Парсер готов.

Разумеется, этот парсер не сможет парсить такие сайты, как Google, Yandex, Avito имеющие системы защиты от таких наглецов. Также он не сможет парсить сайты созданные на любом из лучших конструкторов сайтов. Сайты на эти хоть и очень простые, и сделаны новичками, но имеют под собой сложную инфраструктуру, которая не позволит просто так их парсить.   

Исходные файлы к статье 

лучшие конструкторы сайтов
Рассказать друзьям

Добавить комментарий


Защитный код
Обновить

Комментарии   

-1
kasym
# kasym 29.04.2014 04:41
Здравствуйте!

А могли бы вы прикрепить файлы с исходниками?

А то у меня выводит ошибку:

Parse error: syntax error, unexpected T_VAR in H:\home\parser\www\01\index.php on line 42
0
Виктор Соседко
# Виктор Соседко 03.09.2016 17:43
Привет а можно как то в нём сделать что бы он парсил каждое в своё окно!То есть к примеру я хочу ним парсить описания к фильмам и мне нужно что бы описание было в одном окне а год выпуска например в другом можно ли такое?Кто может помогите это реализовать!
+1
kasym
# kasym 29.04.2014 11:30
Здравствуйте!
Спасибо все работает!
-1
axeld
# axeld 14.06.2014 17:18
Прикольный парсер, хорошо работает. Нужно только научить его выдёргивать сам контент страниц, без меню и прочего мусора. Попробую это сделать.
-1
Игорь
# Игорь 13.12.2014 13:45
А у меня парсер умеет выдергивать произвольный контент страниц:

http://excelvba.ru/programmes/Parser

Только он не на PHP написан, а на VBA для Excel
0
ЛВС
# ЛВС 20.08.2014 03:49
У меня парсер не работает. Чистая страница показывается. Даже форма с текстовым полем и кнопкой на странице не появляется. Т.к. в форме есть короткая запись php, глянул в php.ini параметр short_open_tag = On. Проверил и с помощью phpinfo.php, тоже short_open_tag = On. Два исходных файла к статье положил в localhost. Запускал localhost/index.php.
0
ЛВС
# ЛВС 21.08.2014 04:05
Вероятно, не работает из-за функции request, которую я не знаю, как подключить и куда подключить. Копировать эту функцию как она есть из статьи "Авторизация на сайте при помощи curl php" и вставлять в файл simple_html_dom.php? Сам cUrl я установил, phpinfo.php показывает, что блок curl есть.
0
Leroy
# Leroy 21.08.2014 12:08
в simple_html_dom.php блок ничего вставлять не надо. Этот файл - отдельная библиотека. Создайте другой, тот в котором весь парсер. Сделайте вывод ошибок http://xdan.ru/Vkljuchaem-pokaz-oshibok-v-php.html . Тогда станет понятно что за ошибка у вас
0
ЛВС
# ЛВС 22.08.2014 19:03
"­Создайте другой, тот в котором весь ­парсер". Не очень понятно. Другой файл создать? С каким расширением и что в нём писать? Парсер - это файл index.php, он же уже есть, зачем ещё один создавать. Извиняюсь за свою непонятливость.
0
ЛВС
# ЛВС 23.08.2014 05:05
Функция ­request уже прописана в index.php, её не нужно никуда подключать, лишь бы cUrl был установлен. Сейчас склоняюсь, что может мой интерпретатор php5 или apache неправильно сконфигурированы. Парсер вообще ничего не показывает, даже форму не показывает, хотя если в файле оставить только код формы, вырезав остальное, форма показываться будет.
+1
Leroy
# Leroy 23.08.2014 22:11
включите показ ошибок и все увидите
0
ЛВС
# ЛВС 24.08.2014 15:00
Спасибо! Показ ошибок был выключен. Благодаря указанной статье включил этот показ, вот, что показывает:

Warning: Unknown: failed to open stream: Permission denied in Unknown on line 0

Fatal error: Unknown: Failed opening required '/var/www/index.php' (include_path='.:/usr/share/php:/usr/share/pear')

in Unknown on line 0

В php.ini раскомментировал include_path = ".:/usr/share/php", перезапустил, получилось:

Warning: Unknown: failed to open stream: Permission denied in Unknown on line 0

Fatal error: Unknown: Failed opening required '/var/www/index.php' (include_path='.:/usr/share/php') in Unknown on line 0

По ходу выяснил, что на компе нет pear.
0
Leroy
# Leroy 24.08.2014 21:08
причем тут pear? у вас просто не работает файл. вы hello world для начала напишите
0
ЛВС
# ЛВС 25.08.2014 07:28
hello world работает. И выполнение php в html в тестовом файле тоже работает. Вполне возможно, неисправность от того, что я под роутером сижу, там копать надо.
0
ЛВС
# ЛВС 06.09.2014 15:58
Парсер работает! Всё дело было в недостаточности прав, Ваши два файла имели права: -rw------- 1 root root, а остальные файлы: -rw-r--r-- 1 root root. Сделал для Ваших файлов права -rw-r--r-- 1 root root, и всё заработало. У меня ОС Kali, в ней по умолчанию работают из-под рута, потому и не смотрел права на файлы - я же root, хотя и знал, что из-за прав могут быть проблемы. Излишняя самоуверенность меня подвела. Вероятно, такие первоначальные права на Ваши файлы у меня получились из-за того, что я их распаковал на другом компе, а потом с помощью флешки перенёс на свой комп. В-общем, работает. Спасибо за парсер!
0
СтройРостов161 stroyrostov161
# СтройРостов161 stroyrostov161 02.03.2015 16:56
полезно
СтройРостов161
0
Юрий
# Юрий 18.03.2015 13:11
Ищу человека, который может создать парсер новостей. Цель парсить текст новости и фото если есть, заливать к себе в БД согласно категорий. Разумеется не бесплатно, заинтересованные пишите на почту .
0
Elnazar Berdybaev
# Elnazar Berdybaev 19.05.2015 19:00
выводит такую запись:
Notice: Undefined index: path in C:\xampp\htdocs\parser\index.php on line 85

а в строке 85 : $this->path = $urldata['path'];
0
Vovka
# Vovka 29.02.2016 22:39
Прочитал до конца и с интересом. Сохранил в закладки, да подписался. Для своего пригодится. Спасибо автору!
0
chuvyr.ru
# chuvyr.ru 21.05.2016 12:08
В принципе можно использовать стандартные PHP классы обработки XML. Например, SimpleXML или DOMDocument. Не нужно заморачиваться с дополнительными библиотеками.
0
Владимир Сковкин
# Владимир Сковкин 27.05.2016 19:25
Несмотря на дату.Статья познавательная.
Вот вопрос реально "Avito имеющие системы защиты от таких наглецов."
Сохранил стр с их сайта на денвер, вот я вижу нужный тег !
И вытаскиваю шаблоном preg_match_all - а шаблон его в тупую не видит ???
Кодировку выставлял ---
0
BSOD
# BSOD 14.06.2016 23:45
Спасибо большое, помогли решить проблему. Очень благодарен за статью
0
alexindacomp
# alexindacomp 28.08.2016 00:02
Simple HTML Dom годится только для парсинга идеального html. В других случаях он просто начинает жестко тупить. Другое дело phpparserplus.esy.es, который не виснет и парсит с помощью multi-curl да и интерфейс готовый. Проверен на сотни сайтов.
0
alexindacomp
# alexindacomp 28.08.2016 00:05
Simple HTML DOM годится только для идеалного html кода страницы, иначе начинает жестко тупить. Другое дело phpparserplus.esy.es, который работает с помощью multi-curl и проверен на сотни сайтах.
0
bdseo
# bdseo 01.09.2016 11:09
Спасибо, давно ищу лучшие парсеры на рнр.
Скажите, а phpQuery кто-то пользуется?
0
hdse.ru
# hdse.ru 21.10.2016 15:53
неплохая статья, можно еще и про парсер видео написать