В аську постучал один из читателей этого блога, и заказал универсальный парсер сайтов. Парсер должен был уметь грабить произвольный сайт и выдирать из него всю текстовую информацию. Кроме того, он должен найти все ссылки на сайте и пройти по ним. У парсера должна быть настройка, ограничивающая число страниц, которое он парсит за один раз. Цена была небольшой, но и задание само по себе несложное. Итак, приступим
Для начала нам потребуется библиотека 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 имеющие системы защиты от таких наглецов. Также он не сможет парсить сайты созданные на любом из лучших конструкторов сайтов. Сайты на эти хоть и очень простые, и сделаны новичками, но имеют под собой сложную инфраструктуру, которая не позволит просто так их парсить.
Комментарии
А могли бы вы прикрепить файлы с исходниками?
А то у меня выводит ошибку:
Parse error: syntax error, unexpected T_VAR in H:\home\parser\www\01\index.php on line 42
Цитирую Виктор Соседко:
Цитирую Виктор Соседко:
Цитирую Виктор Соседко:
Не знаю, актуально ли еще, но я могу это сделать) Если еще надо - ответьте на мой комментарий
Здравствуйте! Не знаю, актуально ли еще), но если да - я могу это сделать. Ответьте на мой коммент, если интересно.
Спасибо все работает!
http://excelvba.ru/programmes/Parser
Только он не на PHP написан, а на VBA для Excel
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.
СтройРостов161
Notice: Undefined index: path in C:\xampp\htdocs\parser\index.php on line 85
а в строке 85 : $this->path = $urldata['path'];
Вот вопрос реально "Avito имеющие системы защиты от таких наглецов."
Сохранил стр с их сайта на денвер, вот я вижу нужный тег !
И вытаскиваю шаблоном preg_match_all - а шаблон его в тупую не видит ???
Кодировку выставлял ---
Скажите, а phpQuery кто-то пользуется?
Не планируете свежих статей в этом роде? Может что новое, быстрее появилось?
Подскажите пожалуйста, а если на сайте сначала нужно залогиниться, чтобы появилась информация, которую нужно спарсить. Как быть?
Бесплатный, легко настраиваемый без особых знаний за пару минут на любой сайт
Пример парсинга rozetka.com
Составление списка параметров товаров нужной категории и сохранение в файл. Настроить можно на любой сайт.
Видео https://youtu.be/TfAKu7O5zZo
Deposit and withdraw with an automatic system, do not waste time waiting for a long time.