Заметка посвящается парсингу, в частности парсинг сайтов, парсинг страниц, парсинг в веб-среде, парсинг html-контента сайта.
В процессе разработки различных веб-сервисов очень часто приходится сталкиваться с задачами, в которых требуется быстро получить различного рода информацию в больших объемах. В основном это связано с граббингом, кражей информации, как хотите это называйте. Дело в том, что информация доступна и открыта. Особенность парсинга - это быстрый и автоматизированный сбор данных, контента со страниц сайта.
Сейчас очень популярно парсить в веб-среде, а именно парсить сайта, который содержать хоть какую-нибудь ценность и актуальность для людей. Особой ценностью является каталог товаров, включая картинки, базы данных справочников и многое другое, что может пригодиться для конкурентов.
Давайте попробуем спарсить нужную информацию в html, попробуем достать все ссылки с нескольких страниц нашего сайта.
Для начала нам необходимо получить контент сайта в формате html. Для этого нам достаточно знать адреса нужных страниц.
Хочу показать 2 основных способа получения контента со страницы сайта:
В первую очередь приготовим массив с нужными адресами страниц:
//3 ссылки нашего сайта:
$urls = array('http://hello-site.ru/blog/','http://hello-site.ru/web-notes/','http://hello-site.ru/games/');
1 вариант - php функция file_get_contents. Функция возвращает html-строку, которую мы будем парсить на ссылки:
//помещаем каждую ссылку в функцию file_get_contents
foreach($urls as $urlsItem){
$out .= file_get_contents($urlsItem); //и добавляем содержание каждой страницы в строку
}
echo $out; //здесь контент всех трех страниц
2 вариант - CURL. Библиотека, которая поддерживается php и имеет большой набор настроек, от POST-запросов до работы с FTP. Рассмотрим стандартный вызов библиотеки curl, который отдаст нам контент сайта:
foreach($urls as $urlsItem){ //пропускаем каждую ссылку в цикле
$output = curl_init(); //подключаем курл
curl_setopt($output, CURLOPT_URL, $urlsItem); //отправляем адрес страницы
curl_setopt($output, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($output, CURLOPT_HEADER, 0);
$out .= curl_exec($output); //помещаем html-контент в строку
curl_close($output); //закрываем подключение
}
echo $out; //здесь контент всех трех страниц
Теперь в нашей строке $out находится контент всех трех страниц. Итак, переходим непосредственно к парсингу нашей строки.
Опять же хочу показать 3 варианта решения нашей задачи: "нативный" способ на php, с помощью встроенной библиотеки DOMDocument и библиотеки SimpleHTMLDOM.
1. php функция explode. Функция находит искомый символ или часть строки и делит целую строку на элементы массива.
Повторюсь, нам необходимо получить значения всех атрибутов href у тегов a, для этого будем делить общую строку на некоторые части\отрезки:
// explode
$hrefs = explode('<a',$out); //делим нашу строку контента 3х страниц на элементы массива, разделенные "<a"
unset($hrefs[0]); //удаляем 1ый элемент, там точно ничего нет
foreach($hrefs as $hrefsItem){
$arHref = explode('href="',$hrefsItem); //следующее деление строки на "href=""
$arHref = explode('"',$arHref[1]); //аналогично, но берем 2ой элемент массива
$hrefText[] = $arHref[0]; //в этом случае наш нужный отрезок строки в 1ом элементе массива
}
foreach($hrefText as $hrefTextItem){ //избавляемся от ссылок с пустым атрибутом href
if($hrefTextItem!=''){
$clearHrefs[]=$hrefTextItem;
}
}
$clearHrefs = array_unique($clearHrefs); //избавляемся от одинаковых ссылок
print_r($clearHrefs); // в итоге у нас массив со всем ссылками с 3х страниц
Если распечатать наш массив, будет примерно следующее:
Array
(
[0] => /
[1] => /hello
[3] => /timer/
[4] => /leftmenu/
[5] => /faq/
[6] => /blog/
[8] => /web-notes/
[9] => /ordersite/
[10] => /games
)
2. встроенная библиотека DOMDocument. Работаем с классом примерно следующим образом:
//domelement
$dom = new DOMDocument; //создаем объект
$dom->loadHTML($out); //загружаем контент
$node = $dom->getElementsByTagName('a'); //берем все теги a
for ($i = 0; $i < $node->length; $i++) {
$hrefText[] = $node->item($i)->getAttribute('href'); //вытаскиваем из тега атрибут href
}
foreach($hrefText as $hrefTextItem){ //избавляемся от ссылок с пустым атрибутом href
if($hrefTextItem!=''){
$clearHrefs[]=$hrefTextItem;
}
}
$clearHrefs = array_unique($clearHrefs); //избавляемся от одинаковых ссылок
print_r($clearHrefs); // в итоге у нас массив со всем ссылками с 3х страниц
Результат такого кода ровно такой же, что и с помощью функции explode.
3. библиотека SimpleHTMLDOM. Ее необходимо подключать из файла. Работа примерно схожа с DOMDocument. Работаем с классом:
//simplehtml
include('simple_html_dom.php'); //подключаем файл с классом SimpleHTMLDOM
$html = new simple_html_dom(); //создаем объект
$html->load($out); //помещаем наш контент
$collection = $html->find('a'); //собираем все теги a
foreach($collection as $collectionItem)
{
$articles[] = $collectionItem->attr; //массив всех атрибутов, href в том числе
}
foreach($articles as $articlesItem){
$hrefText[] = $articlesItem['href']; //собираем в массив значения подмассива с ключом href
}
foreach($hrefText as $hrefTextItem){ //избавляемся от ссылок с пустым атрибутом href
if($hrefTextItem!=''){
$clearHrefs[]=$hrefTextItem;
}
}
$clearHrefs = array_unique($clearHrefs); //избавляемся от одинаковых ссылок
print_r($clearHrefs); // в итоге у нас массив со всем ссылками с 3х страниц
Повторюсь, результат в массив ровно такой же как и выше в двух вышеперечисленных.
Теперь, имея массив со всеми ссылками, собранными с трех страниц сайта, можно отправить ссылки в нужное русло, все зависит от задачи и фантазии. Имея такие возможности, можно спарсить большое количество данных самого разного вида информации, картинки, тексты, логи и т.д. Чужая информация в ваших руках, распоряжайтесь как вам угодно, но сами защищайтесь, хотя это невозможно)
Успехов!